diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcs.java b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcs.java index 5e735f8dd554..04fdc34cef2a 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcs.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcs.java @@ -543,5 +543,9 @@ public abstract class AbstractVcs extends S if (myRollbackEnvironment != null) throw new IllegalStateException("Attempt to redefine rollback environment"); myRollbackEnvironment = rollbackEnvironment; } + + public boolean reportsIgnoredDirectories() { + return true; + } } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/AreaMap.java b/platform/vcs-api/src/com/intellij/openapi/vcs/AreaMap.java index 9e597cb65def..47bd960c272b 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/AreaMap.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/AreaMap.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs; +import com.intellij.util.Consumer; import com.intellij.util.PairProcessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,6 +56,37 @@ public class AreaMap { putImpl(key, val); } + protected int putIfNoParent(final Key key, final Val val) { + if(myMap.put(key, val) != null) { + return -1; + } + + if (myKeys.isEmpty()) { + myKeys.add(key); + return 0; + } + + final int idx = Collections.binarySearch(myKeys, key, myComparator); + if (idx < 0) { + // insertion, no copy exist + final int insertionIdx = - idx - 1; + // check parent + for (final ListIterator listIterator = myKeys.listIterator(insertionIdx); listIterator.hasPrevious();) { + final Key previous = listIterator.previous(); + if (myKeysResemblance.process(previous, key)) { + myMap.remove(key); + return -1; + } + } + // insertionIdx not necessarily exist + myKeys.add(insertionIdx, key); + return insertionIdx; + } + assert true; + myMap.remove(key); + return -1; + } + protected int putImpl(final Key key, final Val val) { myMap.put(key, val); @@ -115,8 +147,8 @@ public class AreaMap { // take item before final int itemBeforeIdx = insertionIdx - 1; if (itemBeforeIdx >= 0) { - for (int i = itemBeforeIdx; i >= 0; -- i) { - final Key candidate = myKeys.get(i); + for (ListIterator iterator = myKeys.listIterator(itemBeforeIdx + 1); iterator.hasPrevious(); ) { + final Key candidate = iterator.previous(); if (! myKeysResemblance.process(candidate, key)) continue; if (consumer.process(candidate, myMap.get(candidate))) break; // if need only a part of keys } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/MembershipMap.java b/platform/vcs-api/src/com/intellij/openapi/vcs/MembershipMap.java index 7ddc38a865be..bedfd95930a7 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/MembershipMap.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/MembershipMap.java @@ -38,28 +38,20 @@ public class MembershipMap extends AreaMap { } public void putOptimal(final Key key, final Val val) { - final int idx = putImpl(key, val); + final int idx = putIfNoParent(key, val); + if (idx < 0) return; - // go for parents - for (int i = idx - 1; i >= 0; -- i) { - if (myKeysResemblance.process(myKeys.get(i), key)) { - consistentRemove(idx); - return; + if (idx + 1 < myKeys.size()) { + for (final ListIterator listIterator = myKeys.listIterator(idx + 1); listIterator.hasNext();) { + final Key next = listIterator.next(); + if (myKeysResemblance.process(key, next)) { + listIterator.remove(); + myMap.remove(next); + } else { + break; + } } } - for (int i = idx + 1; i < myKeys.size(); ++ i) { - if (myKeysResemblance.process(key, myKeys.get(i))) { - consistentRemove(i); - -- i; - } else { - break; - } - } - } - - private void consistentRemove(final int idx) { - final Key keyToRemove = myKeys.remove(idx); - myMap.remove(keyToRemove); } public void optimizeMap(final PairProcessor valuesAreas) { @@ -96,4 +88,4 @@ public class MembershipMap extends AreaMap { }); return result.get(); } -} \ No newline at end of file +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/AbstractIgnoredFilesHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/AbstractIgnoredFilesHolder.java new file mode 100644 index 000000000000..4a8e5942f060 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/AbstractIgnoredFilesHolder.java @@ -0,0 +1,70 @@ +/* + * 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 com.intellij.openapi.vcs.changes; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.FilePathImpl; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vfs.VirtualFile; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * @author irengrig + * Date: 2/10/11 + * Time: 3:59 PM + */ +abstract class AbstractIgnoredFilesHolder implements FileHolder, IgnoredFilesHolder { + protected final Project myProject; + private final ProjectLevelVcsManager myVcsManager; + + protected AbstractIgnoredFilesHolder(Project project) { + myProject = project; + myVcsManager = ProjectLevelVcsManager.getInstance(project); + } + + protected abstract void removeFile(final VirtualFile file); + protected abstract Collection keys(); + + @Override + public void cleanAndAdjustScope(final VcsModifiableDirtyScope scope) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (myProject.isDisposed()) return; + + final Iterator iterator = keys().iterator(); + while (iterator.hasNext()) { + final VirtualFile file = iterator.next(); + if (isFileDirty(scope, file)) { + iterator.remove(); + } + } + } + }); + } + + protected boolean isFileDirty(final VcsDirtyScope scope, final VirtualFile file) { + return fileDropped(file) || scope.belongsTo(new FilePathImpl(file)); + } + + protected boolean fileDropped(final VirtualFile file) { + return !file.isValid() || myVcsManager.getVcsFor(file) == null; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index f81f94dcba9d..aa235e73e29f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -295,7 +295,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec private void filterOutIgnoredFiles(final List scopes) { try { synchronized (myDataLock) { - final RecursiveFileHolder fileHolder = (RecursiveFileHolder)myComposite.get(FileHolder.HolderType.IGNORED); + final IgnoredFilesHolder fileHolder = (IgnoredFilesHolder)myComposite.get(FileHolder.HolderType.IGNORED); for (Iterator iterator = scopes.iterator(); iterator.hasNext();) { final VcsModifiableDirtyScope scope = (VcsModifiableDirtyScope) iterator.next(); @@ -337,8 +337,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } private void updateImmediately(final AtomicSectionsAware atomicSectionsAware) { - final FileHolderComposite composite; - final ChangeListWorker changeListWorker; + final DataHolder dataHolder; final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); if (! vcsManager.hasActiveVcss()) return; @@ -371,43 +370,26 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec // mark for "modifier" that update started (it would create duplicates of modification commands done by user during update; // after update of copies of objects is complete, it would apply the same modifications to copies.) synchronized (myDataLock) { - changeListWorker = myWorker.copy(); - composite = (FileHolderComposite) myComposite.copy(); + dataHolder = new DataHolder((FileHolderComposite) myComposite.copy(), myWorker.copy(), wasEverythingDirty); myModifier.enterUpdate(); if (wasEverythingDirty) { myUpdateException = null; - composite.cleanAll(); } if (LOG.isDebugEnabled()) { LOG.debug("refresh procedure started, everything = " + wasEverythingDirty); } } - if (wasEverythingDirty) { - changeListWorker.notifyStartProcessingChanges(null); - } + dataHolder.notifyStart(); myChangesViewManager.scheduleRefresh(); - final ChangeListManagerGate gate = changeListWorker.createSelfGate(); - + final ChangeListManagerGate gate = dataHolder.getChangeListWorker().createSelfGate(); // do actual requests about file statuses - final UpdatingChangeListBuilder builder = new UpdatingChangeListBuilder(changeListWorker, composite, new Getter() { - public Boolean get() { - return myUpdater.isStopped(); - } - }, myIgnoredIdeaLevel, gate); + final UpdatingChangeListBuilder builder = new UpdatingChangeListBuilder(dataHolder.getChangeListWorker(), + dataHolder.getComposite(), myUpdater.getIsStoppedGetter(), myIgnoredIdeaLevel, gate); // todo should also ask self flag - myUpdateChangesProgressIndicator = new EmptyProgressIndicator() { - @Override - public boolean isCanceled() { - return myUpdater.isStopped() || atomicSectionsAware.shouldExitAsap(); - } - @Override - public void checkCanceled() { - checkIfDisposed(); - atomicSectionsAware.checkShouldExit(); - } - }; + myUpdateChangesProgressIndicator = createProgressIndicator(atomicSectionsAware); + for (final VcsDirtyScope scope : scopes) { atomicSectionsAware.checkShouldExit(); @@ -416,18 +398,9 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec final VcsModifiableDirtyScope adjustedScope = vcs.adjustDirtyScope((VcsModifiableDirtyScope) scope); myChangesViewManager.updateProgressText(VcsBundle.message("changes.update.progress.message", vcs.getDisplayName()), false); - if (! wasEverythingDirty) { - composite.cleanAndAdjustScope(adjustedScope); - changeListWorker.notifyStartProcessingChanges(adjustedScope); - } + dataHolder.notifyStartProcessingChanges(adjustedScope); - try { - actualUpdate(wasEverythingDirty, composite, builder, adjustedScope, vcs, changeListWorker, gate); - } - catch (Throwable t) { - LOG.debug(t); - Rethrow.reThrowRuntime(t); - } + actualUpdate(builder, adjustedScope, vcs, dataHolder, gate); if (myUpdateException != null) break; } @@ -435,29 +408,27 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec final boolean takeChanges = (myUpdateException == null); if (takeChanges) { // update IDEA-level ignored files - updateIgnoredFiles(composite); + updateIgnoredFiles(dataHolder.getComposite()); } synchronized (myDataLock) { // do same modifications to change lists as was done during update + do delayed notifications - if (wasEverythingDirty) { - changeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher()); - } + dataHolder.notifyEnd(); myModifier.exitUpdate(); // should be applied for notifications to be delivered (they were delayed) - myModifier.apply(changeListWorker); + myModifier.apply(dataHolder.getChangeListWorker()); myModifier.clearQueue(); // update member from copy if (takeChanges) { - myWorker.takeData(changeListWorker); + myWorker.takeData(dataHolder.getChangeListWorker()); } if (takeChanges) { if (LOG.isDebugEnabled()) { - LOG.debug("refresh procedure finished, size: " + composite.getVFHolder(FileHolder.HolderType.UNVERSIONED).getSize()); + LOG.debug("refresh procedure finished, size: " + dataHolder.getComposite().getVFHolder(FileHolder.HolderType.UNVERSIONED).getSize()); } - final boolean statusChanged = ! myComposite.equals(composite); - myComposite = composite; + final boolean statusChanged = ! myComposite.equals(dataHolder.getComposite()); + myComposite = dataHolder.getComposite(); if (statusChanged) { myDelayedNotificator.getProxyDispatcher().unchangedFileStatusChanged(); } @@ -489,9 +460,71 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } } - private void actualUpdate(final boolean wasEverythingDirty, final FileHolderComposite composite, final UpdatingChangeListBuilder builder, - final VcsDirtyScope scope, final AbstractVcs vcs, final ChangeListWorker changeListWorker, - final ChangeListManagerGate gate) { + private EmptyProgressIndicator createProgressIndicator(final AtomicSectionsAware atomicSectionsAware) { + return new EmptyProgressIndicator() { + @Override + public boolean isCanceled() { + return myUpdater.isStopped() || atomicSectionsAware.shouldExitAsap(); + } + @Override + public void checkCanceled() { + checkIfDisposed(); + atomicSectionsAware.checkShouldExit(); + } + }; + } + + private class DataHolder { + private final boolean myWasEverythingDirty; + final FileHolderComposite myComposite; + final ChangeListWorker myChangeListWorker; + + private DataHolder(FileHolderComposite composite, ChangeListWorker changeListWorker, boolean wasEverythingDirty) { + myComposite = composite; + myChangeListWorker = changeListWorker; + myWasEverythingDirty = wasEverythingDirty; + } + + public void notifyStart() { + if (myWasEverythingDirty) { + myComposite.cleanAll(); + myChangeListWorker.notifyStartProcessingChanges(null); + } + } + + public void notifyStartProcessingChanges(@NotNull final VcsModifiableDirtyScope scope) { + if (! myWasEverythingDirty) { + myComposite.cleanAndAdjustScope(scope); + myChangeListWorker.notifyStartProcessingChanges(scope); + } + + myComposite.notifyVcsStarted(scope.getVcs()); + myChangeListWorker.notifyVcsStarted(scope.getVcs()); + } + + public void notifyDoneProcessingChanges() { + if (! myWasEverythingDirty) { + myChangeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher()); + } + } + + public void notifyEnd() { + if (myWasEverythingDirty) { + myChangeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher()); + } + } + + public FileHolderComposite getComposite() { + return myComposite; + } + + public ChangeListWorker getChangeListWorker() { + return myChangeListWorker; + } + } + + private void actualUpdate(final UpdatingChangeListBuilder builder, final VcsDirtyScope scope, final AbstractVcs vcs, + final DataHolder dataHolder, final ChangeListManagerGate gate) { try { final ChangeProvider changeProvider = vcs.getChangeProvider(); if (changeProvider != null) { @@ -507,10 +540,12 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } } } - } - finally { - if ((! myUpdater.isStopped()) && !wasEverythingDirty) { - changeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher()); + } catch (Throwable t) { + LOG.debug(t); + Rethrow.reThrowRuntime(t); + } finally { + if (! myUpdater.isStopped()) { + dataHolder.notifyDoneProcessingChanges(); } } } @@ -1035,7 +1070,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec synchronized (myDataLock) { final VirtualFileHolder unversionedHolder = myComposite.getVFHolder(FileHolder.HolderType.UNVERSIONED); - final RecursiveFileHolder ignoredHolder = (RecursiveFileHolder) myComposite.get(FileHolder.HolderType.IGNORED); + final IgnoredFilesHolder ignoredHolder = (IgnoredFilesHolder) myComposite.get(FileHolder.HolderType.IGNORED); scheduler.accept(unversionedHolder.getFiles()); scheduler.accept(ignoredHolder.values()); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java index 1d6e08c8209e..54a235057b27 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java @@ -531,6 +531,11 @@ public class ChangeListWorker implements ChangeListsWriteOperations { return myLocallyDeleted.isContainedInLocallyDeleted(filePath); } + public void notifyVcsStarted(AbstractVcs vcs) { + myLocallyDeleted.notifyVcsStarted(vcs); + mySwitchedHolder.notifyVcsStarted(vcs); + } + private abstract class ExternalVsInternalChangesIntersection { protected final Collection myInChanges; protected final Map, LocalChangeList> myInternalMap; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DeletedFilesHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DeletedFilesHolder.java index 45e3bb13ea2c..d36b57d60ce3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DeletedFilesHolder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/DeletedFilesHolder.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.changes; +import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import java.util.ArrayList; @@ -53,6 +54,10 @@ public class DeletedFilesHolder implements FileHolder { return HolderType.DELETED; } + @Override + public void notifyVcsStarted(AbstractVcs scope) { + } + public void addFile(final LocallyDeletedChange change) { myFiles.put(change.getPresentableUrl(), change); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolder.java index 062cc5e05596..8e5798798668 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolder.java @@ -15,12 +15,16 @@ */ package com.intellij.openapi.vcs.changes; +import com.intellij.openapi.vcs.AbstractVcs; + interface FileHolder { void cleanAll(); void cleanAndAdjustScope(VcsModifiableDirtyScope scope); FileHolder copy(); HolderType getType(); + void notifyVcsStarted(AbstractVcs scope); + static enum HolderType { DELETED, UNVERSIONED, diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolderComposite.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolderComposite.java index 10218a6cd67d..b26193a8298d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolderComposite.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FileHolderComposite.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcs; import org.jetbrains.annotations.NotNull; import java.util.HashMap; @@ -29,7 +30,7 @@ public class FileHolderComposite implements FileHolder { myHolders.put(FileHolder.HolderType.UNVERSIONED, new VirtualFileHolder(project, FileHolder.HolderType.UNVERSIONED)); myHolders.put(FileHolder.HolderType.ROOT_SWITCH, new SwitchedFileHolder(project, HolderType.ROOT_SWITCH)); myHolders.put(FileHolder.HolderType.MODIFIED_WITHOUT_EDITING, new VirtualFileHolder(project, FileHolder.HolderType.MODIFIED_WITHOUT_EDITING)); - myHolders.put(FileHolder.HolderType.IGNORED, new RecursiveFileHolder(project, FileHolder.HolderType.IGNORED)); + myHolders.put(FileHolder.HolderType.IGNORED, new IgnoredFilesCompositeHolder(project)); myHolders.put(FileHolder.HolderType.LOCKED, new VirtualFileHolder(project, FileHolder.HolderType.LOCKED)); myHolders.put(FileHolder.HolderType.LOGICALLY_LOCKED, new LogicallyLockedHolder(project)); } @@ -99,7 +100,13 @@ public class FileHolderComposite implements FileHolder { throw new UnsupportedOperationException(); } - public RecursiveFileHolder getIgnoredFileHolder() { - return (RecursiveFileHolder) myHolders.get(HolderType.IGNORED); + public IgnoredFilesHolder getIgnoredFileHolder() { + return (IgnoredFilesHolder) myHolders.get(HolderType.IGNORED); + } + + public void notifyVcsStarted(AbstractVcs vcs) { + for (FileHolder fileHolder : myHolders.values()) { + fileHolder.notifyVcsStarted(vcs); + } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesCompositeHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesCompositeHolder.java new file mode 100644 index 000000000000..1634c61237c6 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesCompositeHolder.java @@ -0,0 +1,99 @@ +/* + * 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 com.intellij.openapi.vcs.changes; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vfs.VirtualFile; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/** + * @author irengrig + * Date: 2/10/11 + * Time: 3:57 PM + */ +public class IgnoredFilesCompositeHolder implements IgnoredFilesHolder { + private final Map myHolderMap; + private final Project myProject; + private AbstractVcs myCurrentVcs; + private final ProjectLevelVcsManager myVcsManager; + + public IgnoredFilesCompositeHolder(final Project project) { + super(); + myProject = project; + myHolderMap = new HashMap(); + myVcsManager = ProjectLevelVcsManager.getInstance(myProject); + } + + @Override + public void cleanAll() { + myHolderMap.clear(); + } + + @Override + public void cleanAndAdjustScope(VcsModifiableDirtyScope scope) { + myHolderMap.get(scope.getVcs()).cleanAndAdjustScope(scope); + } + + @Override + public FileHolder copy() { + final IgnoredFilesCompositeHolder result = new IgnoredFilesCompositeHolder(myProject); + result.myHolderMap.putAll(new HashMap(myHolderMap)); + return result; + } + + @Override + public HolderType getType() { + return HolderType.IGNORED; + } + + @Override + public void addFile(VirtualFile file) { + myHolderMap.get(myCurrentVcs).addFile(file); + } + + @Override + public boolean containsFile(VirtualFile file) { + final AbstractVcs vcs = myVcsManager.getVcsFor(file); + if (vcs == null) return false; + final IgnoredFilesHolder ignoredFilesHolder = myHolderMap.get(vcs); + return ignoredFilesHolder == null ? false : ignoredFilesHolder.containsFile(file); + } + + @Override + public Collection values() { + if (myHolderMap.size() == 1) return myHolderMap.values().iterator().next().values(); + final HashSet result = new HashSet(); + for (IgnoredFilesHolder holder : myHolderMap.values()) { + result.addAll(holder.values()); + } + return result; + } + + @Override + public void notifyVcsStarted(AbstractVcs vcs) { + myCurrentVcs = vcs; + if (! myHolderMap.containsKey(vcs)) { + myHolderMap.put(vcs, vcs.reportsIgnoredDirectories() ? (IgnoredFilesHolder) new RecursiveFileHolder(myProject, HolderType.IGNORED) : + new MapIgnoredFilesHolder(myProject)); + } + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesHolder.java new file mode 100644 index 000000000000..f48355c49ddc --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesHolder.java @@ -0,0 +1,32 @@ +/* + * 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 com.intellij.openapi.vcs.changes; + +import com.intellij.openapi.vfs.VirtualFile; + +import java.util.Collection; + +/** + * @author irengrig + * Date: 2/10/11 + * Time: 4:54 PM + */ +public interface IgnoredFilesHolder extends FileHolder { + void addFile(VirtualFile file); + boolean containsFile(VirtualFile file); + Collection values(); + void cleanAndAdjustScope(VcsModifiableDirtyScope scope); +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LogicallyLockedHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LogicallyLockedHolder.java index ca74613ff9a0..131530fda147 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LogicallyLockedHolder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LogicallyLockedHolder.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vfs.VirtualFile; import java.util.Collections; @@ -53,6 +54,10 @@ public class LogicallyLockedHolder implements FileHolder { return HolderType.LOGICALLY_LOCKED; } + @Override + public void notifyVcsStarted(AbstractVcs vcs) { + } + public boolean containsKey(final VirtualFile vf) { return myMap.containsKey(vf); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/MapIgnoredFilesHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/MapIgnoredFilesHolder.java new file mode 100644 index 000000000000..8f98eda3eb9c --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/MapIgnoredFilesHolder.java @@ -0,0 +1,90 @@ +/* + * 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 com.intellij.openapi.vcs.changes; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.hash.HashSet; + +import java.util.Collection; +import java.util.Set; + +/** + * @author irengrig + * Date: 2/10/11 + * Time: 4:20 PM + */ +public class MapIgnoredFilesHolder extends AbstractIgnoredFilesHolder { + private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.MapIgnoredFilesHolder"); + + private final Set mySet; + private final Project myProject; + + public MapIgnoredFilesHolder(Project project) { + super(project); + myProject = project; + mySet = new HashSet(); + } + + @Override + protected void removeFile(VirtualFile file) { + mySet.remove(file); + } + + @Override + protected Collection keys() { + return mySet; + } + + @Override + public void addFile(VirtualFile file) { + LOG.assertTrue(! file.isDirectory()); + mySet.add(file); + } + + @Override + public boolean containsFile(VirtualFile file) { + return mySet.contains(file); + } + + @Override + public Collection values() { + return mySet; + } + + @Override + public void cleanAll() { + mySet.clear(); + } + + @Override + public FileHolder copy() { + final MapIgnoredFilesHolder result = new MapIgnoredFilesHolder(myProject); + result.mySet.addAll(mySet); + return result; + } + + @Override + public HolderType getType() { + return HolderType.IGNORED; + } + + @Override + public void notifyVcsStarted(AbstractVcs scope) { + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RecursiveFileHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RecursiveFileHolder.java index 7b9f78b20fed..fc56b138208e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RecursiveFileHolder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RecursiveFileHolder.java @@ -7,6 +7,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diff.impl.patch.formove.FilePathComparator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.MembershipMap; import com.intellij.openapi.vcs.ProjectLevelVcsManager; @@ -14,84 +15,67 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PairProcessor; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; /** * @author max */ -public class RecursiveFileHolder implements FileHolder { +public class RecursiveFileHolder extends AbstractIgnoredFilesHolder { protected final HolderType myHolderType; - protected final MembershipMap myMap; - - protected final Project myProject; + protected final TreeMap myMap; public RecursiveFileHolder(final Project project, final HolderType holderType) { - myMap = MembershipMap.createMembershipMap(new PairProcessor() { - @Override - public boolean process(final VirtualFile parent, final VirtualFile child) { - return VfsUtil.isAncestor(parent, child, false); - } - }, FilePathComparator.getInstance()); - - myProject = project; + super(project); + myMap = new TreeMap(FilePathComparator.getInstance()); myHolderType = holderType; } - public synchronized void cleanAll() { + public void cleanAll() { myMap.clear(); } - public void cleanAndAdjustScope(final VcsModifiableDirtyScope scope) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - // to avoid deadlocks caused by incorrect lock ordering, need to lock on this after taking read action - synchronized(RecursiveFileHolder.this) { - if (myProject.isDisposed()) return; - - final List currentFiles = new ArrayList(myMap.keySet()); - for (final VirtualFile file : currentFiles) { - if (isFileDirty(scope, file)) { - myMap.remove(file); - } - } - } - } - }); + @Override + protected Collection keys() { + return myMap.keySet(); } - protected boolean isFileDirty(final VcsDirtyScope scope, final VirtualFile file) { - return fileDropped(file) || scope.belongsTo(new FilePathImpl(file)); + @Override + public void notifyVcsStarted(AbstractVcs scope) { } public HolderType getType() { return myHolderType; } - protected boolean fileDropped(final VirtualFile file) { - return !file.isValid() || ProjectLevelVcsManager.getInstance(myProject).getVcsFor(file) == null; + public void addFile(final VirtualFile file) { + if (! containsFile(file)) { + myMap.put(file, null); + } } - public synchronized void addFile(final VirtualFile file) { - myMap.putOptimal(file, null); - } - - public synchronized void removeFile(final VirtualFile file) { + public void removeFile(final VirtualFile file) { myMap.remove(file); } - public synchronized RecursiveFileHolder copy() { + public RecursiveFileHolder copy() { final RecursiveFileHolder copyHolder = new RecursiveFileHolder(myProject, myHolderType); copyHolder.myMap.putAll(myMap); return copyHolder; } - public synchronized boolean containsFile(final VirtualFile file) { - return myMap.getMapping(file) != null; + public boolean containsFile(final VirtualFile file) { + final VirtualFile floor = myMap.floorKey(file); + if (floor == null) return false; + final SortedMap floorMap = myMap.headMap(floor, true); + for (VirtualFile parent : floorMap.keySet()) { + if (VfsUtil.isAncestor(parent, file, false)) { + return true; + } + } + return false; } - public synchronized Collection values() { + public Collection values() { return myMap.keySet(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SwitchedFileHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SwitchedFileHolder.java index 7f3ba218a569..967975dd24a6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SwitchedFileHolder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/SwitchedFileHolder.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PairProcessor; import com.intellij.util.containers.MultiMap; @@ -24,6 +25,7 @@ import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.SortedMap; // true = recursively, branch name public class SwitchedFileHolder extends RecursiveFileHolder> { @@ -53,7 +55,7 @@ public class SwitchedFileHolder extends RecursiveFileHolder getFilesMapCopy() { final HashMap result = new HashMap(); for (final VirtualFile vf : myMap.keySet()) { - result.put(vf, myMap.getExact(vf).getSecond()); + result.put(vf, myMap.get(vf).getSecond()); } return result; } @@ -66,33 +68,40 @@ public class SwitchedFileHolder extends RecursiveFileHolder getBranchToFileMap() { final MultiMap result = new MultiMap(); for (final VirtualFile vf : myMap.keySet()) { - result.putValue(myMap.getExact(vf).getSecond(), vf); + result.putValue(myMap.get(vf).getSecond(), vf); } return result; } @Override public synchronized boolean containsFile(final VirtualFile file) { - final Pair> mapping = myMap.getMapping(file); - if (mapping != null) { - return mapping.getFirst().equals(file) || mapping.getSecond().getFirst(); + final VirtualFile floor = myMap.floorKey(file); + if (floor == null) return false; + final SortedMap> floorMap = myMap.headMap(floor); + for (VirtualFile parent : floorMap.keySet()) { + if (VfsUtil.isAncestor(parent, file, false)) { + final Pair value = floorMap.get(parent); + return parent.equals(file) || value.getFirst(); + } } return false; } @Nullable public String getBranchForFile(final VirtualFile file) { - final Pair> mapping = myMap.getMapping(file); - if (mapping != null) { - if (mapping.getFirst().equals(file) || mapping.getSecond().getFirst()) { - return mapping.getSecond().getSecond(); + final VirtualFile floor = myMap.floorKey(file); + if (floor == null) return null; + final SortedMap> floorMap = myMap.headMap(floor); + for (VirtualFile parent : floorMap.keySet()) { + if (VfsUtil.isAncestor(parent, file, false)) { + return floorMap.get(parent).getSecond(); } } return null; } public void calculateChildren() { - myMap.optimizeMap(MyOptimizeProcessor.getInstance()); + //myMap.optimizeMap(MyOptimizeProcessor.getInstance()); } private static class MyOptimizeProcessor implements PairProcessor, Pair> { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdateRequestsQueue.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdateRequestsQueue.java index 0113b8aa3e84..07a973ef2932 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdateRequestsQueue.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdateRequestsQueue.java @@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.SomeQueue; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; +import com.intellij.openapi.util.Getter; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.util.Consumer; import com.intellij.util.io.storage.HeavyProcessLatch; @@ -58,6 +59,7 @@ public class UpdateRequestsQueue { private final ExecutorWrapper myExecutorWrapper; @NonNls public static final String LOCAL_CHANGES_UPDATE = "Local changes update"; private final boolean myTrackHeavyLatch; + private Getter myIsStoppedGetter; public UpdateRequestsQueue(final Project project, final ScheduledExecutorService executor, final LocalChangesUpdater delegate) { myProject = project; @@ -75,6 +77,12 @@ public class UpdateRequestsQueue { // not initialized myStarted = false; myStopped = false; + myIsStoppedGetter = new Getter() { + @Override + public Boolean get() { + return isStopped(); + } + }; } public void initialized() { @@ -82,6 +90,10 @@ public class UpdateRequestsQueue { myStarted = true; } + public Getter getIsStoppedGetter() { + return myIsStoppedGetter; + } + public boolean isStopped() { return myStopped; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VirtualFileHolder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VirtualFileHolder.java index 6df9cb915dbc..64cfb59b4df5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VirtualFileHolder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VirtualFileHolder.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vfs.VirtualFile; @@ -42,6 +43,10 @@ public class VirtualFileHolder implements FileHolder { return myType; } + @Override + public void notifyVcsStarted(AbstractVcs vcs) { + } + public void cleanAll() { myFiles.clear(); myNumDirs = 0; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java index ae717723db89..6aff4dfc7c5e 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java @@ -358,4 +358,9 @@ public class HgVcs extends AbstractVcs { return myExecutableValidator; } } + + @Override + public boolean reportsIgnoredDirectories() { + return false; + } }