blob: 1e783918c334202ce5b77cb3e2d18b31c3a2095b [file] [log] [blame]
/*
* Copyright 2000-2011 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 git4idea.stash;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsNotifier;
import com.intellij.openapi.vcs.changes.ChangeListManagerEx;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.continuation.ContinuationContext;
import git4idea.GitPlatformFacade;
import git4idea.commands.Git;
import git4idea.config.GitVcsSettings;
import git4idea.merge.GitConflictResolver;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import java.util.Collection;
/**
* Saves and restores uncommitted local changes - it is used before and after the update process.
* Respects changelists.
*
* @author Kirill Likhodedov
*/
public abstract class GitChangesSaver {
private static final Logger LOG = Logger.getInstance(GitChangesSaver.class);
@NotNull protected final Project myProject;
@NotNull protected final GitPlatformFacade myPlatformFacade;
@NotNull protected final ChangeListManagerEx myChangeManager;
@NotNull protected final Git myGit;
@NotNull protected final ProgressIndicator myProgressIndicator;
@NotNull protected final String myStashMessage;
protected GitConflictResolver.Params myParams;
/**
* Refreshes files changed during save or load.
*/
public abstract void refresh();
/**
* Returns an instance of the proper GitChangesSaver depending on the chosen save changes policy.
* @return {@link GitStashChangesSaver}, {@link GitShelveChangesSaver} or {@link GitDumbChangesSaver}
*/
public static GitChangesSaver getSaver(@NotNull Project project, @NotNull GitPlatformFacade platformFacade, @NotNull Git git,
@NotNull ProgressIndicator progressIndicator, @NotNull String stashMessage) {
final GitVcsSettings settings = GitVcsSettings.getInstance(project);
if (settings == null) {
return getDefaultSaver(project, platformFacade, git, progressIndicator, stashMessage);
}
switch (settings.updateChangesPolicy()) {
case STASH: return new GitStashChangesSaver(project, platformFacade, git, progressIndicator, stashMessage);
case SHELVE: return new GitShelveChangesSaver(project, platformFacade, git, progressIndicator, stashMessage);
}
return getDefaultSaver(project, platformFacade, git, progressIndicator, stashMessage);
}
// In the case of illegal value in the settings or impossibility to get the settings.
private static GitChangesSaver getDefaultSaver(@NotNull Project project, @NotNull GitPlatformFacade platformFacade, @NotNull Git git,
@NotNull ProgressIndicator progressIndicator, @NotNull String stashMessage) {
return new GitStashChangesSaver(project, platformFacade, git, progressIndicator, stashMessage);
}
protected GitChangesSaver(@NotNull Project project, @NotNull GitPlatformFacade platformFacade, @NotNull Git git,
@NotNull ProgressIndicator indicator, @NotNull String stashMessage) {
myProject = project;
myPlatformFacade = platformFacade;
myGit = git;
myProgressIndicator = indicator;
myStashMessage = stashMessage;
myChangeManager = platformFacade.getChangeListManager(project);
}
/**
* Saves local changes in stash or in shelf.
* @param rootsToSave Save changes only from these roots.
*/
public void saveLocalChanges(@Nullable Collection<VirtualFile> rootsToSave) throws VcsException {
if (rootsToSave == null || rootsToSave.isEmpty()) {
return;
}
save(rootsToSave);
}
/**
* Loads local changes from stash or shelf, and sorts the changes back to the change lists they were before update.
* @param context
*/
public void restoreLocalChanges(ContinuationContext context) {
load(context);
}
public void notifyLocalChangesAreNotRestored() {
if (wereChangesSaved()) {
LOG.info("Update is incomplete, changes are not restored");
VcsNotifier.getInstance(myProject).notifyImportantWarning("Local changes were not restored",
"Before update your uncommitted changes were saved to <a href='saver'>" +
getSaverName() +
"</a>.<br/>" +
"Update is not complete, you have unresolved merges in your working tree<br/>" +
"Resolve conflicts, complete update and restore changes manually.",
new ShowSavedChangesNotificationListener()
);
}
}
public void setConflictResolverParams(GitConflictResolver.Params params) {
myParams = params;
}
/**
* Saves local changes - specific for chosen save strategy.
* @param rootsToSave local changes should be saved on these roots.
*/
protected abstract void save(Collection<VirtualFile> rootsToSave) throws VcsException;
/**
* Loads the changes - specific for chosen save strategy.
* @param exceptionConsumer
*/
protected abstract void load(ContinuationContext exceptionConsumer);
/**
* @return true if there were local changes to save.
*/
protected abstract boolean wereChangesSaved();
/**
* @return name of the save capability provider - stash or shelf.
*/
public abstract String getSaverName();
/**
* Show the saved local changes in the proper viewer.
*/
protected abstract void showSavedChanges();
/**
* The right panel title of the merge conflict dialog: changes that came from update.
*/
@NotNull
protected static String getConflictRightPanelTitle() {
return "Changes from remote";
}
/**
* The left panel title of the merge conflict dialog: changes that were preserved in this saver during update.
*/
@NotNull
protected static String getConflictLeftPanelTitle() {
return "Your uncommitted changes";
}
protected class ShowSavedChangesNotificationListener implements NotificationListener {
@Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equals("saver")) {
showSavedChanges();
}
}
}
}