blob: 55580f565f902c3f1d39438a19de358a5611bbb0 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes.actions;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.diff.DiffRequest;
import com.intellij.openapi.diff.DiffTool;
import com.intellij.openapi.diff.DiffToolbar;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.NullableFactory;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ChangeRequestChain;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author yole
*/
public class ChangeDiffRequest implements ChangeRequestChain {
@NotNull private final List<DiffRequestPresentable> mySteps;
private final boolean myShowFrame;
private int myIndex;
private final DiffExtendUIFactory myActionsFactory;
private final AnAction myPrevChangeAction;
private final AnAction myNextChangeAction;
private final Project myProject;
private final DiffChainContext myContext;
private final AnAction mySelectChangeAction;
public ChangeDiffRequest(final Project project, @NotNull List<DiffRequestPresentable> steps, final DiffExtendUIFactory actionsFactory,
final boolean showFrame) {
myProject = project;
mySteps = steps;
myShowFrame = showFrame;
myContext = new DiffChainContext();
myIndex = 0;
myActionsFactory = actionsFactory;
myPrevChangeAction = ActionManager.getInstance().getAction("Diff.PrevChange");
myNextChangeAction = ActionManager.getInstance().getAction("Diff.NextChange");
mySelectChangeAction = ActionManager.getInstance().getAction("Diff.SelectedChange");
}
@NotNull
@Override
public List<DiffRequestPresentable> getAllRequests() {
return mySteps;
}
private void onEveryMove(final DiffRequest simpleRequest, final boolean showFrame) {
simpleRequest.passForDataContext(VcsDataKeys.DIFF_REQUEST_CHAIN, this);
if (showFrame) {
simpleRequest.addHint(DiffTool.HINT_SHOW_FRAME);
}
else {
simpleRequest.addHint(DiffTool.HINT_SHOW_MODAL_DIALOG);
}
if (mySteps.size() > 1) {
simpleRequest.addHint(DiffTool.HINT_ALLOW_NO_DIFFERENCES);
}
}
public void quickCheckHaveStuff() throws VcsException {
if (mySteps.isEmpty()) {
throw new VcsException("Nothing selected to show diff");
}
if (mySteps.size() == 1) {
mySteps.get(0).haveStuff();
}
}
@Nullable
public DiffRequest init(final int idx) {
if (idx < 0 || idx > (mySteps.size() - 1)) return null;
myIndex = idx - 1;
final DiffRequest result = moveForward();
if (result == null && idx > 0) {
myIndex = -1;
return moveForward();
}
return result;
}
public boolean canMoveForward() {
return myIndex < (mySteps.size() - 1);
}
public boolean canMoveBack() {
return myIndex > 0;
}
@Nullable
public DiffRequest moveForward() {
return moveWithErrorReport(new MoveDirection() {
public boolean canMove() {
return canMoveForward();
}
public int direction() {
return 1;
}
});
}
@Nullable
@Override
public DiffRequest moveTo(DiffRequestPresentable presentable) {
int index = findRequest(presentable);
if (index == -1) {
return null;
}
final List<String> errors = new ArrayList<String>();
DiffRequestPresentable.MyResult result = moveImpl(presentable, errors);
showErrors(errors);
if (result == null) {
return null;
}
if (DiffPresentationReturnValue.removeFromList.equals(result.getReturnValue())) {
return null;
}
myIndex = index;
return result.getRequest();
}
@Nullable
@Override
public DiffRequestPresentable getCurrentRequest() {
if (myIndex < 0 || myIndex >= mySteps.size()) {
return null;
}
return mySteps.get(myIndex);
}
private int findRequest(DiffRequestPresentable presentable) {
for (int i = 0; i < mySteps.size(); i++) {
DiffRequestPresentable step = mySteps.get(i);
if (step.equals(presentable)) {
return i;
}
}
return -1;
}
@Nullable
private DiffRequest moveWithErrorReport(final MoveDirection moveDirection) {
final List<String> errors = new ArrayList<String>();
final DiffRequest diffRequest = moveInc(moveDirection, errors);
showErrors(errors);
return diffRequest;
}
@Nullable
private DiffRequestPresentable.MyResult moveImpl(DiffRequestPresentable requestPresentable, final List<String> errors) {
final DiffRequestPresentable.MyResult result = requestPresentable.step(myContext);
final DiffPresentationReturnValue returnValue = result.getReturnValue();
if (DiffPresentationReturnValue.quit.equals(returnValue)) {
errors.addAll(result.getErrors());
return null;
}
if (DiffPresentationReturnValue.removeFromList.equals(returnValue)) {
mySteps.remove(requestPresentable);
errors.addAll(result.getErrors());
return result;
}
final DiffRequest request = result.getRequest();
takeStuffFromFactory(request, requestPresentable.createActions(myActionsFactory));
onEveryMove(request, myShowFrame);
return result;
}
@Nullable
private DiffRequest moveInc(final MoveDirection moveDirection, final List<String> errors) {
while (moveDirection.canMove()) {
final int nextIdx = myIndex + moveDirection.direction();
final DiffRequestPresentable diffRequestPresentable = mySteps.get(nextIdx);
DiffRequestPresentable.MyResult result = moveImpl(diffRequestPresentable, errors);
if (result == null) {
return null;
}
if (DiffPresentationReturnValue.removeFromList.equals(result.getReturnValue())) {
if (moveDirection.direction() < 0) {
// our position moves to head
myIndex += moveDirection.direction();
}
continue;
}
myIndex = nextIdx;
return result.getRequest();
}
return null;
}
private void showErrors(final List<String> errors) {
if (errors.isEmpty()) return;
final StringBuilder sb = new StringBuilder("Following problems have occurred:\n\n");
for (String error : errors) {
sb.append(error).append('\n');
}
Messages.showErrorDialog(myProject, sb.toString(), "Show Diff");
}
private interface MoveDirection {
boolean canMove();
int direction();
}
@Nullable
public DiffRequest moveBack() {
return moveWithErrorReport(new MoveDirection() {
public boolean canMove() {
return canMoveBack();
}
public int direction() {
return -1;
}
});
}
private void takeStuffFromFactory(final DiffRequest request, final List<? extends AnAction> actions) {
if (mySteps.size() > 1 || (myActionsFactory != null)) {
request.setToolbarAddons(new DiffRequest.ToolbarAddons() {
public void customize(final DiffToolbar toolbar) {
if (mySteps.size() > 1) {
toolbar.addSeparator();
}
toolbar.addAction(myPrevChangeAction);
toolbar.addAction(myNextChangeAction);
toolbar.addAction(mySelectChangeAction);
if (myActionsFactory != null) {
toolbar.addSeparator();
for (AnAction action : actions) {
toolbar.addAction(action);
}
}
}
});
}
if (myActionsFactory != null) {
request.setBottomComponentFactory(new NullableFactory<JComponent>() {
public JComponent create() {
return myActionsFactory.createBottomComponent();
}
});
}
}
}