All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.openapi.diff.actions.MergeOperations Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition platform-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2013 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.diff.actions;

import com.intellij.icons.AllIcons;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diff.DiffBundle;
import com.intellij.openapi.diff.impl.DiffPanelImpl;
import com.intellij.openapi.diff.impl.fragments.Fragment;
import com.intellij.openapi.diff.impl.fragments.FragmentList;
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.ArrayList;
import java.util.List;

public class MergeOperations {
  private final DiffPanelImpl myDiffPanel;
  private final FragmentSide mySide;
  private static final List NO_OPERATIONS = ContainerUtil.emptyList();
  private static final Condition NOT_EQUAL_FRAGMENT = new Condition() {
          public boolean value(Fragment fragment) {
            return fragment.getType() != null;
          }
        };

  public MergeOperations(DiffPanelImpl diffPanel, FragmentSide side) {
    myDiffPanel = diffPanel;
    mySide = side;
  }

  @NotNull
  public List getOperations() {
    Fragment fragment = getCurrentFragment();
    if (fragment == null) return NO_OPERATIONS;
    ArrayList operations = new ArrayList(3);
    TextRange range = fragment.getRange(mySide);
    if (range.getLength() > 0) {
      if (isWritable(mySide)) operations.add(removeOperation(range, getDocument()));
      TextRange otherRange = fragment.getRange(mySide.otherSide());
      boolean otherIsWritable = isWritable(mySide.otherSide());
      if (otherIsWritable) operations.add(insertOperation(range, otherRange.getEndOffset(), getDocument(), getOtherDocument()));
      if (otherRange.getLength() > 0 && otherIsWritable) operations.add(replaceOperation(range, otherRange, getDocument(), getOtherDocument()));
    }
    return operations;
  }

  private boolean isWritable(FragmentSide side) {
    Editor editor = myDiffPanel.getEditor(side);
    return !editor.isViewer() && canMakeWritable(editor.getDocument());
  }

  private static boolean canMakeWritable(final Document document) {
    if (document.isWritable()) {
      return true;
    }
    final VirtualFile file = FileDocumentManager.getInstance().getFile(document);
    if (file != null && file.isInLocalFileSystem()) {
      return true;
    }
    return false;
  }

  public void selectSuggestion() {
    Fragment fragment = getCurrentFragment();
    if (fragment == null) return;
    setSelection(fragment, mySide);
    setSelection(fragment, mySide.otherSide());
  }

  private void setSelection(Fragment fragment, FragmentSide side) {
    TextRange range = fragment.getRange(side);
    if (range.getLength() > 0)
    myDiffPanel.getEditor(side).getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
  }

  private static Operation replaceOperation(TextRange range, TextRange otherRange, Document document, Document otherDocument) {
    return new Operation(DiffBundle.message("merge.editor.replace.operation.name"),
                         AllIcons.Diff.Arrow,
                         otherDocument,
                         replaceModification(range, document, otherRange, otherDocument));
  }

  @Nullable
  public static Operation mostSensible(Document document, Document otherDocument, TextRange range, TextRange otherRange) {
    if (!canMakeWritable(document) && !canMakeWritable(otherDocument)) return null;
    if (range.getLength() != 0) {
      if (canMakeWritable(otherDocument))
        return otherRange.getLength() != 0 ?
               replaceOperation(range, otherRange, document, otherDocument) :
               insertOperation(range, otherRange.getEndOffset(), document, otherDocument);
      else return otherRange.getLength() == 0 ? removeOperation(range, document) : null;
    }
    return null;
  }

  private static Runnable replaceModification(TextRange range, Document document,
                                       final TextRange otherRange, final Document otherDocument) {
    final String replacement = getSubstring(document, range);
    return new Runnable() {
      public void run() {
        otherDocument.replaceString(otherRange.getStartOffset(), otherRange.getEndOffset(), replacement);
      }
    };
  }

  private static Operation insertOperation(TextRange range, int offset, Document document, Document otherDocument) {
    return new Operation(DiffBundle.message("merge.editor.insert.operation.name"),
                         AllIcons.Diff.ArrowLeftDown,
                         otherDocument,
                         insertModification(range, document, offset, otherDocument));
  }

  private static Runnable insertModification(TextRange range, Document document,
                                      final int offset, final Document otherDocument) {
    final String insertion = getSubstring(document, range);
    return new Runnable(){
      public void run() {
        otherDocument.insertString(offset, insertion);
      }
    };
  }

  private static String getSubstring(Document document, TextRange range) {
    return document.getText(range);
  }

  private Document getOtherDocument() {
    return myDiffPanel.getEditor(mySide.otherSide()).getDocument();
  }

  private static Operation removeOperation(TextRange range, Document document) {
    return new Operation(DiffBundle.message("merge.editor.remove.operation.name"),
                         AllIcons.Diff.Remove,
                         document,
                         removeModification(range, document));
  }

  private static Runnable removeModification(final TextRange range, final Document document) {
    return new Runnable(){
      public void run() {
        document.deleteString(range.getStartOffset(), range.getEndOffset());
      }
    };
  }

  private Document getDocument() {
    return myDiffPanel.getEditor(mySide).getDocument();
  }

  public Fragment getCurrentFragment() {
    FragmentList fragments = myDiffPanel.getFragments();
    int caretPosition = myDiffPanel.getEditor(mySide).getCaretModel().getOffset();
    return fragments.getFragmentAt(caretPosition, mySide, NOT_EQUAL_FRAGMENT);
  }

  public static class Operation {
    private final String myName;
    private final Document myDocument;
    private final Runnable myModification;
    private final Icon myGutterIcon;
    private boolean myPerformed = false;

    public Operation(String name, Icon icon, final Document document, Runnable modification) {
      myName = name;
      myGutterIcon = icon;
      myDocument = document;
      myModification = modification;
    }

    public Icon getGutterIcon() {
      return myGutterIcon;
    }

    public String getName() {
      return myName;
    }

    public void perform(final Project project) {
      if (myPerformed) return;
      myPerformed = true;
      if (!myDocument.isWritable()) {
        final VirtualFile file = FileDocumentManager.getInstance().getFile(myDocument);
        final ReadonlyStatusHandler.OperationStatus status = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(file);
        if (status.hasReadonlyFiles()) return;
      }
      ApplicationManager.getApplication().runWriteAction(new Runnable(){
        public void run() {
          CommandProcessor.getInstance().executeCommand(project, myModification, getName(), null);
        }
      });
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy