2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.vcs
.changes
;
18 import com
.intellij
.lifecycle
.AtomicSectionsAware
;
19 import com
.intellij
.openapi
.Disposable
;
20 import com
.intellij
.openapi
.components
.ServiceManager
;
21 import com
.intellij
.openapi
.diagnostic
.Logger
;
22 import com
.intellij
.openapi
.project
.Project
;
23 import com
.intellij
.openapi
.util
.Disposer
;
24 import com
.intellij
.openapi
.util
.Pair
;
25 import com
.intellij
.openapi
.vcs
.*;
26 import com
.intellij
.openapi
.vcs
.changes
.ui
.RemoteStatusChangeNodeDecorator
;
27 import com
.intellij
.openapi
.vcs
.impl
.ProjectLevelVcsManagerImpl
;
28 import com
.intellij
.openapi
.vcs
.impl
.VcsInitObject
;
29 import com
.intellij
.openapi
.vcs
.update
.UpdateFilesHelper
;
30 import com
.intellij
.openapi
.vcs
.update
.UpdatedFiles
;
31 import com
.intellij
.util
.Consumer
;
32 import com
.intellij
.util
.messages
.Topic
;
34 import java
.util
.Collection
;
35 import java
.util
.HashMap
;
36 import java
.util
.LinkedList
;
39 public class RemoteRevisionsCache
implements PlusMinus
<Pair
<String
, AbstractVcs
>>, VcsListener
{
40 private static final Logger LOG
= Logger
.getInstance("#com.intellij.openapi.vcs.changes.RemoteRevisionsCache");
42 public static Topic
<Runnable
> REMOTE_VERSION_CHANGED
= new Topic
<Runnable
>("REMOTE_VERSION_CHANGED", Runnable
.class);
44 private final RemoteRevisionsNumbersCache myRemoteRevisionsNumbersCache
;
45 private final RemoteRevisionsStateCache myRemoteRevisionsStateCache
;
47 private final ProjectLevelVcsManager myVcsManager
;
49 private final RemoteStatusChangeNodeDecorator myChangeDecorator
;
50 private final Project myProject
;
51 private final Object myLock
;
52 private final Map
<String
, RemoteDifferenceStrategy
> myKinds
;
53 private ControlledCycle myControlledCycle
;
55 public static RemoteRevisionsCache
getInstance(final Project project
) {
56 return ServiceManager
.getService(project
, RemoteRevisionsCache
.class);
59 private RemoteRevisionsCache(final Project project
) {
61 myLock
= new Object();
63 myRemoteRevisionsNumbersCache
= new RemoteRevisionsNumbersCache(myProject
);
64 myRemoteRevisionsStateCache
= new RemoteRevisionsStateCache(myProject
);
66 myChangeDecorator
= new RemoteStatusChangeNodeDecorator(this);
68 myVcsManager
= ProjectLevelVcsManager
.getInstance(project
);
69 myVcsManager
.addVcsListener(this);
70 myKinds
= new HashMap
<String
, RemoteDifferenceStrategy
>();
71 Disposer
.register(project
, new Disposable() {
72 public void dispose() {
73 myVcsManager
.removeVcsListener(RemoteRevisionsCache
.this);
77 myControlledCycle
= new ControlledCycle(project
, new ControlledCycle
.MyCallback() {
78 public boolean call(final AtomicSectionsAware atomicSectionsAware
) {
79 atomicSectionsAware
.checkShouldExit();
80 final boolean shouldBeDone
= VcsConfiguration
.getInstance(myProject
).CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND
;
82 boolean somethingChanged
= myRemoteRevisionsNumbersCache
.updateStep(atomicSectionsAware
);
83 atomicSectionsAware
.checkShouldExit();
84 somethingChanged
|= myRemoteRevisionsStateCache
.updateStep(atomicSectionsAware
);
85 if (somethingChanged
) {
86 myProject
.getMessageBus().syncPublisher(REMOTE_VERSION_CHANGED
).run();
91 }, "Finishing \"changed on server\" update", 3 * 60 * 1000);
92 if ((! myProject
.isDefault()) && VcsConfiguration
.getInstance(myProject
).CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND
) {
93 ((ProjectLevelVcsManagerImpl
) myVcsManager
).addInitializationRequest(VcsInitObject
.REMOTE_REVISIONS_CACHE
,
96 myControlledCycle
.start();
102 public void startRefreshInBackground() {
103 if (myProject
.isDefault()) return;
104 myControlledCycle
.start();
107 private void updateKinds() {
108 final VcsRoot
[] roots
= myVcsManager
.getAllVcsRoots();
109 synchronized (myLock
) {
110 for (VcsRoot root
: roots
) {
111 final AbstractVcs vcs
= root
.vcs
;
112 if (! myKinds
.containsKey(vcs
.getName())) {
113 myKinds
.put(vcs
.getName(), vcs
.getRemoteDifferenceStrategy());
119 public void directoryMappingChanged() {
121 myRemoteRevisionsNumbersCache
.directoryMappingChanged();
122 myRemoteRevisionsStateCache
.directoryMappingChanged();
125 public void plus(final Pair
<String
, AbstractVcs
> pair
) {
126 final AbstractVcs vcs
= pair
.getSecond();
127 if (RemoteDifferenceStrategy
.ASK_TREE_PROVIDER
.equals(vcs
.getRemoteDifferenceStrategy())) {
128 myRemoteRevisionsStateCache
.plus(pair
);
130 myRemoteRevisionsNumbersCache
.plus(pair
);
134 public void invalidate(final UpdatedFiles updatedFiles
) {
135 final Map
<String
, RemoteDifferenceStrategy
> strategyMap
;
136 synchronized (myLock
) {
137 strategyMap
= new HashMap
<String
, RemoteDifferenceStrategy
>(myKinds
);
139 final Collection
<String
> newForTree
= new LinkedList
<String
>();
140 final Collection
<String
> newForUsual
= new LinkedList
<String
>();
141 UpdateFilesHelper
.iterateAffectedFiles(updatedFiles
, new Consumer
<Pair
<String
, String
>>() {
142 public void consume(final Pair
<String
, String
> pair
) {
143 final String vcsName
= pair
.getSecond();
144 RemoteDifferenceStrategy strategy
= strategyMap
.get(vcsName
);
145 if (strategy
== null) {
146 final AbstractVcs vcs
= myVcsManager
.findVcsByName(vcsName
);
147 if (vcs
== null) return;
148 strategy
= vcs
.getRemoteDifferenceStrategy();
150 if (RemoteDifferenceStrategy
.ASK_TREE_PROVIDER
.equals(strategy
)) {
151 newForTree
.add(pair
.getFirst());
153 newForUsual
.add(pair
.getFirst());
158 myRemoteRevisionsStateCache
.invalidate(newForTree
);
159 myRemoteRevisionsNumbersCache
.invalidate(newForUsual
);
162 public void minus(Pair
<String
, AbstractVcs
> pair
) {
163 final AbstractVcs vcs
= pair
.getSecond();
164 if (RemoteDifferenceStrategy
.ASK_TREE_PROVIDER
.equals(vcs
.getRemoteDifferenceStrategy())) {
165 myRemoteRevisionsStateCache
.minus(pair
);
167 myRemoteRevisionsNumbersCache
.minus(pair
);
172 * @return false if not up to date
174 public boolean isUpToDate(final Change change
) {
175 final AbstractVcs vcs
= ChangesUtil
.getVcsForChange(change
, myProject
);
176 if (vcs
== null) return true;
177 final RemoteDifferenceStrategy strategy
= vcs
.getRemoteDifferenceStrategy();
178 if (RemoteDifferenceStrategy
.ASK_TREE_PROVIDER
.equals(strategy
)) {
179 return myRemoteRevisionsStateCache
.isUpToDate(change
);
181 return myRemoteRevisionsNumbersCache
.isUpToDate(change
);
185 public RemoteStatusChangeNodeDecorator
getChangesNodeDecorator() {
186 return myChangeDecorator
;