/*
* Copyright 2000-2010 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 org.community.intellij.plugins.communitycase.checkout.branches;
import com.intellij.lifecycle.PeriodicalTasksCloser;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.util.EventDispatcher;
import org.community.intellij.plugins.communitycase.Branch;
import org.community.intellij.plugins.communitycase.Util;
import org.community.intellij.plugins.communitycase.Vcs;
import org.community.intellij.plugins.communitycase.commands.Command;
import org.community.intellij.plugins.communitycase.commands.SimpleHandler;
import org.community.intellij.plugins.communitycase.history.HistoryUtils;
import org.community.intellij.plugins.communitycase.merge.MergeUtil;
import org.community.intellij.plugins.communitycase.rebase.RebaseUtils;
import org.community.intellij.plugins.communitycase.ui.UiUtil;
import org.community.intellij.plugins.communitycase.vfs.ReferenceListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
/**
* branch configurations settings and project level state
*/
@State(
name = ".Branch.Configurations",
storages = {@Storage(
id = "ws",
file = "$WORKSPACE_FILE$")})
public class BranchConfigurations implements PersistentStateComponent<BranchConfigurations.State>, Disposable {
/**
* The logger
*/
private static final Logger LOG = Logger.getInstance("#"+BranchConfigurations.class.getName());
/**
* The comparator for branch configuration by name
*/
private static final Comparator<BranchConfiguration> CONFIGURATION_COMPARATOR = new Comparator<BranchConfiguration>() {
@Override
public int compare(BranchConfiguration o1, BranchConfiguration o2) {
return o1.NAME.compareTo(o2.NAME);
}
};
/**
* The comparator for branch information by root
*/
private static final Comparator<BranchInfo> BRANCH_INFO_COMPARATOR = new Comparator<BranchInfo>() {
@Override
public int compare(BranchInfo o1, BranchInfo o2) {
return o1.ROOT.compareTo(o2.ROOT);
}
};
/**
* The project
*/
private final Project myProject;
/**
* The vcs
*/
private final Vcs myVcs;
/**
* The shelve manager instance
*/
private final ShelveChangesManager myShelveManager;
/**
* The dirty scope manager
*/
private final VcsDirtyScopeManager myDirtyScopeManager;
/**
* Change manager
*/
private final ChangeListManagerEx myChangeManager;
/**
* Project manager
*/
private final ProjectManagerEx myProjectManager;
/**
* The state lock
*/
private final Object myStateLock = new Object();
/**
* The set of configurations
*/
private final HashMap<String, org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration> myConfigurations = new HashMap<String, org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration>();
/**
* Create event dispatcher for configuration events
*/
private final EventDispatcher<BranchConfigurationsListener> myListeners =
EventDispatcher.create(BranchConfigurationsListener.class);
/**
* The current configuration
*/
private org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration myCurrentConfiguration;
/**
* The reference listener
*/
private final ReferenceListener myReferenceListener;
/**
* The current status (cached, invalidated when references change)
*/
private SpecialStatus myCurrentStatus;
/**
* The collection of roots
*/
private List<VirtualFile> myRoots = Collections.emptyList();
/**
* If true, checkout background process is in progress
*/
private boolean myCheckoutIsInProgress = false;
/**
* The widget uninstall action (on deactivate)
*/
private Runnable myWidgetUninstall;
/**
* Listener for changes
*/
private final ChangeListAdapter myChangesListener;
/**
* If true, the widget is enabled
*/
private boolean myWidgetEnabled = true;
/**
* The constructor used to dependency injection
*
* @param project the project
* @param shelveManager the shelve manager
* @param dirtyScopeManager the dirty scope manager
* @param changeManager the change manager
* @param projectManager the project manager
*/
public BranchConfigurations(Project project, ShelveChangesManager shelveManager,
VcsDirtyScopeManager dirtyScopeManager,
ChangeListManagerEx changeManager,
ProjectManagerEx projectManager) {
myProject = project;
myVcs = Vcs.getInstance(project);
myShelveManager = shelveManager;
myDirtyScopeManager = dirtyScopeManager;
myChangeManager = changeManager;
myProjectManager = projectManager;
myReferenceListener = new ReferenceListener() {
@Override
public void referencesChanged(VirtualFile root) {
BranchConfigurations.this.referencesChanged();
}
};
Disposer.register(myProject, this);
myChangesListener = new ChangeListAdapter() {
@Override
public void changesRemoved(Collection<Change> changes, ChangeList fromList) {
BranchConfigurations.this.referencesChanged();
}
@Override
public void changesAdded(Collection<Change> changes, ChangeList toList) {
BranchConfigurations.this.referencesChanged();
}
};
}
/**
* Add listener
*
* @param l the listener
*/
public void addConfigurationListener(BranchConfigurationsListener l) {
myListeners.addListener(l);
}
/**
* Remove listener
*
* @param l the listener
*/
public void removeConfigurationListener(BranchConfigurationsListener l) {
myListeners.removeListener(l);
}
/**
* Handle reference change, also notified when roots changed.
*/
public void referencesChanged() {
synchronized (myStateLock) {
updateRootCollection();
updateSpecialStatus();
fireReferencesChanged();
}
}
/**
* Fire that references changed
*/
private void fireReferencesChanged() {
myListeners.getMulticaster().referencesChanged();
}
/**
* Update collections of roots
*/
private void updateRootCollection() {
try {
myRoots = Util.getRoots(myProject, myVcs);
}
catch (VcsException e) {
LOG.warn("Empty list of roots is detected", e);
myRoots = Collections.emptyList();
}
}
/**
* Update special status
*/
private void updateSpecialStatus() {
SpecialStatus p = myCurrentStatus;
myCurrentStatus = calculateSpecialStatus();
if (p != myCurrentStatus) {
myListeners.getMulticaster().specialStatusChanged();
}
}
/**
* Activate component
*/
public void activate() {
myVcs.addReferenceListener(myReferenceListener);
myChangeManager.addChangeListListener(myChangesListener);
synchronized (myStateLock) {
updateRootCollection();
if (myCurrentConfiguration == null) {
if (calculateSpecialStatus() == SpecialStatus.NORMAL) {
try {
detectLocals();
} catch (VcsException e) {
LOG.info("Exception during detecting local configurations", e);
UiUtil.checkExecutableAndShowNotification(myProject, e);
}
}
}
referencesChanged();
}
if (isWidgetEnabled()) {
installWidget();
}
}
/**
* Install widget
*/
private void installWidget() {
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
final Runnable r = BranchesWidget.install(myProject, this);
synchronized (myStateLock) {
myWidgetUninstall = r;
}
}
}
/**
* Deactivate component
*/
public void deactivate() {
myVcs.removeReferenceListener(myReferenceListener);
myChangeManager.removeChangeListListener(myChangesListener);
uninstallWidget();
}
private void uninstallWidget() {
final Runnable r;
synchronized (myStateLock) {
r = myWidgetUninstall;
myWidgetUninstall = null;
}
if (r != null) {
r.run();
}
}
/**
* Get component instance
*
* @param project a context project
* @return the settings
*/
public static BranchConfigurations getInstance(Project project) {
return PeriodicalTasksCloser.getInstance().safeGetService(project, BranchConfigurations.class);
}
@Override
public void dispose() {
deactivate();
}
/**
* {@inheritDoc}
*/
@SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext"})
@Override
public State getState() {
synchronized (myStateLock) {
State rc = new State();
rc.IS_WIDGET_ENABLED = myWidgetEnabled;
rc.CURRENT = myCurrentConfiguration == null ? null : myCurrentConfiguration.getName();
ArrayList<BranchConfiguration> cs = new ArrayList<BranchConfiguration>(myConfigurations.size());
for (org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration ci : myConfigurations.values()) {
BranchConfiguration c = new BranchConfiguration();
c.NAME = ci.getName();
Map<String, String> map = ci.getReferences();
ArrayList<BranchInfo> bs = new ArrayList<BranchInfo>(map.size());
for (Map.Entry<String, String> m : map.entrySet()) {
BranchInfo b = new BranchInfo();
b.ROOT = m.getKey();
b.REFERENCE = m.getValue();
bs.add(b);
}
c.BRANCHES = bs.toArray(new BranchInfo[bs.size()]);
Arrays.sort(c.BRANCHES, BRANCH_INFO_COMPARATOR);
c.CHANGES = ci.getChanges();
c.IS_AUTO_DETECTED = ci.isAutoDetected();
cs.add(c);
}
rc.CONFIGURATIONS = cs.toArray(new BranchConfiguration[cs.size()]);
Arrays.sort(rc.CONFIGURATIONS, CONFIGURATION_COMPARATOR);
return rc;
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext"})
@Override
public void loadState(State state) {
synchronized (myStateLock) {
if (!myConfigurations.isEmpty()) {
return;
}
for (BranchConfiguration bc : state.CONFIGURATIONS) {
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration n = new org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration(this, bc.NAME);
myConfigurations.put(n.getName(), n);
for (BranchInfo bi : bc.BRANCHES) {
n.setReference(bi.ROOT, bi.REFERENCE);
}
myConfigurations.put(bc.NAME, n);
n.setAutoDetected(bc.IS_AUTO_DETECTED);
}
if (myCurrentConfiguration == null) {
myCurrentConfiguration = myConfigurations.get(state.CURRENT);
}
else {
myCurrentConfiguration = myConfigurations.get(myCurrentConfiguration.getName());
if (myCurrentConfiguration == null) {
myCurrentConfiguration = myConfigurations.get(state.CURRENT);
}
}
fireCurrentConfigurationChanged();
fireConfigurationsChanged();
if (state.IS_WIDGET_ENABLED != myWidgetEnabled) {
myWidgetEnabled = state.IS_WIDGET_ENABLED;
updateWidgetState();
}
}
}
/**
* Update widget state after update
*/
private void updateWidgetState() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (isWidgetEnabled()) {
if (myVcs.isActivated() && myWidgetUninstall == null) {
installWidget();
}
}
else {
uninstallWidget();
}
}
});
}
/**
* @return true if widget is enabled
*/
public boolean isWidgetEnabled() {
synchronized (myStateLock) {
return myWidgetEnabled;
}
}
/**
* Update widget state
*
* @param value true to enable widget
*/
public void setWidgetEnabled(boolean value) {
synchronized (myStateLock) {
myWidgetEnabled = value;
updateWidgetState();
}
}
/**
* @return the candidate remote configurations
*/
List<String> getRemotesCandidates() {
try {
final List<VirtualFile> roots;
synchronized (myStateLock) {
roots = myRoots;
}
return detectConfigurations(false, roots);
}
catch (VcsException e) {
return Collections.emptyList();
}
}
/**
* @return the overall special status
*/
public SpecialStatus getSpecialStatus() {
synchronized (myStateLock) {
return myCurrentStatus;
}
}
/**
* @return the calculated overall special status
*/
private SpecialStatus calculateSpecialStatus() {
synchronized (myStateLock) {
if (myCheckoutIsInProgress) {
return SpecialStatus.CHECKOUT_IN_PROGRESS;
}
for (VirtualFile root : myRoots) {
if (RebaseUtils.isRebaseInTheProgress(root)) {
return SpecialStatus.REBASING;
}
if (MergeUtil.isMergeInTheProgress(root)) {
return SpecialStatus.MERGING;
}
}
for (LocalChangeList changeList : myChangeManager.getChangeListsCopy()) {
for (Change change : changeList.getChanges()) {
if (change.getFileStatus() == FileStatus.MERGED_WITH_CONFLICTS) {
return SpecialStatus.MERGING;
}
}
}
return myRoots.size() == 0 ? SpecialStatus.NON_ : SpecialStatus.NORMAL;
}
}
/**
* Detect local branch configurations
*
* @throws VcsException if there is a problem with detecting
*/
private void detectLocals() throws VcsException {
synchronized (myStateLock) {
final HashMap<VirtualFile, String> rootToCurrentBranch = new HashMap<VirtualFile, String>();
for (VirtualFile root : myRoots) {
Branch current = Branch.current(myProject, root);
rootToCurrentBranch.put(root, current == null ? "" : current.getName());
}
if (myConfigurations.isEmpty()) {
detectLocalConfigurations(true);
updateCurrentConfiguration(rootToCurrentBranch);
if (myCurrentConfiguration == null) {
// the configuration does not matches any standard, there could be no configurations with spaces at this point
// since it is not allowed branch name.
String name = "untitled";
if (myConfigurations.containsKey(name)) {
String p = name;
name = null;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
final String c = p + i;
if (!myConfigurations.containsKey(c)) {
name = c;
break;
}
}
if (name == null) {
name = "untitled 1";
}
}
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration c = createConfiguration(name);
for (VirtualFile root : myRoots) {
c.setReference(root.getPath(), describeRoot(root));
}
}
} else if (myCurrentConfiguration == null) {
updateCurrentConfiguration(rootToCurrentBranch);
}
fireCurrentConfigurationChanged();
fireConfigurationsChanged();
}
}
/**
* Updates myCurrentConfiguration (displayed in the BranchesWidget) to the proper value from the list
* of all myConfigurations.
* @param rootToCurrentBranch Mapping from a root to the name of current branch selected on this root.
*/
private void updateCurrentConfiguration(HashMap<VirtualFile, String> rootToCurrentBranch) {
for (org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration configuration : myConfigurations.values()) {
boolean currentsMatched = true;
for (VirtualFile root : myRoots) {
currentsMatched &= rootToCurrentBranch.get(root).equals(configuration.getReference(root.getPath()));
}
if (currentsMatched) {
myCurrentConfiguration = configuration;
break;
}
}
}
/**
* Detect local configurations
*
* @param complete if complete configurations should be detected
* @throws VcsException
*/
void detectLocalConfigurations(boolean complete) throws VcsException {
synchronized (myStateLock) {
if (complete) {
List<String> locals = detectConfigurations(true, myRoots);
if (locals.isEmpty()) {
// no commits
locals.add("master");
}
locals.removeAll(myConfigurations.keySet());
for (String localName : locals) {
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration c = createConfiguration(localName);
c.setAutoDetected(true);
for (VirtualFile root : myRoots) {
c.setReference(root.getPath(), localName);
}
}
}
else {
HashSet<String> detected = new HashSet<String>();
HashSet<String> forRoot = new HashSet<String>();
for (VirtualFile root : myRoots) {
forRoot.clear();
Branch.listAsStrings(myProject, root, false, true, forRoot, null);
for (String b : forRoot) {
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration c;
if (detected.contains(b)) {
c = myConfigurations.get(b);
}
else if (!myConfigurations.containsKey(b)) {
detected.add(b);
c = createConfiguration(b);
c.setAutoDetected(true);
}
else {
continue;
}
c.setReference(root.getPath(), b);
}
}
}
}
}
/**
* The configurations changed
*/
private void fireConfigurationsChanged() {
myListeners.getMulticaster().configurationsChanged();
}
/**
* The current configuration changed
*/
private void fireCurrentConfigurationChanged() {
myListeners.getMulticaster().currentConfigurationChanged();
}
/**
* Describe vcs root
*
* @param root the root to describe
* @return the current reference
* @throws VcsException if there is a problem with describing the root
*/
String describeRoot(VirtualFile root) throws VcsException {
Branch current = Branch.current(myProject, root);
if (current == null) {
// It is on the tag or specific commit. In future, support for submodules should be added.
return detectTag(root, "HEAD");
}
else {
return current.getName();
}
}
/**
* Get tag name for the head
*
* @param root the root to describe
* @param ref the ref to detect
* @return the commit expression that describes root state
*/
String detectTag(VirtualFile root, final String ref) {
try {
SimpleHandler h = new SimpleHandler(myProject, root, Command.DESCRIBE);
h.addParameters("--tags", "--exact", ref);
h.setRemote(true);
return h.run().trim();
}
catch (VcsException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("describe HEAD failed for root: " + root.getPath());
}
try {
return HistoryUtils.validateRevisionNumber(ref).asString();
}
catch (VcsException e1) {
throw new RuntimeException("Unexpected exception at this time, the failure should have been detected at current(): ", e1);
}
}
}
/**
* Detect possible configurations
*
* @param roots the vcs roots used to detect configuraitons
* @return a sorted list of branches
* @throws VcsException if there is a problem with running
*/
private List<String> detectConfigurations(boolean local, final List<VirtualFile> roots) throws VcsException {
HashSet<String> all = new HashSet<String>();
HashSet<String> forRoot = new HashSet<String>();
boolean isFirst = true;
for (VirtualFile root : roots) {
forRoot.clear();
Branch.listAsStrings(myProject, root, !local, local, forRoot, null);
if (isFirst) {
isFirst = false;
all.addAll(forRoot);
}
else {
all.retainAll(forRoot);
}
}
ArrayList<String> rc = new ArrayList<String>(all);
Collections.sort(rc);
return rc;
}
/**
* @return the used vcs
*/
Vcs getVcs() {
return myVcs;
}
/**
* @return the context project
*/
Project getProject() {
return myProject;
}
/**
* @return the current configuration
* @throws VcsException if there is a problem with configurations
*/
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration getCurrentConfiguration() throws VcsException {
synchronized (myStateLock) {
if (myCurrentConfiguration == null) {
throw new VcsException("The current configuration is not yet detected");
}
return myCurrentConfiguration;
}
}
/**
* @return the configuration names
*/
Set<String> getConfigurationNames() {
synchronized (myStateLock) {
return new HashSet<String>(myConfigurations.keySet());
}
}
/**
* Create new branch configuration
*
* @param name the configuration name
* @return the created configuration
*/
@NotNull
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration createConfiguration(String name) {
synchronized (myStateLock) {
if (myConfigurations.containsKey(name)) {
throw new IllegalStateException("The name " + name + " is already used");
}
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration c = new org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration(this, name);
myConfigurations.put(name, c);
fireConfigurationsChanged();
return c;
}
}
/**
* Find configuration by name
*
* @param name the name to use
* @return the configuration by name
* @throws VcsException if there is an error in the state
*/
@Nullable
org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration getConfiguration(String name) throws VcsException {
synchronized (myStateLock) {
return myConfigurations.get(name);
}
}
/**
* @return the state lock for branch configurations
*/
Object getStateLock() {
return myStateLock;
}
/**
* Set current configuration
*
* @param newConfiguration the new current configuration
*/
void setCurrentConfiguration(org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration newConfiguration) {
synchronized (myStateLock) {
assert myConfigurations.get(newConfiguration.getName()) == newConfiguration;
myCurrentConfiguration = newConfiguration;
fireCurrentConfigurationChanged();
}
}
/**
* @return the shelve manager from project
*/
ShelveChangesManager getShelveManager() {
return myShelveManager;
}
/**
* Remove configuration
*
* @param toRemove the removed configuration
*/
public void removeConfiguration(@NotNull org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration toRemove) {
synchronized (myStateLock) {
if (toRemove == myCurrentConfiguration) {
throw new IllegalArgumentException("Unable to remove the current configuration");
}
myConfigurations.remove(toRemove.getName());
fireConfigurationsChanged();
}
}
/**
* Start checkout process for selected configuration in the background
*
* @param configuration the selected configuration or null if new configuration is needed.
* @param remote the remote pseudo configuration name
* @param quick the quick checkout
*/
public void startCheckout(final org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration configuration, final String remote, final boolean quick) {
if (remote != null && configuration != null) {
throw new IllegalArgumentException("Either remote or configuration to checkout must be null");
}
synchronized (myStateLock) {
final SpecialStatus status = calculateSpecialStatus();
if (status != SpecialStatus.NORMAL) {
throw new IllegalStateException("Checkout cannot be started due to special status (it must have been checked in UI): " + status);
}
myCheckoutIsInProgress = true;
updateSpecialStatus();
}
final String name = configuration != null ? configuration.getName() : remote == null ? "new configuration" : remote;
final String title = "Checking out " + name;
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, title, false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
final CheckoutProcess process =
new CheckoutProcess(BranchConfigurations.this, myProject, myShelveManager, myDirtyScopeManager, myChangeManager,
myProjectManager, indicator, configuration, remote, quick);
process.run();
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
final List<VcsException> exceptions = process.getExceptions();
String op = (process.isModify() ? "Modification" : "Checkout") + " of " + name;
if (!exceptions.isEmpty()) {
UiUtil.showTabErrors(myProject, title, exceptions);
ToolWindowManager.getInstance(myProject).notifyByBalloon(
ChangesViewContentManager.TOOLWINDOW_ID, MessageType.ERROR, op + " failed.");
}
else if (process.isCancelled()) {
ToolWindowManager.getInstance(myProject).notifyByBalloon(
ChangesViewContentManager.TOOLWINDOW_ID, MessageType.WARNING, op + " was cancelled by user.");
}
else {
ToolWindowManager.getInstance(myProject).notifyByBalloon(
ChangesViewContentManager.TOOLWINDOW_ID, MessageType.INFO, op + " complete.");
}
}
});
}
catch (Throwable t) {
LOG.error("Unexpected exception from checkout: ", t);
}
finally {
synchronized (myStateLock) {
myCheckoutIsInProgress = false;
updateSpecialStatus();
}
}
}
});
}
/**
* Internal notification about renamed configuration
*
* @param toRename configuration to rename
* @param oldName the old name
* @param newName the new name @return true if configuration actually renamed.
*/
boolean configurationRenamed(org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration toRename, String oldName, String newName) {
synchronized (myStateLock) {
final org.community.intellij.plugins.communitycase.checkout.branches.BranchConfiguration c = myConfigurations.get(oldName);
if (c == toRename) {
myConfigurations.remove(oldName);
myConfigurations.put(newName, c);
}
return c == toRename;
}
}
/**
* The configuration state
*/
public static class State {
/**
* If true, branches widget is enabled
*/
public boolean IS_WIDGET_ENABLED = true;
/**
* The current configuration
*/
public String CURRENT;
/**
* The branch configuration
*/
public BranchConfiguration[] CONFIGURATIONS = new BranchConfiguration[0];
}
/**
* The branch configuration
*/
public static class BranchConfiguration {
/**
* If true, the configuration was auto-detected
*/
public boolean IS_AUTO_DETECTED;
/**
* The configuration name
*/
public String NAME;
/**
* The branch information
*/
public BranchInfo[] BRANCHES = new BranchInfo[0];
/**
* The branch changes
*/
public BranchChanges CHANGES;
}
/**
* Branch mapping information
*/
public static class BranchInfo {
/**
* The vcs root for which information is stored
*/
public String ROOT;
/**
* The local branch or specific commit
*/
public String REFERENCE;
}
/**
* The changes associated with the branch state
*/
public static class BranchChanges {
/**
* The path to shelve that keeps changes
*/
public String SHELVE_PATH;
/**
* Change list information
*/
public ChangeListInfo[] CHANGE_LISTS = new ChangeListInfo[0];
/**
* Information about distribution of changes among change lists
*/
public ChangeInfo[] CHANGES = new ChangeInfo[0];
}
/**
* The change list information
*/
public static class ChangeListInfo {
/**
* If true, the change list was a default change list
*/
public boolean IS_DEFAULT = false;
/**
* The change list name
*/
public String NAME;
/**
* The change list comment
*/
public String COMMENT;
}
/**
* Change information. The change is identified by before path and after path (for deleted)
*/
public static class ChangeInfo {
/**
* The before path
*/
public String BEFORE_PATH;
/**
* The after path
*/
public String AFTER_PATH;
/**
* The name of change list to which change belong
*/
public String CHANGE_LIST_NAME;
}
/**
* The special status for the roots
*/
public enum SpecialStatus {
/**
* Normal work tree, checkout is possible
*/
NORMAL,
/**
* Rebasing
*/
REBASING,
/**
* Merging
*/
MERGING,
/**
* Non project
*/
NON_,
/**
* The background checkout process is in progress
*/
CHECKOUT_IN_PROGRESS
}
}