private Couple<String> keyForChange(final Change change) {
   final FilePath beforePath = ChangesUtil.getBeforePath(change);
   final String beforeKey = beforePath == null ? null : beforePath.getIOFile().getAbsolutePath();
   final FilePath afterPath = ChangesUtil.getAfterPath(change);
   final String afterKey = afterPath == null ? null : afterPath.getIOFile().getAbsolutePath();
   return Couple.of(beforeKey, afterKey);
 }
 public void run() {
   ChangesUtil.markInternalOperation(myChanges, true);
   try {
     doRun();
   } finally {
     ChangesUtil.markInternalOperation(myChanges, false);
   }
 }
 @Override
 public void calcData(DataKey key, DataSink sink) {
   if (key == VcsDataKeys.CHANGES) {
     sink.put(VcsDataKeys.CHANGES, getSelectedChanges());
   } else if (key == VcsDataKeys.CHANGE_LEAD_SELECTION) {
     sink.put(VcsDataKeys.CHANGE_LEAD_SELECTION, getLeadSelection());
   } else if (key == VcsDataKeys.CHANGE_LISTS) {
     sink.put(VcsDataKeys.CHANGE_LISTS, getSelectedChangeLists());
   } else if (key == PlatformDataKeys.VIRTUAL_FILE_ARRAY) {
     sink.put(PlatformDataKeys.VIRTUAL_FILE_ARRAY, getSelectedFiles());
   } else if (key == PlatformDataKeys.NAVIGATABLE) {
     final VirtualFile[] files = getSelectedFiles();
     if (files.length == 1 && !files[0].isDirectory()) {
       sink.put(PlatformDataKeys.NAVIGATABLE, new OpenFileDescriptor(myProject, files[0], 0));
     }
   } else if (key == PlatformDataKeys.NAVIGATABLE_ARRAY) {
     sink.put(
         PlatformDataKeys.NAVIGATABLE_ARRAY,
         ChangesUtil.getNavigatableArray(myProject, getSelectedFiles()));
   } else if (key == PlatformDataKeys.DELETE_ELEMENT_PROVIDER) {
     final TreePath[] paths = getSelectionPaths();
     if (paths != null) {
       for (TreePath path : paths) {
         ChangesBrowserNode node = (ChangesBrowserNode) path.getLastPathComponent();
         if (!(node.getUserObject() instanceof ChangeList)) {
           sink.put(PlatformDataKeys.DELETE_ELEMENT_PROVIDER, new VirtualFileDeleteProvider());
           break;
         }
       }
     }
   } else if (key == PlatformDataKeys.COPY_PROVIDER) {
     sink.put(PlatformDataKeys.COPY_PROVIDER, myCopyProvider);
   } else if (key == UNVERSIONED_FILES_DATA_KEY) {
     sink.put(UNVERSIONED_FILES_DATA_KEY, getSelectedUnversionedFiles());
   } else if (key == VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY) {
     sink.put(VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY, getSelectedModifiedWithoutEditing());
   } else if (key == LOCALLY_DELETED_CHANGES) {
     sink.put(LOCALLY_DELETED_CHANGES, getSelectedLocallyDeletedChanges());
   } else if (key == MISSING_FILES_DATA_KEY) {
     sink.put(MISSING_FILES_DATA_KEY, getSelectedMissingFiles());
   } else if (VcsDataKeys.HAVE_LOCALLY_DELETED == key) {
     sink.put(VcsDataKeys.HAVE_LOCALLY_DELETED, haveLocallyDeleted());
   } else if (VcsDataKeys.HAVE_MODIFIED_WITHOUT_EDITING == key) {
     sink.put(VcsDataKeys.HAVE_MODIFIED_WITHOUT_EDITING, haveLocallyModified());
   } else if (VcsDataKeys.HAVE_SELECTED_CHANGES == key) {
     sink.put(VcsDataKeys.HAVE_SELECTED_CHANGES, haveSelectedChanges());
   } else if (key == HELP_ID_DATA_KEY) {
     sink.put(HELP_ID_DATA_KEY, ourHelpId);
   } else if (key == VcsDataKeys.CHANGES_IN_LIST_KEY) {
     final TreePath selectionPath = getSelectionPath();
     if (selectionPath != null && selectionPath.getPathCount() > 1) {
       ChangesBrowserNode<?> firstNode = (ChangesBrowserNode) selectionPath.getPathComponent(1);
       if (firstNode instanceof ChangesBrowserChangeListNode) {
         final List<Change> list = firstNode.getAllChangesUnder();
         sink.put(VcsDataKeys.CHANGES_IN_LIST_KEY, list);
       }
     }
   }
 }
 @Nullable
 private static Change[] loadFakeRevisions(final Project project, final Change[] changes) {
   List<Change> matchingChanges = new ArrayList<Change>();
   for (Change change : changes) {
     matchingChanges.addAll(
         ChangeListManager.getInstance(project).getChangesIn(ChangesUtil.getFilePath(change)));
   }
   return matchingChanges.toArray(new Change[matchingChanges.size()]);
 }
 /** @return false if not up to date */
 public boolean isUpToDate(final Change change) {
   final AbstractVcs vcs = ChangesUtil.getVcsForChange(change, myProject);
   if (vcs == null) return true;
   final RemoteDifferenceStrategy strategy = vcs.getRemoteDifferenceStrategy();
   if (RemoteDifferenceStrategy.ASK_TREE_PROVIDER.equals(strategy)) {
     return myRemoteRevisionsStateCache.isUpToDate(change);
   } else {
     return myRemoteRevisionsNumbersCache.isUpToDate(change);
   }
 }
 public static BeforeAfter<DiffContent> createBinaryDiffContents(
     final Project project, final Change change) throws VcsException {
   final FilePath filePath = ChangesUtil.getFilePath(change);
   try {
     return new BeforeAfter<DiffContent>(
         createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()),
         createBinaryFileContent(project, change.getAfterRevision(), filePath.getName()));
   } catch (IOException e) {
     throw new VcsException(e);
   }
 }
 public boolean isUpToDate(final Change change) {
   final List<File> files = ChangesUtil.getIoFilesFromChanges(Collections.singletonList(change));
   synchronized (myLock) {
     for (File file : files) {
       final String path = file.getAbsolutePath();
       final Pair<Boolean, VcsRoot> data = myChanged.get(path);
       if (data != null && Boolean.TRUE.equals(data.getFirst())) return false;
     }
   }
   return true;
 }
  public ShelvedChangeList shelveChanges(
      final Collection<Change> changes, final String commitMessage, final boolean rollback)
      throws IOException, VcsException {
    final List<Change> textChanges = new ArrayList<Change>();
    final List<ShelvedBinaryFile> binaryFiles = new ArrayList<ShelvedBinaryFile>();
    for (Change change : changes) {
      if (ChangesUtil.getFilePath(change).isDirectory()) {
        continue;
      }
      if (change.getBeforeRevision() instanceof BinaryContentRevision
          || change.getAfterRevision() instanceof BinaryContentRevision) {
        binaryFiles.add(shelveBinaryFile(change));
      } else {
        textChanges.add(change);
      }
    }

    final ShelvedChangeList changeList;
    try {
      File patchPath = getPatchPath(commitMessage);
      ProgressManager.checkCanceled();
      final List<FilePatch> patches =
          IdeaTextPatchBuilder.buildPatch(
              myProject, textChanges, myProject.getBaseDir().getPresentableUrl(), false);
      ProgressManager.checkCanceled();

      CommitContext commitContext = new CommitContext();
      baseRevisionsOfDvcsIntoContext(textChanges, commitContext);
      myFileProcessor.savePathFile(
          new CompoundShelfFileProcessor.ContentProvider() {
            public void writeContentTo(final Writer writer, CommitContext commitContext)
                throws IOException {
              UnifiedDiffWriter.write(myProject, patches, writer, "\n", commitContext);
            }
          },
          patchPath,
          commitContext);

      changeList =
          new ShelvedChangeList(
              patchPath.toString(), commitMessage.replace('\n', ' '), binaryFiles);
      myShelvedChangeLists.add(changeList);
      ProgressManager.checkCanceled();

      if (rollback) {
        new RollbackWorker(myProject, false)
            .doRollback(changes, true, null, VcsBundle.message("shelve.changes.action"));
      }
    } finally {
      notifyStateChanged();
    }

    return changeList;
  }
  private ShelvedBinaryFile shelveBinaryFile(final Change change) throws IOException {
    final ContentRevision beforeRevision = change.getBeforeRevision();
    final ContentRevision afterRevision = change.getAfterRevision();
    File beforeFile = beforeRevision == null ? null : beforeRevision.getFile().getIOFile();
    File afterFile = afterRevision == null ? null : afterRevision.getFile().getIOFile();
    String shelvedPath = null;
    if (afterFile != null) {
      String shelvedName = FileUtil.getNameWithoutExtension(afterFile.getName());
      String shelvedExt = FileUtil.getExtension(afterFile.getName());
      File shelvedFile =
          FileUtil.findSequentNonexistentFile(
              myFileProcessor.getBaseIODir(), shelvedName, shelvedExt);

      myFileProcessor.saveFile(afterRevision.getFile().getIOFile(), shelvedFile);

      shelvedPath = shelvedFile.getPath();
    }
    String beforePath = ChangesUtil.getProjectRelativePath(myProject, beforeFile);
    String afterPath = ChangesUtil.getProjectRelativePath(myProject, afterFile);
    return new ShelvedBinaryFile(beforePath, afterPath, shelvedPath);
  }
 private List<Change> filterOutBinary(List<Change> paths) {
   List<Change> result = null;
   for (Iterator<Change> iterator = paths.iterator(); iterator.hasNext(); ) {
     final Change change = iterator.next();
     if (ChangesUtil.isBinaryChange(change)) {
       result = (result == null ? new SmartList<Change>() : result);
       result.add(change);
       iterator.remove();
     }
   }
   return result;
 }
 private static SimpleDiffRequest createBinaryDiffRequest(
     final Project project, final Change change) throws VcsException {
   final FilePath filePath = ChangesUtil.getFilePath(change);
   final SimpleDiffRequest request = new SimpleDiffRequest(project, filePath.getPath());
   try {
     request.setContents(
         createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()),
         createBinaryFileContent(project, change.getAfterRevision(), filePath.getName()));
     return request;
   } catch (IOException e) {
     throw new VcsException(e);
   }
 }
    private void doRun() {
      myIndicator = ProgressManager.getInstance().getProgressIndicator();

      final List<Change> changesToRefresh = new ArrayList<Change>();
      try {
        ChangesUtil.processChangesByVcs(
            myProject,
            myChanges,
            new ChangesUtil.PerVcsProcessor<Change>() {
              public void process(AbstractVcs vcs, List<Change> changes) {
                final RollbackEnvironment environment = vcs.getRollbackEnvironment();
                if (environment != null) {
                  changesToRefresh.addAll(changes);

                  if (myIndicator != null) {
                    myIndicator.setText(vcs.getDisplayName() + ": performing rollback...");
                    myIndicator.setIndeterminate(false);
                    myIndicator.checkCanceled();
                  }
                  environment.rollbackChanges(
                      changes,
                      myExceptions,
                      new RollbackProgressModifier(changes.size(), myIndicator));
                  if (myIndicator != null) {
                    myIndicator.setText2("");
                    myIndicator.checkCanceled();
                  }

                  if (myExceptions.isEmpty() && myDeleteLocallyAddedFiles) {
                    deleteAddedFilesLocally(changes);
                  }
                }
              }
            });
      } catch (ProcessCanceledException e) {
        // still do refresh
      }

      if (myIndicator != null) {
        myIndicator.startNonCancelableSection();
        myIndicator.setIndeterminate(true);
        myIndicator.setText2("");
        myIndicator.setText(VcsBundle.message("progress.text.synchronizing.files"));
      }

      doRefresh(myProject, changesToRefresh);

      AbstractVcsHelper.getInstance(myProject)
          .showErrors(myExceptions, VcsBundle.message("changes.action.rollback.text"));
    }
 private static boolean directoryOrBinary(final Change change) {
   // todo instead for repository tab, filter directories (? ask remotely ? non leaf nodes)
   /*if ((change.getBeforeRevision() instanceof BinaryContentRevision) || (change.getAfterRevision() instanceof BinaryContentRevision)) {
     changesList.remove(i);
     continue;
   }*/
   final FilePath path = ChangesUtil.getFilePath(change);
   if (path.isDirectory()) {
     return !change.hasOtherLayers();
   }
   /*final FileType type = path.getFileType();
   if ((! FileTypes.UNKNOWN.equals(type)) && (type.isBinary())) {
     return true;
   }*/
   return false;
 }
 public boolean addChangeToList(
     @NotNull final String name, final Change change, final VcsKey vcsKey) {
   LOG.debug(
       "[addChangeToList] name: "
           + name
           + " change: "
           + ChangesUtil.getFilePath(change).getPath()
           + " vcs: "
           + (vcsKey == null ? null : vcsKey.getName()));
   final LocalChangeList changeList = myMap.get(name);
   if (changeList != null) {
     ((LocalChangeListImpl) changeList).addChange(change);
     myIdx.changeAdded(change, vcsKey);
   }
   return changeList != null;
 }
  public MergeFromTheirsResolver(
      SvnVcs vcs, TreeConflictDescription description, Change change, SvnRevisionNumber revision) {
    myVcs = vcs;
    myDescription = description;
    myChange = change;
    myCommittedRevision = revision;
    myOldFilePath = myChange.getBeforeRevision().getFile();
    myNewFilePath = myChange.getAfterRevision().getFile();
    myBaseForPatch = ChangesUtil.findValidParentAccurately(myNewFilePath);
    myOldPresentation = TreeConflictRefreshablePanel.filePath(myOldFilePath);
    myNewPresentation = TreeConflictRefreshablePanel.filePath(myNewFilePath);

    myTheirsChanges = new ArrayList<Change>();
    myTheirsBinaryChanges = new ArrayList<Change>();
    myWarnings = new ArrayList<VcsException>();
    myTextPatches = Collections.emptyList();
  }
 private void baseRevisionsOfDvcsIntoContext(
     List<Change> textChanges, CommitContext commitContext) {
   ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject);
   if (vcsManager.dvcsUsedInProject()
       && VcsConfiguration.getInstance(myProject).INCLUDE_TEXT_INTO_SHELF) {
     final Set<Change> big = SelectFilesToAddTextsToPatchPanel.getBig(textChanges);
     final ArrayList<FilePath> toKeep = new ArrayList<FilePath>();
     for (Change change : textChanges) {
       if (change.getBeforeRevision() == null || change.getAfterRevision() == null) continue;
       if (big.contains(change)) continue;
       FilePath filePath = ChangesUtil.getFilePath(change);
       final AbstractVcs vcs = vcsManager.getVcsFor(filePath);
       if (vcs != null && VcsType.distibuted.equals(vcs.getType())) {
         toKeep.add(filePath);
       }
     }
     commitContext.putUserData(BaseRevisionTextPatchEP.ourPutBaseRevisionTextKey, true);
     commitContext.putUserData(BaseRevisionTextPatchEP.ourBaseRevisionPaths, toKeep);
   }
 }
 @Override
 public void run(ContinuationContext context) {
   if (myTheirsBinaryChanges.isEmpty()) return;
   final List<Change> converted;
   try {
     converted = convertPaths(myTheirsBinaryChanges);
   } catch (VcsException e) {
     context.handleException(e, true);
     return;
   }
   if (converted.isEmpty()) return;
   final Map<FilePath, Change> map = new HashMap<FilePath, Change>();
   for (Change change : converted) {
     map.put(ChangesUtil.getFilePath(change), change);
   }
   final Collection<FilePath> selected = chooseBinaryFiles(converted, map.keySet());
   myTheirsBinaryChanges.clear();
   for (FilePath filePath : selected) {
     myTheirsBinaryChanges.add(map.get(filePath));
   }
 }
    @Override
    public void run(final ContinuationContext context) {
      final MultiMap<String, Change> map = myIntersection.getChangesSubset();

      final RefreshSessionImpl session =
          new RefreshSessionImpl(
              true,
              false,
              new Runnable() {
                public void run() {
                  context.ping();
                }
              });

      for (String name : map.keySet()) {
        try {
          final Collection<Change> changes = map.get(name);
          ApplicationManager.getApplication()
              .invokeAndWait(
                  new Runnable() {
                    @Override
                    public void run() {
                      FileDocumentManager.getInstance().saveAllDocuments();
                    }
                  },
                  ModalityState.NON_MODAL);
          ShelveChangesManager.getInstance(myProject)
              .shelveChanges(
                  changes, myIntersection.getComment(name) + " (auto shelve before merge)", true);
          session.addAllFiles(ChangesUtil.getFilesFromChanges(changes));
        } catch (IOException e) {
          finishWithError(context, e.getMessage(), true);
        } catch (VcsException e) {
          finishWithError(context, e.getMessage(), true);
        }
      }
      // first suspend to guarantee stop->then start back sequence
      context.suspend();
      session.launch();
    }
  private Collection<FilePath> chooseBinaryFiles(List<Change> converted, Set<FilePath> paths) {
    String singleMessage = "";
    if (paths.size() == 1) {
      final Change change = converted.get(0);
      final FileStatus status = change.getFileStatus();
      final FilePath path = ChangesUtil.getFilePath(change);
      final String stringPath = TreeConflictRefreshablePanel.filePath(path);
      if (FileStatus.DELETED.equals(status)) {
        singleMessage = "Delete binary file " + stringPath + " (according to theirs changes)?";
      } else if (FileStatus.ADDED.equals(status)) {
        singleMessage = "Create binary file " + stringPath + " (according to theirs changes)?";
      } else {
        singleMessage =
            "Apply changes to binary file " + stringPath + " (according to theirs changes)?";
      }
    }
    return AbstractVcsHelper.getInstance(myVcs.getProject())
        .selectFilePathsToProcess(
            new ArrayList<FilePath>(paths),
            TreeConflictRefreshablePanel.TITLE,
            "Select binary files to patch",
            TreeConflictRefreshablePanel.TITLE,
            singleMessage,
            new VcsShowConfirmationOption() {

              @Override
              public Value getValue() {
                return null;
              }

              @Override
              public void setValue(Value value) {}

              @Override
              public boolean isPersistent() {
                return false;
              }
            });
  }
 public void addChangeToCorrespondingList(final Change change, final VcsKey vcsKey) {
   final String path = ChangesUtil.getFilePath(change).getPath();
   LOG.debug(
       "[addChangeToCorrespondingList] for change "
           + path
           + " type: "
           + change.getType()
           + " have before revision: "
           + (change.getBeforeRevision() != null));
   assert myDefault != null;
   for (LocalChangeList list : myMap.values()) {
     if (list.isDefault()) {
       LOG.debug(
           "[addChangeToCorrespondingList] skip default list: "
               + list.getName()
               + " type: "
               + change.getType()
               + " have before revision: "
               + (change.getBeforeRevision() != null));
       continue;
     }
     if (((LocalChangeListImpl) list).processChange(change)) {
       LOG.debug(
           "[addChangeToCorrespondingList] matched: "
               + list.getName()
               + " type: "
               + change.getType()
               + " have before revision: "
               + (change.getBeforeRevision() != null));
       myIdx.changeAdded(change, vcsKey);
       return;
     }
   }
   ((LocalChangeListImpl) myDefault).processChange(change);
   myIdx.changeAdded(change, vcsKey);
 }
 protected static boolean canShowDiff(Change[] changes) {
   if (changes == null || changes.length == 0) return false;
   return !ChangesUtil.getFilePath(changes[0]).isDirectory() || changes[0].hasOtherLayers();
 }
 private static void markInternalOperation(
     List<Pair<VirtualFile, ApplyTextFilePatch>> textPatches, boolean set) {
   for (Pair<VirtualFile, ApplyTextFilePatch> patch : textPatches) {
     ChangesUtil.markInternalOperation(patch.getFirst(), set);
   }
 }
    @Override
    public void run(ContinuationContext context) {
      final String message;
      final Intersection intersection;
      final ChangeListManager listManager = ChangeListManager.getInstance(myProject);
      final List<LocalChangeList> localChangeLists = listManager.getChangeListsCopy();

      if (myMergeAll) {
        intersection = getMergeAllIntersection(localChangeLists);
        message =
            "There are local changes that can potentially intersect with merge changes.\nDo you want to continue?";
      } else {
        intersection = checkIntersection(myLists, localChangeLists);
        message =
            "There are local changes that will intersect with merge changes.\nDo you want to continue?";
      }
      if (intersection == null || intersection.getChangesSubset().isEmpty()) return;

      final LocalChangesAction action;
      if (!myMergeAll) {
        final LocalChangesAction[] possibleResults = {
          LocalChangesAction.shelve,
          LocalChangesAction.inspect,
          LocalChangesAction.continueMerge,
          LocalChangesAction.cancel
        };
        final int result =
            Messages.showDialog(
                message,
                myTitle,
                new String[] {
                  "Shelve local changes", "Inspect changes", "Continue merge", "Cancel"
                },
                0,
                Messages.getQuestionIcon());
        action = possibleResults[result];
      } else {
        final LocalChangesAction[] possibleResults = {
          LocalChangesAction.shelve, LocalChangesAction.continueMerge, LocalChangesAction.cancel
        };
        final int result =
            Messages.showDialog(
                message,
                myTitle,
                new String[] {"Shelve local changes", "Continue merge", "Cancel"},
                0,
                Messages.getQuestionIcon());
        action = possibleResults[result];
      }
      switch (action) {
          // shelve
        case shelve:
          context.next(new ShelveLocalChanges(intersection));
          return;
          // cancel
        case cancel:
          context.cancelEverything();
          return;
          // continue
        case continueMerge:
          return;
          // inspect
        case inspect:
          final Collection<Change> changes =
              (Collection<Change>) intersection.getChangesSubset().values();
          final List<FilePath> paths = ChangesUtil.getPaths(changes);
          Collections.sort(paths, FilePathByPathComparator.getInstance());
          // todo rework message
          IntersectingLocalChangesPanel.showInVersionControlToolWindow(
              myProject,
              myTitle + ", local changes intersection",
              paths,
              "The following file(s) have local changes that will intersect with merge changes:");
          context.cancelEverything();
          return;
        default:
      }
    }