diff options
Diffstat (limited to 'platform/vcs-impl/src/com/intellij')
23 files changed, 604 insertions, 207 deletions
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 b9f0855c175c..5e01feada2f3 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 @@ -23,15 +23,20 @@ import com.intellij.openapi.application.RuntimeInterruptedException; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.impl.DirectoryIndexExcludePolicy; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.conflicts.ChangelistConflictTracker; @@ -43,6 +48,7 @@ import com.intellij.openapi.vcs.readOnlyHandler.ReadonlyStatusHandlerImpl; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotifications; import com.intellij.util.*; @@ -68,8 +74,10 @@ import java.util.concurrent.atomic.AtomicReference; /** * @author max */ -public class ChangeListManagerImpl extends ChangeListManagerEx implements ProjectComponent, ChangeListOwner, JDOMExternalizable, RoamingTypeDisabled { +public class ChangeListManagerImpl extends ChangeListManagerEx implements ProjectComponent, ChangeListOwner, JDOMExternalizable, + RoamingTypeDisabled { public static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.ChangeListManagerImpl"); + private static final String EXCLUDED_CONVERTED_TO_IGNORED_OPTION = "EXCLUDED_CONVERTED_TO_IGNORED"; private final Project myProject; private final VcsConfiguration myConfig; @@ -101,6 +109,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec private final List<CommitExecutor> myExecutors = new ArrayList<CommitExecutor>(); private final IgnoredFilesComponent myIgnoredIdeaLevel; + private boolean myExcludedConvertedToIgnored; private ProgressIndicator myUpdateChangesProgressIndicator; public static final Topic<LocalChangeListsLoadedListener> LISTS_LOADED = new Topic<LocalChangeListsLoadedListener>( @@ -191,6 +200,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec /** * Shows the proposal to delete one or more changelists that were default and became empty. + * * @return true if the changelists have to be deleted, false if not. */ private boolean showRemoveEmptyChangeListsProposal(@NotNull final VcsConfiguration config, @NotNull Collection<LocalChangeList> lists) { @@ -242,7 +252,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec public void unblockModalNotifications() { myModalNotificationsBlocked = false; if (myListsToBeDeleted.isEmpty()) { - return ; + return; } if (showRemoveEmptyChangeListsProposal(myConfig, myListsToBeDeleted)) { for (LocalChangeList list : myListsToBeDeleted) { @@ -261,14 +271,14 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec vcsManager.addVcsListener(myVcsListener); } else { - ((ProjectLevelVcsManagerImpl) vcsManager).addInitializationRequest( + ((ProjectLevelVcsManagerImpl)vcsManager).addInitializationRequest( VcsInitObject.CHANGE_LIST_MANAGER, new DumbAwareRunnable() { - public void run() { - myUpdater.initialized(); - broadcastStateAfterLoad(); - vcsManager.addVcsListener(myVcsListener); - } - }); + public void run() { + myUpdater.initialized(); + broadcastStateAfterLoad(); + vcsManager.addVcsListener(myVcsListener); + } + }); } myConflictTracker.startTracking(); @@ -279,7 +289,9 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec synchronized (myDataLock) { listCopy = getChangeListsCopy(); } - myProject.getMessageBus().syncPublisher(LISTS_LOADED).processLoadedLists(listCopy); + if (!myProject.isDisposed()) { + myProject.getMessageBus().syncPublisher(LISTS_LOADED).processLoadedLists(listCopy); + } } private void initializeForNewProject() { @@ -297,11 +309,29 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec myIgnoredIdeaLevel.add(IgnoredBeanFactory.ignoreFile(Project.DIRECTORY_STORE_FOLDER + "/workspace.xml", myProject)); } } + if (!Registry.is("ide.hide.excluded.files") && !myExcludedConvertedToIgnored) { + convertExcludedToIgnored(); + myExcludedConvertedToIgnored = true; + } } } }); } + void convertExcludedToIgnored() { + for (DirectoryIndexExcludePolicy policy : DirectoryIndexExcludePolicy.EP_NAME.getExtensions(myProject)) { + for (VirtualFile file : policy.getExcludeRootsForProject()) { + addDirectoryToIgnoreImplicitly(file.getPath()); + } + } + + for (Module module : ModuleManager.getInstance(myProject).getModules()) { + for (String url : ModuleRootManager.getInstance(module).getExcludeRootUrls()) { + addDirectoryToIgnoreImplicitly(VfsUtilCore.urlToPath(url)); + } + } + } + public void projectClosed() { ProjectLevelVcsManager.getInstance(myProject).removeVcsListener(myVcsListener); @@ -328,11 +358,12 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec /** * update itself might produce actions done on AWT thread (invoked-after), - * so waiting for its completion on AWT thread is not good - * - * runnable is invoked on AWT thread + * so waiting for its completion on AWT thread is not good runnable is invoked on AWT thread */ - public void invokeAfterUpdate(final Runnable afterUpdate, final InvokeAfterUpdateMode mode, @Nullable final String title, @Nullable final ModalityState state) { + public void invokeAfterUpdate(final Runnable afterUpdate, + final InvokeAfterUpdateMode mode, + @Nullable final String title, + @Nullable final ModalityState state) { myUpdater.invokeAfterUpdate(afterUpdate, mode, title, null, state); } @@ -394,13 +425,13 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec synchronized (myDataLock) { final IgnoredFilesHolder fileHolder = (IgnoredFilesHolder)myComposite.get(FileHolder.HolderType.IGNORED); - for (Iterator<VcsDirtyScope> iterator = scopes.iterator(); iterator.hasNext();) { - final VcsModifiableDirtyScope scope = (VcsModifiableDirtyScope) iterator.next(); + for (Iterator<VcsDirtyScope> iterator = scopes.iterator(); iterator.hasNext(); ) { + final VcsModifiableDirtyScope scope = (VcsModifiableDirtyScope)iterator.next(); final VcsDirtyScopeModifier modifier = scope.getModifier(); if (modifier != null) { fileHolder.notifyVcsStarted(scope.getVcs()); final Iterator<FilePath> filesIterator = modifier.getDirtyFilesIterator(); - for (; filesIterator.hasNext();) { + while (filesIterator.hasNext()) { final FilePath dirtyFile = filesIterator.next(); if ((dirtyFile.getVirtualFile() != null) && isIgnoredFile(dirtyFile.getVirtualFile())) { filesIterator.remove(); @@ -411,7 +442,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec final Collection<VirtualFile> roots = modifier.getAffectedVcsRoots(); for (VirtualFile root : roots) { final Iterator<FilePath> dirIterator = modifier.getDirtyDirectoriesIterator(root); - for (; dirIterator.hasNext(); ) { + while (dirIterator.hasNext()) { final FilePath dir = dirIterator.next(); if ((dir.getVirtualFile() != null) && isIgnoredFile(dir.getVirtualFile())) { dirIterator.remove(); @@ -428,10 +459,10 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } } } - catch(Exception ex) { + catch (Exception ex) { LOG.error(ex); } - catch(AssertionError ex) { + catch (AssertionError ex) { LOG.error(ex); } for (VirtualFile file : refreshFiles) { @@ -443,7 +474,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec final DataHolder dataHolder; final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); - if (! vcsManager.hasActiveVcss()) return; + if (!vcsManager.hasActiveVcss()) return; final VcsInvalidated invalidated = myDirtyScopeManager.retrieveScopes(); if (checkScopeIsEmpty(invalidated)) return; @@ -458,14 +489,14 @@ 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) { - dataHolder = new DataHolder((FileHolderComposite) myComposite.copy(), myWorker.copy(), wasEverythingDirty); + dataHolder = new DataHolder((FileHolderComposite)myComposite.copy(), myWorker.copy(), wasEverythingDirty); myModifier.enterUpdate(); if (wasEverythingDirty) { myUpdateException = null; myAdditionalInfo = null; } } - final String scopeInString = (! LOG.isDebugEnabled()) ? "" : StringUtil.join(scopes, new Function<VcsDirtyScope, String>() { + final String scopeInString = (!LOG.isDebugEnabled()) ? "" : StringUtil.join(scopes, new Function<VcsDirtyScope, String>() { @Override public String fun(VcsDirtyScope scope) { return scope.toString(); @@ -504,7 +535,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec myWorker.onAfterWorkerSwitch(oldWorker); myModifier.setWorker(myWorker); LOG.debug("refresh procedure finished, unversioned size: " + - dataHolder.getComposite().getVFHolder(FileHolder.HolderType.UNVERSIONED).getSize() + "\n changes: " + myWorker); + dataHolder.getComposite().getVFHolder(FileHolder.HolderType.UNVERSIONED).getSize() + "\n changes: " + myWorker); final boolean statusChanged = !myComposite.equals(dataHolder.getComposite()); myComposite = dataHolder.getComposite(); if (statusChanged) { @@ -535,19 +566,20 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec catch (DisposedException e) { // OK, we're finishing all the stuff now. } - catch(ProcessCanceledException e) { + catch (ProcessCanceledException e) { // OK, we're finishing all the stuff now. - } catch (RuntimeInterruptedException ignore) { } - catch(Exception ex) { + catch (RuntimeInterruptedException ignore) { + } + catch (Exception ex) { LOG.error(ex); } - catch(AssertionError ex) { + catch (AssertionError ex) { LOG.error(ex); } finally { myDirtyScopeManager.changesProcessed(); - + synchronized (myDataLock) { myDelayedNotificator.getProxyDispatcher().changeListUpdateDone(); myChangesViewManager.scheduleRefresh(); @@ -556,7 +588,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } private boolean checkScopeIsAllIgnored(VcsInvalidated invalidated) { - if (! invalidated.isEverythingDirty()) { + if (!invalidated.isEverythingDirty()) { filterOutIgnoredFiles(invalidated.getScopes()); if (invalidated.isEmpty()) { return true; @@ -586,7 +618,8 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } }; final UpdatingChangeListBuilder builder = new UpdatingChangeListBuilder(dataHolder.getChangeListWorker(), - dataHolder.getComposite(), disposedGetter, myIgnoredIdeaLevel, gate); + dataHolder.getComposite(), disposedGetter, myIgnoredIdeaLevel, + gate); for (final VcsDirtyScope scope : scopes) { myUpdateChangesProgressIndicator.checkCanceled(); @@ -594,7 +627,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec final AbstractVcs vcs = scope.getVcs(); if (vcs == null) continue; scope.setWasEverythingDirty(wasEverythingDirty); - final VcsModifiableDirtyScope adjustedScope = vcs.adjustDirtyScope((VcsModifiableDirtyScope) scope); + final VcsModifiableDirtyScope adjustedScope = vcs.adjustDirtyScope((VcsModifiableDirtyScope)scope); myChangesViewManager.setBusy(true); dataHolder.notifyStartProcessingChanges(adjustedScope); @@ -614,7 +647,8 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec final ContentRevisionCache cache = ProjectLevelVcsManager.getInstance(myProject).getContentRevisionCache(); if (invalidated.isEverythingDirty()) { cache.clearAllCurrent(); - } else { + } + else { cache.clearScope(invalidated.getScopes()); } } @@ -625,6 +659,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec public boolean isCanceled() { return myUpdater.isStopped(); } + @Override public void checkCanceled() { checkIfDisposed(); @@ -651,7 +686,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } public void notifyStartProcessingChanges(@NotNull final VcsModifiableDirtyScope scope) { - if (! myWasEverythingDirty) { + if (!myWasEverythingDirty) { myComposite.cleanAndAdjustScope(scope); myChangeListWorker.notifyStartProcessingChanges(scope); } @@ -661,7 +696,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } public void notifyDoneProcessingChanges() { - if (! myWasEverythingDirty) { + if (!myWasEverythingDirty) { myChangeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher()); } } @@ -695,11 +730,14 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec handleUpdateException(e); } } - } catch (ProcessCanceledException ignore) { - } catch (Throwable t) { + } + catch (ProcessCanceledException ignore) { + } + catch (Throwable t) { LOG.debug(t); Rethrow.reThrowRuntime(t); - } finally { + } + finally { if (!myUpdater.isStopped()) { dataHolder.notifyDoneProcessingChanges(); } @@ -748,8 +786,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } /** - * @deprecated - * this method made equivalent to {@link #getChangeListsCopy()} so to don't be confused by method name, + * @deprecated this method made equivalent to {@link #getChangeListsCopy()} so to don't be confused by method name, * better use {@link #getChangeListsCopy()} */ @NotNull @@ -816,13 +853,14 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec Map<VirtualFile, LogicalLock> getLogicallyLockedFolders() { synchronized (myDataLock) { - return new HashMap<VirtualFile, LogicalLock>(((LogicallyLockedHolder) myComposite.get(FileHolder.HolderType.LOGICALLY_LOCKED)).getMap()); + return new HashMap<VirtualFile, LogicalLock>( + ((LogicallyLockedHolder)myComposite.get(FileHolder.HolderType.LOGICALLY_LOCKED)).getMap()); } } public boolean isLogicallyLocked(final VirtualFile file) { synchronized (myDataLock) { - return ((LogicallyLockedHolder) myComposite.get(FileHolder.HolderType.LOGICALLY_LOCKED)).containsKey(file); + return ((LogicallyLockedHolder)myComposite.get(FileHolder.HolderType.LOGICALLY_LOCKED)).containsKey(file); } } @@ -847,7 +885,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec @Nullable Map<VirtualFile, String> getSwitchedRoots() { synchronized (myDataLock) { - return ((SwitchedFileHolder) myComposite.get(FileHolder.HolderType.ROOT_SWITCH)).getFilesMapCopy(); + return ((SwitchedFileHolder)myComposite.get(FileHolder.HolderType.ROOT_SWITCH)).getFilesMapCopy(); } } @@ -856,7 +894,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec return myUpdateException; } } - + public Factory<JComponent> getAdditionalUpdateInfo() { synchronized (myDataLock) { return myAdditionalInfo; @@ -937,7 +975,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec synchronized (myDataLock) { for (Map.Entry<String, List<Change>> entry : map.entrySet()) { final List<Change> changes = entry.getValue(); - for (Iterator<Change> iterator = changes.iterator(); iterator.hasNext();) { + for (Iterator<Change> iterator = changes.iterator(); iterator.hasNext(); ) { final Change change = iterator.next(); if (getChangeList(change) != null) { // was not actually rolled back @@ -948,7 +986,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } for (String listName : map.keySet()) { final LocalChangeList byName = myWorker.getCopyByName(listName); - if (byName != null && byName.getChanges().isEmpty() && ! byName.isDefault() && ! byName.isReadOnly()) { + if (byName != null && byName.getChanges().isEmpty() && !byName.isDefault() && !byName.isReadOnly()) { myWorker.removeChangeList(listName); } } @@ -1005,15 +1043,14 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } /** - * @deprecated - * better use normal comparison, with equals + * @deprecated better use normal comparison, with equals */ @Nullable public LocalChangeList getIdentityChangeList(Change change) { synchronized (myDataLock) { final List<LocalChangeList> lists = myWorker.getListsCopy(); for (LocalChangeList list : lists) { - for(Change oldChange: list.getChanges()) { + for (Change oldChange : list.getChanges()) { if (oldChange == change) { return list; } @@ -1168,7 +1205,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec if (exceptions.size() > 0) { StringBuilder message = new StringBuilder(VcsBundle.message("error.adding.files.prompt")); - for(VcsException ex: exceptions) { + for (VcsException ex : exceptions) { message.append("\n").append(ex.getMessage()); } Messages.showErrorDialog(myProject, message.toString(), VcsBundle.message("error.adding.files.title")); @@ -1189,7 +1226,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec synchronized (myDataLock) { List<Change> changesToMove = new ArrayList<Change>(); final LocalChangeList defaultList = getDefaultChangeList(); - for(Change change: defaultList.getChanges()) { + for (Change change : defaultList.getChanges()) { final ContentRevision afterRevision = change.getAfterRevision(); if (afterRevision != null) { VirtualFile vFile = afterRevision.getFile().getVirtualFile(); @@ -1208,8 +1245,9 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec myChangesViewManager.scheduleRefresh(); } - }, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE_NOT_AWT, VcsBundle.message("change.lists.manager.add.unversioned"), null); - } else { + }, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE_NOT_AWT, VcsBundle.message("change.lists.manager.add.unversioned"), null); + } + else { myChangesViewManager.scheduleRefresh(); } } @@ -1238,8 +1276,8 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec private boolean doCommit(final LocalChangeList changeList, final List<Change> changes, final boolean synchronously) { FileDocumentManager.getInstance().saveAllDocuments(); return new CommitHelper(myProject, changeList, changes, changeList.getName(), - StringUtil.isEmpty(changeList.getComment()) ? changeList.getName() : changeList.getComment(), - new ArrayList<CheckinHandler>(), false, synchronously, NullableFunction.NULL, null).doCommit(); + StringUtil.isEmpty(changeList.getComment()) ? changeList.getName() : changeList.getComment(), + new ArrayList<CheckinHandler>(), false, synchronously, NullableFunction.NULL, null).doCommit(); } public void commitChangesSynchronously(LocalChangeList changeList, List<Change> changes) { @@ -1252,20 +1290,21 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec @SuppressWarnings({"unchecked"}) public void readExternal(Element element) throws InvalidDataException { - if (! myProject.isDefault()) { + if (!myProject.isDefault()) { synchronized (myDataLock) { myIgnoredIdeaLevel.clear(); new ChangeListManagerSerialization(myIgnoredIdeaLevel, myWorker).readExternal(element); - if ((! myWorker.isEmpty()) && getDefaultChangeList() == null) { + if ((!myWorker.isEmpty()) && getDefaultChangeList() == null) { setDefaultChangeList(myWorker.getListsCopy().get(0)); } } + myExcludedConvertedToIgnored = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, EXCLUDED_CONVERTED_TO_IGNORED_OPTION)); myConflictTracker.loadState(element); } } public void writeExternal(Element element) throws WriteExternalException { - if (! myProject.isDefault()) { + if (!myProject.isDefault()) { final IgnoredFilesComponent ignoredFilesComponent; final ChangeListWorker worker; synchronized (myDataLock) { @@ -1273,6 +1312,9 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec worker = myWorker.copy(); } new ChangeListManagerSerialization(ignoredFilesComponent, worker).writeExternal(element); + if (myExcludedConvertedToIgnored) { + JDOMExternalizerUtil.writeField(element, EXCLUDED_CONVERTED_TO_IGNORED_OPTION, String.valueOf(true)); + } myConflictTracker.saveState(element); } } @@ -1316,10 +1358,11 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } if (vf.isDirectory()) { myDirs.add(vf); - } else { + } + else { myFiles.add(vf); } - ++ myCnt; + ++myCnt; } } @@ -1327,7 +1370,8 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject); if (myEveryThing) { vcsDirtyScopeManager.markEverythingDirty(); - } else { + } + else { vcsDirtyScopeManager.filesDirty(myFiles, myDirs); } } @@ -1338,12 +1382,21 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec scheduleUnversionedUpdate(); } + @Override + public void addDirectoryToIgnoreImplicitly(@NotNull String path) { + myIgnoredIdeaLevel.addIgnoredDirectoryImplicitly(path, myProject); + } + + public IgnoredFilesComponent getIgnoredFilesComponent() { + return myIgnoredIdeaLevel; + } + private void scheduleUnversionedUpdate() { final MyDirtyFilesScheduler scheduler = new MyDirtyFilesScheduler(myProject); synchronized (myDataLock) { final VirtualFileHolder unversionedHolder = myComposite.getVFHolder(FileHolder.HolderType.UNVERSIONED); - final IgnoredFilesHolder ignoredHolder = (IgnoredFilesHolder) myComposite.get(FileHolder.HolderType.IGNORED); + final IgnoredFilesHolder ignoredHolder = (IgnoredFilesHolder)myComposite.get(FileHolder.HolderType.IGNORED); scheduler.accept(unversionedHolder.getFiles()); scheduler.accept(ignoredHolder.values()); @@ -1368,7 +1421,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } private void exchangeWithIgnored(FileHolderComposite composite, VirtualFileHolder vfHolder, List<VirtualFile> unversionedFiles) { - for(VirtualFile file: unversionedFiles) { + for (VirtualFile file : unversionedFiles) { if (isIgnoredFile(file)) { vfHolder.removeFile(file); composite.getIgnoredFileHolder().addFile(file); @@ -1594,11 +1647,11 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec if (freezeReason != null) { if (modalTitle != null) { Messages.showErrorDialog(myProject, freezeReason, modalTitle); - } else { + } + else { VcsBalloonProblemNotifier.showOverChangesView(myProject, freezeReason, MessageType.WARNING); } } return freezeReason != null; } - } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java index a4c30e62bda5..0e20b4140b56 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java @@ -22,12 +22,10 @@ import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.text.StringUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.util.*; class ChangeListManagerSerialization { @NonNls static final String ATT_ID = "id"; @@ -44,6 +42,8 @@ class ChangeListManagerSerialization { @NonNls static final String NODE_LIST = "list"; @NonNls static final String NODE_IGNORED = "ignored"; @NonNls static final String NODE_CHANGE = "change"; + @NonNls static final String MANUALLY_REMOVED_FROM_IGNORED = "manually-removed-from-ignored"; + @NonNls static final String DIRECTORY_TAG = "directory"; private final IgnoredFilesComponent myIgnoredIdeaLevel; private final ChangeListWorker myWorker; @@ -60,9 +60,17 @@ class ChangeListManagerSerialization { readChangeList(listNode); } final List<Element> ignoredNodes = element.getChildren(NODE_IGNORED); - for (Element ignoredNode: ignoredNodes) { + for (Element ignoredNode : ignoredNodes) { readFileToIgnore(ignoredNode); } + Element manuallyRemovedFromIgnoredTag = element.getChild(MANUALLY_REMOVED_FROM_IGNORED); + Set<String> manuallyRemovedFromIgnoredPaths = new HashSet<String>(); + if (manuallyRemovedFromIgnoredTag != null) { + for (Element tag : manuallyRemovedFromIgnoredTag.getChildren(DIRECTORY_TAG)) { + manuallyRemovedFromIgnoredPaths.add(tag.getAttributeValue(ATT_PATH)); + } + } + myIgnoredIdeaLevel.setDirectoriesManuallyRemovedFromIgnored(manuallyRemovedFromIgnoredPaths); } private void readChangeList(final Element listNode) { @@ -90,7 +98,6 @@ class ChangeListManagerSerialization { if (ATT_VALUE_TRUE.equals(listNode.getAttributeValue(ATT_READONLY))) { list.setReadOnly(true); } - } private void readFileToIgnore(final Element ignoredNode) { @@ -123,7 +130,10 @@ class ChangeListManagerSerialization { listNode.setAttribute(ATT_ID, list.getId()); listNode.setAttribute(ATT_NAME, list.getName()); - listNode.setAttribute(ATT_COMMENT, list.getComment()); + String comment = list.getComment(); + if (comment != null) { + listNode.setAttribute(ATT_COMMENT, comment); + } List<Change> changes = new ArrayList<Change>(list.getChanges()); Collections.sort(changes, new ChangeComparator()); for (Change change : changes) { @@ -131,26 +141,35 @@ class ChangeListManagerSerialization { } } final IgnoredFileBean[] filesToIgnore = myIgnoredIdeaLevel.getFilesToIgnore(); - for(IgnoredFileBean bean: filesToIgnore) { - Element fileNode = new Element(NODE_IGNORED); - element.addContent(fileNode); - String path = bean.getPath(); - if (path != null) { - fileNode.setAttribute("path", path); - } - String mask = bean.getMask(); - if (mask != null) { - fileNode.setAttribute("mask", mask); - } + for (IgnoredFileBean bean : filesToIgnore) { + Element fileNode = new Element(NODE_IGNORED); + element.addContent(fileNode); + String path = bean.getPath(); + if (path != null) { + fileNode.setAttribute("path", path); + } + String mask = bean.getMask(); + if (mask != null) { + fileNode.setAttribute("mask", mask); } + } + Set<String> manuallyRemovedFromIgnored = myIgnoredIdeaLevel.getDirectoriesManuallyRemovedFromIgnored(); + if (!manuallyRemovedFromIgnored.isEmpty()) { + Element list = new Element(MANUALLY_REMOVED_FROM_IGNORED); + for (String path : manuallyRemovedFromIgnored) { + list.addContent(new Element(DIRECTORY_TAG).setAttribute(ATT_PATH, path)); + } + element.addContent(list); + } } private static class ChangeComparator implements Comparator<Change> { @Override - public int compare(Change o1, Change o2) { + public int compare(@NotNull Change o1, @NotNull Change o2) { return Comparing.compare(o1.toString(), o2.toString()); } } + private static void writeChange(final Element listNode, final Change change) { Element changeNode = new Element(NODE_CHANGE); listNode.addContent(changeNode); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java index 6d13d21a996c..f81c5069718b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java @@ -16,7 +16,10 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vcs.FileStatus; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.BeforeAfter; import java.util.List; @@ -30,13 +33,41 @@ public class FragmentedContent { private final Document myBefore; private final Document myAfter; private final List<BeforeAfter<TextRange>> myRanges; - private boolean myOneSide; - private boolean myIsAddition; - public FragmentedContent(Document before, Document after, List<BeforeAfter<TextRange>> ranges) { + private final boolean myOneSide; + private final boolean myIsAddition; + + private final VirtualFile myFileBefore; + private final VirtualFile myFileAfter; + private final FileType myFileTypeBefore; + private final FileType myFileTypeAfter; + + public FragmentedContent(Document before, Document after, List<BeforeAfter<TextRange>> ranges, Change change) { myBefore = before; myAfter = after; myRanges = ranges; + + final FileStatus fs = change.getFileStatus(); + myIsAddition = FileStatus.ADDED.equals(fs); + myOneSide = FileStatus.ADDED.equals(fs) || FileStatus.DELETED.equals(fs); + + if (change.getBeforeRevision() != null) { + myFileBefore = change.getBeforeRevision().getFile().getVirtualFile(); + myFileTypeBefore = change.getBeforeRevision().getFile().getFileType(); + } + else { + myFileBefore = null; + myFileTypeBefore = null; + } + + if (change.getAfterRevision() != null) { + myFileAfter = change.getAfterRevision().getFile().getVirtualFile(); + myFileTypeAfter = change.getAfterRevision().getFile().getFileType(); + } + else { + myFileAfter = null; + myFileTypeAfter = null; + } } public Document getBefore() { @@ -50,7 +81,7 @@ public class FragmentedContent { public List<BeforeAfter<TextRange>> getRanges() { return myRanges; } - + public int getSize() { return myRanges.size(); } @@ -59,15 +90,23 @@ public class FragmentedContent { return myOneSide; } - public void setOneSide(boolean oneSide) { - myOneSide = oneSide; - } - public boolean isAddition() { return myIsAddition; } - public void setIsAddition(boolean isAddition) { - myIsAddition = isAddition; + public VirtualFile getFileBefore() { + return myFileBefore; + } + + public VirtualFile getFileAfter() { + return myFileAfter; + } + + public FileType getFileTypeBefore() { + return myFileTypeBefore; + } + + public FileType getFileTypeAfter() { + return myFileTypeAfter; } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java index 2f3788ae509c..77dd9b3f42b3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java @@ -81,10 +81,7 @@ public class FragmentedDiffRequestFromChange { } List<BeforeAfter<TextRange>> ranges = calculator.getRanges(); if (ranges == null || ranges.isEmpty()) return null; - FragmentedContent fragmentedContent = new FragmentedContent(calculator.getOldDocument(), calculator.getDocument(), ranges); - final FileStatus fs = change.getFileStatus(); - fragmentedContent.setIsAddition(FileStatus.ADDED.equals(fs)); - fragmentedContent.setOneSide(FileStatus.ADDED.equals(fs) || FileStatus.DELETED.equals(fs)); + FragmentedContent fragmentedContent = new FragmentedContent(calculator.getOldDocument(), calculator.getDocument(), ranges, change); VirtualFile file = filePath.getVirtualFile(); if (file == null) { filePath.hardRefresh(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesComponent.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesComponent.java index 5c8ac2a6b623..b2eaa1f2e6e3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesComponent.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/IgnoredFilesComponent.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; @@ -27,6 +28,7 @@ import java.util.*; public class IgnoredFilesComponent { private final Set<IgnoredFileBean> myFilesToIgnore; private final Map<String, IgnoredFileBean> myFilesMap; + private final Set<String> myDirectoriesManuallyRemovedFromIgnored; public IgnoredFilesComponent(final Project project, final boolean registerListener) { myFilesToIgnore = new LinkedHashSet<IgnoredFileBean>(); @@ -40,20 +42,53 @@ public class IgnoredFilesComponent { } }); } + myDirectoriesManuallyRemovedFromIgnored = new HashSet<String>(); } public IgnoredFilesComponent(final IgnoredFilesComponent other) { myFilesToIgnore = new LinkedHashSet<IgnoredFileBean>(other.myFilesToIgnore); myFilesMap = new HashMap<String, IgnoredFileBean>(other.myFilesMap); + myDirectoriesManuallyRemovedFromIgnored = new HashSet<String>(other.myDirectoriesManuallyRemovedFromIgnored); } public void add(final IgnoredFileBean... filesToIgnore) { - synchronized(myFilesToIgnore) { + synchronized (myFilesToIgnore) { Collections.addAll(myFilesToIgnore, filesToIgnore); addIgnoredFiles(filesToIgnore); } } + public Set<String> getDirectoriesManuallyRemovedFromIgnored() { + return Collections.unmodifiableSet(myDirectoriesManuallyRemovedFromIgnored); + } + + public void setDirectoriesManuallyRemovedFromIgnored(Set<String> directories) { + myDirectoriesManuallyRemovedFromIgnored.clear(); + myDirectoriesManuallyRemovedFromIgnored.addAll(directories); + } + + public void addIgnoredDirectoryImplicitly(@NotNull String path, @NotNull Project project) { + synchronized (myFilesToIgnore) { + if (myDirectoriesManuallyRemovedFromIgnored.contains(path) || myDirectoriesManuallyRemovedFromIgnored.contains(path + "/")) { + return; + } + for (IgnoredFileBean bean : myFilesToIgnore) { + if (bean.getType() == IgnoreSettingsType.UNDER_DIR && FileUtil.isAncestor(bean.getPath(), path, false)) { + return; + } + } + List<IgnoredFileBean> toRemove = new ArrayList<IgnoredFileBean>(); + for (IgnoredFileBean bean : myFilesToIgnore) { + if ((bean.getType() == IgnoreSettingsType.UNDER_DIR || bean.getType() == IgnoreSettingsType.FILE) && + FileUtil.isAncestor(path, bean.getPath(), false)) { + toRemove.add(bean); + } + } + myFilesToIgnore.removeAll(toRemove); + myFilesToIgnore.add(IgnoredBeanFactory.ignoreUnderDirectory(path, project)); + } + } + private void addIgnoredFiles(final IgnoredFileBean... filesToIgnore) { for (IgnoredFileBean bean : filesToIgnore) { if (IgnoreSettingsType.FILE.equals(bean.getType())) { @@ -73,6 +108,7 @@ public class IgnoredFilesComponent { myFilesMap.clear(); } } + public boolean isEmpty() { synchronized (myFilesToIgnore) { return myFilesToIgnore.isEmpty(); @@ -80,7 +116,7 @@ public class IgnoredFilesComponent { } public void set(final IgnoredFileBean... filesToIgnore) { - synchronized(myFilesToIgnore) { + synchronized (myFilesToIgnore) { myFilesToIgnore.clear(); Collections.addAll(myFilesToIgnore, filesToIgnore); myFilesMap.clear(); @@ -89,7 +125,7 @@ public class IgnoredFilesComponent { } public IgnoredFileBean[] getFilesToIgnore() { - synchronized(myFilesToIgnore) { + synchronized (myFilesToIgnore) { return myFilesToIgnore.toArray(new IgnoredFileBean[myFilesToIgnore.size()]); } } @@ -103,14 +139,14 @@ public class IgnoredFilesComponent { } public boolean isIgnoredFile(@NotNull VirtualFile file) { - synchronized(myFilesToIgnore) { + synchronized (myFilesToIgnore) { if (myFilesToIgnore.size() == 0) return false; final String path = FilePathsHelper.convertPath(file); final IgnoredFileBean fileBean = myFilesMap.get(path); if (fileBean != null && fileBean.matchesFile(file)) return true; - for(IgnoredFileBean bean: myFilesToIgnore) { + for (IgnoredFileBean bean : myFilesToIgnore) { if (bean.matchesFile(file)) return true; } return false; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java index c413cca246c3..1d310d5a023a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java @@ -1,14 +1,13 @@ package com.intellij.openapi.vcs.changes; -import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.OpenTHashSet; @@ -147,12 +146,11 @@ public class LocalChangeListImpl extends LocalChangeList { createReadChangesCache(); final Collection<Change> result = new ArrayList<Change>(); myChangesBeforeUpdate = new OpenTHashSet<Change>(myChanges); - final FileIndexFacade fileIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, FileIndexFacade.class); for (Change oldBoy : myChangesBeforeUpdate) { final ContentRevision before = oldBoy.getBeforeRevision(); final ContentRevision after = oldBoy.getAfterRevision(); if (scope == null || before != null && scope.belongsTo(before.getFile()) || after != null && scope.belongsTo(after.getFile()) - || isIgnoredChange(oldBoy, fileIndex)) { + || isIgnoredChange(oldBoy, project)) { result.add(oldBoy); myChanges.remove(oldBoy); myReadChangesCache = null; @@ -161,18 +159,21 @@ public class LocalChangeListImpl extends LocalChangeList { return result; } - private static boolean isIgnoredChange(final Change change, final FileIndexFacade fileIndex) { - boolean beforeRevIgnored = change.getBeforeRevision() == null || isIgnoredRevision(change.getBeforeRevision(), fileIndex); - boolean afterRevIgnored = change.getAfterRevision() == null || isIgnoredRevision(change.getAfterRevision(), fileIndex); + private static boolean isIgnoredChange(@NotNull Change change, @NotNull Project project) { + boolean beforeRevIgnored = change.getBeforeRevision() == null || isIgnoredRevision(change.getBeforeRevision(), project); + boolean afterRevIgnored = change.getAfterRevision() == null || isIgnoredRevision(change.getAfterRevision(), project); return beforeRevIgnored && afterRevIgnored; } - private static boolean isIgnoredRevision(final ContentRevision revision, final FileIndexFacade fileIndex) { + private static boolean isIgnoredRevision(final @NotNull ContentRevision revision, final @NotNull Project project) { return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { + if (project.isDisposed()) { + return false; + } VirtualFile vFile = revision.getFile().getVirtualFile(); - return vFile != null && fileIndex.isExcludedFile(vFile); + return vFile != null && ProjectLevelVcsManager.getInstance(project).isIgnored(vFile); } }); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java index 2c2d0634b709..6e8a1a04d135 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreparedFragmentedContent.java @@ -18,6 +18,8 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diff.DiffContent; import com.intellij.openapi.diff.SimpleContent; +import com.intellij.openapi.diff.impl.DiffHighlighterFactory; +import com.intellij.openapi.diff.impl.DiffHighlighterFactoryImpl; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.highlighter.*; @@ -35,6 +37,7 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsConfiguration; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.impl.ContentRevisionCache; +import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.BeforeAfter; import com.intellij.util.Consumer; @@ -140,6 +143,9 @@ public class PreparedFragmentedContent { fragmentedContent.getBefore(), fragmentedContent.getAfter()); // add "artificial" empty lines + final Document document = fragmentedContent.getBefore(); + final Document document1 = fragmentedContent.getAfter(); + // line starts BeforeAfter<Integer> lines = new BeforeAfter<Integer>(0, 0); for (BeforeAfter<TextRange> lineNumbers : expandedRanges) { @@ -155,7 +161,6 @@ public class PreparedFragmentedContent { oldConvertor.put(lines.getBefore(), lineNumbers.getBefore().getStartOffset()); newConvertor.put(lines.getAfter(), lineNumbers.getAfter().getStartOffset()); - final Document document = fragmentedContent.getBefore(); if (sbOld.length() > 0) { sbOld.append('\n'); } @@ -164,7 +169,6 @@ public class PreparedFragmentedContent { myBeforeFragments.add(beforeRange); sbOld.append(document.getText(beforeRange)); - final Document document1 = fragmentedContent.getAfter(); if (sbNew.length() > 0) { sbNew.append('\n'); } @@ -180,7 +184,23 @@ public class PreparedFragmentedContent { myLineRanges.add(new BeforeAfter<Integer>(lines.getBefore() == 0 ? 0 : lines.getBefore() - 1, lines.getAfter() == 0 ? 0 : lines.getAfter() - 1)); - setHighlighters(fragmentedContent.getBefore(), fragmentedContent.getAfter(), expandedRanges); + if (!expandedRanges.isEmpty()) { + BeforeAfter<TextRange> last = expandedRanges.get(expandedRanges.size() - 1); + if (sbOld.length() > 0) { + if (document.getLineEndOffset(last.getBefore().getEndOffset()) != document.getTextLength()) { + sbOld.append('\n'); + oldConvertor.emptyLine(lines.getBefore()); + } + } + if (sbNew.length() > 0) { + if (document1.getLineEndOffset(last.getAfter().getEndOffset()) != document1.getTextLength()) { + sbNew.append('\n'); + newConvertor.emptyLine(lines.getAfter()); + } + } + } + + setHighlighters(fragmentedContent.getBefore(), fragmentedContent.getAfter(), expandedRanges, fragmentedContent); setTodoHighlighting(fragmentedContent.getBefore(), fragmentedContent.getAfter()); } }); @@ -323,29 +343,37 @@ public class PreparedFragmentedContent { } private void setHighlighters(final Document oldDocument, final Document document, - List<BeforeAfter<TextRange>> ranges) { - EditorHighlighterFactory editorHighlighterFactory = EditorHighlighterFactory.getInstance(); - final SyntaxHighlighter syntaxHighlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(myFileType, myProject, null); - final EditorHighlighter highlighter = - editorHighlighterFactory.createEditorHighlighter(syntaxHighlighter, EditorColorsManager.getInstance().getGlobalScheme()); - + List<BeforeAfter<TextRange>> ranges, FragmentedContent fragmentedContent) { + EditorHighlighter highlighter = createHighlighter(fragmentedContent.getFileTypeBefore(), + fragmentedContent.getFileBefore(), + fragmentedContent.getFileAfter(), myProject).createHighlighter(); highlighter.setEditor(new LightHighlighterClient(oldDocument, myProject)); highlighter.setText(oldDocument.getText()); HighlighterIterator iterator = highlighter.createIterator(ranges.get(0).getBefore().getStartOffset()); - FragmentedEditorHighlighter beforeHighlighter = - new FragmentedEditorHighlighter(iterator, getBeforeFragments(), 1, true); + FragmentedEditorHighlighter beforeHighlighter = new FragmentedEditorHighlighter(iterator, getBeforeFragments(), 1, true); setBeforeHighlighter(beforeHighlighter); - final EditorHighlighter highlighter1 = - editorHighlighterFactory.createEditorHighlighter(syntaxHighlighter, EditorColorsManager.getInstance().getGlobalScheme()); + EditorHighlighter highlighter1 = createHighlighter(fragmentedContent.getFileTypeAfter(), + fragmentedContent.getFileAfter(), + fragmentedContent.getFileBefore(), myProject).createHighlighter(); highlighter1.setEditor(new LightHighlighterClient(document, myProject)); highlighter1.setText(document.getText()); HighlighterIterator iterator1 = highlighter1.createIterator(ranges.get(0).getAfter().getStartOffset()); - FragmentedEditorHighlighter afterHighlighter = - new FragmentedEditorHighlighter(iterator1, getAfterFragments(), 1, true); + FragmentedEditorHighlighter afterHighlighter = new FragmentedEditorHighlighter(iterator1, getAfterFragments(), 1, true); setAfterHighlighter(afterHighlighter); } + private DiffHighlighterFactory createHighlighter(FileType contentType, + VirtualFile file, + VirtualFile otherFile, + Project project) { + VirtualFile baseFile = file; + if (baseFile == null) baseFile = otherFile; + if (contentType == null) contentType = myFileType; + + return new DiffHighlighterFactoryImpl(contentType, baseFile, project); + } + private void setTodoHighlighting(final Document oldDocument, final Document document) { final ContentRevisionCache cache = ProjectLevelVcsManager.getInstance(myProject).getContentRevisionCache(); final List<Pair<TextRange,TextAttributes>> beforeTodoRanges = myBeforeNumber == null ? Collections.<Pair<TextRange,TextAttributes>>emptyList() : diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java index fdc079641b68..d06c8f888ad7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java @@ -15,16 +15,15 @@ */ package com.intellij.openapi.vcs.changes; -import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Getter; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FilePathImpl; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsKey; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.Nullable; @@ -40,7 +39,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { private VcsDirtyScope myScope; private FoldersCutDownWorker myFoldersCutDownWorker; private final IgnoredFilesComponent myIgnoredFilesComponent; - private final FileIndexFacade myIndex; + private final ProjectLevelVcsManager myVcsManager; private final ChangeListManagerGate myGate; private Factory<JComponent> myAdditionalInfo; @@ -53,7 +52,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { myDisposedGetter = disposedGetter; myIgnoredFilesComponent = ignoredFilesComponent; myGate = gate; - myIndex = PeriodicalTasksCloser.getInstance().safeGetService(changeListWorker.getProject(), FileIndexFacade.class); + myVcsManager = ProjectLevelVcsManager.getInstance(changeListWorker.getProject()); } private void checkIfDisposed() { @@ -117,12 +116,12 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { myChangeListWorker.removeRegisteredChangeFor(path); } - private boolean isExcluded(final VirtualFile file) { + private boolean isIgnoredByVcs(final VirtualFile file) { return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { checkIfDisposed(); - return myIndex.isExcludedFile(file); + return myVcsManager.isIgnored(file); } }); } @@ -133,7 +132,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { } if (file == null) return; checkIfDisposed(); - if (isExcluded(file)) return; + if (isIgnoredByVcs(file)) return; if (myScope.belongsTo(new FilePathImpl(file))) { if (myIgnoredFilesComponent.isIgnoredFile(file)) { myComposite.getIgnoredFileHolder().addFile(file); @@ -165,7 +164,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { public void processModifiedWithoutCheckout(final VirtualFile file) { if (file == null) return; checkIfDisposed(); - if (isExcluded(file)) return; + if (isIgnoredByVcs(file)) return; if (myScope.belongsTo(new FilePathImpl(file))) { if (LOG.isDebugEnabled()) { LOG.debug("processModifiedWithoutCheckout " + file); @@ -177,7 +176,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { public void processIgnoredFile(final VirtualFile file) { if (file == null) return; checkIfDisposed(); - if (isExcluded(file)) return; + if (isIgnoredByVcs(file)) return; if (myScope.belongsTo(new FilePathImpl(file))) { IgnoredFilesHolder ignoredFilesHolder = myComposite.getIgnoredFileHolder(); if (ignoredFilesHolder instanceof IgnoredFilesCompositeHolder) { @@ -212,7 +211,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { public void processSwitchedFile(final VirtualFile file, final String branch, final boolean recursive) { if (file == null) return; checkIfDisposed(); - if (isExcluded(file)) return; + if (isIgnoredByVcs(file)) return; if (myScope.belongsTo(new FilePathImpl(file))) { myChangeListWorker.addSwitched(file, branch, recursive); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeImpl.java index eb44d591d605..c8617dc5f347 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeImpl.java @@ -34,6 +34,7 @@ import com.intellij.util.containers.Convertor; import com.intellij.util.containers.MultiMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -75,14 +76,14 @@ public class VcsDirtyScopeImpl extends VcsModifiableDirtyScope { return ContainerUtil.concatIterators(iteratorList); } - @Nullable + @NotNull @Override public Iterator<FilePath> getDirtyDirectoriesIterator(final VirtualFile root) { final THashSet<FilePath> filePaths = myDirtyDirectoriesRecursively.get(root); if (filePaths != null) { return filePaths.iterator(); } - return null; + return ContainerUtil.emptyIterator(); } @Override @@ -338,10 +339,8 @@ public class VcsDirtyScopeImpl extends VcsModifiableDirtyScope { } /** - * Add dirty file to the scope. Note that file is not added - * if its ancestor was added as dirty recursively or if its parent - * is in already in the dirty scope. Also immendiate non-directory - * children are removed from the set of dirty files. + * Add dirty file to the scope. Note that file is not added if its ancestor was added as dirty recursively or if its parent is in already + * in the dirty scope. Also immediate non-directory children are removed from the set of dirty files. * * @param newcomer a file or directory added to the dirty scope. */ diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java index 00ca9f2ebf4f..112caa4a40b4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java @@ -73,7 +73,7 @@ public class VcsGuess { final boolean inContent = myVcsManager.isFileInContent(validParent); if (inContent) return true; if (filePath != null) { - return isFileInBaseDir(filePath, myProject.getBaseDir()) && !myExcludedFileIndex.isExcludedFile(validParent); + return isFileInBaseDir(filePath, myProject.getBaseDir()) && !myVcsManager.isIgnored(validParent); } return false; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ConflictedDiffRequestPresentable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ConflictedDiffRequestPresentable.java index 02586bba5e78..f70c84405c2d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ConflictedDiffRequestPresentable.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ConflictedDiffRequestPresentable.java @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffRequestFactory; import com.intellij.openapi.diff.MergeRequest; import com.intellij.openapi.diff.SimpleDiffRequest; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.io.FileUtil; @@ -60,6 +61,7 @@ public class ConflictedDiffRequestPresentable implements DiffRequestPresentable public MyResult step(DiffChainContext context) { if (myChange.getAfterRevision() == null) return createErrorResult(); final Getter<MergeTexts> mergeProvider = myChange.getMergeProvider(); + FileType type = myChange.getVirtualFile() != null ? myChange.getVirtualFile().getFileType() : null; if (mergeProvider != null) { // guaranteed text final MergeTexts texts = mergeProvider.get(); @@ -67,7 +69,7 @@ public class ConflictedDiffRequestPresentable implements DiffRequestPresentable return createErrorResult(); } final MergeRequest request = DiffRequestFactory.getInstance() - .create3WayDiffRequest(texts.getLeft(), texts.getRight(), texts.getBase(), myProject, null, null); + .create3WayDiffRequest(texts.getLeft(), texts.getRight(), texts.getBase(), type, myProject, null, null); request.setWindowTitle(FileUtil.toSystemDependentName(myFile.getPresentableUrl())); // todo titles? request.setVersionTitles(new String[] {myChange.getAfterRevision().getRevisionNumber().asString(), @@ -95,7 +97,8 @@ public class ConflictedDiffRequestPresentable implements DiffRequestPresentable final MergeRequest request = DiffRequestFactory.getInstance() .create3WayDiffRequest(CharsetToolkit.bytesToString(mergeData.CURRENT, charset), CharsetToolkit.bytesToString(mergeData.LAST, charset), - CharsetToolkit.bytesToString(mergeData.ORIGINAL, charset), myProject, null, null); + CharsetToolkit.bytesToString(mergeData.ORIGINAL, charset), + type, myProject, null, null); request.setWindowTitle(FileUtil.toSystemDependentName(myFile.getPresentableUrl())); // todo titles? VcsRevisionNumber lastRevisionNumber = mergeData.LAST_REVISION_NUMBER; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java index 6b4a3fb2c390..f7fbe4c9980d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java @@ -325,7 +325,7 @@ public class ApplyPatchAction extends DumbAwareAction { MergeRequest request; if (myReadOnly) { request = DiffRequestFactory.getInstance() - .create3WayDiffRequest(leftText, rightText, originalContent, project, null, null); + .create3WayDiffRequest(leftText, rightText, originalContent, file.getFileType(), project, null, null); } else { request = DiffRequestFactory.getInstance().createMergeRequest(reverse ? rightText : leftText, reverse ? leftText : rightText, originalContent, diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/MergedDiffRequestPresentable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/MergedDiffRequestPresentable.java index 05b4e95b8672..a3ddc2ba450d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/MergedDiffRequestPresentable.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/MergedDiffRequestPresentable.java @@ -58,7 +58,10 @@ public class MergedDiffRequestPresentable implements DiffRequestPresentable { return new MyResult(badDiffRequest, DiffPresentationReturnValue.useRequest); } final MergeRequest request = DiffRequestFactory.getInstance() - .create3WayDiffRequest(revisionTexts.getLocal().toString(), revisionTexts.getPatched(), revisionTexts.getBase().toString(), myProject, null, null); + .create3WayDiffRequest(revisionTexts.getLocal().toString(), + revisionTexts.getPatched(), + revisionTexts.getBase().toString(), + filePath.getFileType(), myProject, null, null); request.setWindowTitle(VcsBundle.message("patch.apply.conflict.title", FileUtil.toSystemDependentName(myFile.getPresentableUrl()))); request.setVersionTitles(new String[] {"Current Version", "Base Version", FileUtil.toSystemDependentName(myAfterTitle)}); return new MyResult(request, DiffPresentationReturnValue.useRequest); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/FilePathChangesTreeList.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/FilePathChangesTreeList.java index fe9c12036596..ee3390390f06 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/FilePathChangesTreeList.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/FilePathChangesTreeList.java @@ -24,13 +24,11 @@ import javax.swing.tree.DefaultTreeModel; import java.util.List; public class FilePathChangesTreeList extends ChangesTreeList<FilePath> { - private final Project myProject; public FilePathChangesTreeList(@NotNull Project project, @NotNull List<FilePath> originalFiles, boolean showCheckboxes, boolean highlightProblems, @Nullable Runnable inclusionListener, @Nullable ChangeNodeDecorator nodeDecorator) { super(project, originalFiles, showCheckboxes, highlightProblems, inclusionListener, nodeDecorator); - myProject = project; } protected DefaultTreeModel buildTreeModel(final List<FilePath> changes, ChangeNodeDecorator changeNodeDecorator) { @@ -43,10 +41,7 @@ public class FilePathChangesTreeList extends ChangesTreeList<FilePath> { @Nullable protected FilePath getLeadSelectedObject(final ChangesBrowserNode node) { - final Object userObject = node.getUserObject(); - if (userObject instanceof FilePath) { - return (FilePath) userObject; - } - return null; + Object userObject = node.getUserObject(); + return userObject instanceof FilePath ? (FilePath)userObject : null; } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/IgnoredSettingsPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/IgnoredSettingsPanel.java index 82b676a8834d..6edfbb96c848 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/IgnoredSettingsPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/IgnoredSettingsPanel.java @@ -27,7 +27,8 @@ import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.VcsBundle; -import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; +import com.intellij.openapi.vcs.changes.IgnoreSettingsType; import com.intellij.openapi.vcs.changes.IgnoredFileBean; import com.intellij.ui.*; import com.intellij.ui.components.JBList; @@ -37,13 +38,16 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.util.HashSet; +import java.util.Set; public class IgnoredSettingsPanel implements SearchableConfigurable, Configurable.NoScroll { private JBList myList; private JPanel myPanel; private final Project myProject; private DefaultListModel myModel; - private final ChangeListManager myChangeListManager; + private final ChangeListManagerImpl myChangeListManager; + private final Set<String> myDirectoriesManuallyRemovedFromIgnored = new HashSet<String>(); public IgnoredSettingsPanel(Project project) { myList = new JBList(); @@ -51,7 +55,7 @@ public class IgnoredSettingsPanel implements SearchableConfigurable, Configurabl myList.getEmptyText().setText(VcsBundle.message("no.ignored.files")); myProject = project; - myChangeListManager = ChangeListManager.getInstance(myProject); + myChangeListManager = ChangeListManagerImpl.getInstanceImpl(myProject); } private void setItems(final IgnoredFileBean[] filesToIgnore) { @@ -97,32 +101,30 @@ public class IgnoredSettingsPanel implements SearchableConfigurable, Configurabl } private void deleteItems() { - boolean contigiousSelection = true; - int minSelectionIndex = myList.getSelectionModel().getMinSelectionIndex(); - int maxSelectionIndex = myList.getSelectionModel().getMaxSelectionIndex(); - for (int i = minSelectionIndex; i <= maxSelectionIndex; i++) { - if (!myList.getSelectionModel().isSelectedIndex(i)) { - contigiousSelection = false; - break; - } - } - if (contigiousSelection) { - myModel.removeRange(minSelectionIndex, maxSelectionIndex); - } - else { - final Object[] selection = myList.getSelectedValues(); - for (Object item : selection) { - myModel.removeElement(item); + for (Object o : myList.getSelectedValues()) { + IgnoredFileBean bean = (IgnoredFileBean)o; + if (bean.getType() == IgnoreSettingsType.UNDER_DIR) { + myDirectoriesManuallyRemovedFromIgnored.add(bean.getPath()); } } + ListUtil.removeSelectedItems(myList); } public void reset() { setItems(myChangeListManager.getFilesToIgnore()); + myDirectoriesManuallyRemovedFromIgnored.clear(); + myDirectoriesManuallyRemovedFromIgnored.addAll(myChangeListManager.getIgnoredFilesComponent().getDirectoriesManuallyRemovedFromIgnored()); } public void apply() { - myChangeListManager.setFilesToIgnore(getItems()); + IgnoredFileBean[] toIgnore = getItems(); + myChangeListManager.setFilesToIgnore(toIgnore); + for (IgnoredFileBean bean : toIgnore) { + if (bean.getType() == IgnoreSettingsType.UNDER_DIR) { + myDirectoriesManuallyRemovedFromIgnored.remove(bean.getPath()); + } + } + myChangeListManager.getIgnoredFilesComponent().setDirectoriesManuallyRemovedFromIgnored(myDirectoriesManuallyRemovedFromIgnored); } public boolean isModified() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index 6f1cd15ef018..d332d1faa792 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -160,11 +160,16 @@ public class LineStatusTrackerDrawing { localShowPrevAction.copyFrom(globalShowPrevAction); final RollbackLineStatusRangeAction rollback = new RollbackLineStatusRangeAction(tracker, range, editor); - EmptyAction.setupAction(rollback, IdeActions.SELECTED_CHANGES_ROLLBACK, editorComponent); + final ShowLineStatusRangeDiffAction showDiff = new ShowLineStatusRangeDiffAction(tracker, range, editor); + final CopyLineStatusRangeAction copyRange = new CopyLineStatusRangeAction(tracker, range); + group.add(rollback); + group.add(showDiff); + group.add(copyRange); - group.add(new ShowLineStatusRangeDiffAction(tracker, range, editor)); - group.add(new CopyLineStatusRangeAction(tracker, range)); + EmptyAction.setupAction(rollback, IdeActions.SELECTED_CHANGES_ROLLBACK, editorComponent); + EmptyAction.setupAction(showDiff, "ChangesView.Diff", editorComponent); + EmptyAction.setupAction(copyRange, IdeActions.ACTION_COPY, editorComponent); final JComponent toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, group, true).getComponent(); @@ -221,6 +226,8 @@ public class LineStatusTrackerDrawing { HintListener closeListener = new HintListener() { public void hintHidden(final EventObject event) { actionList.remove(rollback); + actionList.remove(showDiff); + actionList.remove(copyRange); actionList.remove(localShowPrevAction); actionList.remove(localShowNextAction); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java index 59697f1222dd..6e08d90a3b5d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java @@ -13,6 +13,7 @@ package com.intellij.openapi.vcs.ex; import com.intellij.icons.AllIcons; +import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -32,7 +33,9 @@ import java.util.List; public class RollbackLineStatusAction extends DumbAwareAction { public RollbackLineStatusAction() { - super("Rollback", "Rollback selected changes", AllIcons.Actions.Reset); + super(ActionsBundle.actionText("Vcs.RollbackChangedLines"), + ActionsBundle.actionDescription("Vcs.RollbackChangedLines"), + AllIcons.Actions.Reset); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/BaseDiffFromHistoryHandler.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/BaseDiffFromHistoryHandler.java new file mode 100644 index 000000000000..8a16ba6a481f --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/BaseDiffFromHistoryHandler.java @@ -0,0 +1,197 @@ +/* + * Copyright 2000-2014 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.history; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogBuilder; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.util.Couple; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public abstract class BaseDiffFromHistoryHandler<T extends VcsFileRevision> implements DiffFromHistoryHandler { + + private static final Logger LOG = Logger.getInstance(BaseDiffFromHistoryHandler.class); + + @NotNull protected final Project myProject; + + protected BaseDiffFromHistoryHandler(@NotNull Project project) { + myProject = project; + } + + @Override + public void showDiffForOne(@NotNull AnActionEvent e, + @NotNull FilePath filePath, + @NotNull VcsFileRevision previousRevision, + @NotNull VcsFileRevision revision) { + doShowDiff(filePath, previousRevision, revision, false); + } + + @Override + public void showDiffForTwo(@NotNull FilePath filePath, @NotNull VcsFileRevision revision1, @NotNull VcsFileRevision revision2) { + doShowDiff(filePath, revision1, revision2, true); + } + + @SuppressWarnings("unchecked") + protected void doShowDiff(@NotNull FilePath filePath, + @NotNull VcsFileRevision revision1, + @NotNull VcsFileRevision revision2, + boolean autoSort) { + if (!filePath.isDirectory()) { + VcsHistoryUtil.showDifferencesInBackground(myProject, filePath, revision1, revision2, autoSort); + } + else if (revision1.equals(VcsFileRevision.NULL)) { + T right = (T)revision2; + showAffectedChanges(filePath, right); + } + else if (revision2 instanceof CurrentRevision) { + T left = (T)revision1; + showChangesBetweenRevisions(filePath, left, null); + } + else { + T left = (T)revision1; + T right = (T)revision2; + if (autoSort) { + Couple<VcsFileRevision> pair = VcsHistoryUtil.sortRevisions(revision1, revision2); + left = (T)pair.first; + right = (T)pair.second; + } + showChangesBetweenRevisions(filePath, left, right); + } + } + + protected void showChangesBetweenRevisions(@NotNull final FilePath path, @NotNull final T rev1, @Nullable final T rev2) { + new CollectChangesTask("Comparing revisions...") { + + @NotNull + @Override + public List<Change> getChanges() throws VcsException { + return getChangesBetweenRevisions(path, rev1, rev2); + } + + @NotNull + @Override + public String getDialogTitle() { + return getChangesBetweenRevisionsDialogTitle(path, rev1, rev2); + } + }.queue(); + } + + protected void showAffectedChanges(@NotNull final FilePath path, @NotNull final T rev) { + new CollectChangesTask("Collecting affected changes...") { + + @NotNull + @Override + public List<Change> getChanges() throws VcsException { + return getAffectedChanges(path, rev); + } + + @NotNull + @Override + public String getDialogTitle() { + return getAffectedChangesDialogTitle(path, rev); + } + }.queue(); + } + + // rev2 == null -> compare rev1 with local + // rev2 != null -> compare rev1 with rev2 + @NotNull + protected abstract List<Change> getChangesBetweenRevisions(@NotNull final FilePath path, @NotNull final T rev1, @Nullable final T rev2) + throws VcsException; + + @NotNull + protected abstract List<Change> getAffectedChanges(@NotNull final FilePath path, @NotNull final T rev) throws VcsException; + + @NotNull + protected abstract String getPresentableName(@NotNull T revision); + + protected void showChangesDialog(@NotNull String title, @NotNull List<Change> changes) { + DialogBuilder dialogBuilder = new DialogBuilder(myProject); + + dialogBuilder.setTitle(title); + dialogBuilder.setActionDescriptors(new DialogBuilder.ActionDescriptor[]{new DialogBuilder.CloseDialogAction()}); + final ChangesBrowser changesBrowser = + new ChangesBrowser(myProject, null, changes, null, false, true, null, ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); + changesBrowser.setChangesToDisplay(changes); + dialogBuilder.setCenterPanel(changesBrowser); + dialogBuilder.showNotModal(); + } + + protected void showError(@NotNull VcsException e, @NotNull String logMessage) { + LOG.info(logMessage, e); + VcsBalloonProblemNotifier.showOverVersionControlView(myProject, e.getMessage(), MessageType.ERROR); + } + + @NotNull + protected String getChangesBetweenRevisionsDialogTitle(@NotNull final FilePath path, @NotNull final T rev1, @Nullable final T rev2) { + String rev1Title = getPresentableName(rev1); + + return rev2 != null + ? String.format("Difference between %s and %s in %s", rev1Title, getPresentableName(rev2), path.getName()) + : String.format("Difference between %s and local version in %s", rev1Title, path.getName()); + } + + @NotNull + protected String getAffectedChangesDialogTitle(@NotNull final FilePath path, @NotNull final T rev) { + return String.format("Initial commit %s in %s", getPresentableName(rev), path.getName()); + } + + protected abstract class CollectChangesTask extends Task.Backgroundable { + + private List<Change> myChanges; + + public CollectChangesTask(@NotNull String title) { + super(BaseDiffFromHistoryHandler.this.myProject, title); + } + + @Override + public void run(@NotNull ProgressIndicator indicator) { + try { + myChanges = getChanges(); + } + catch (VcsException e) { + showError(e, "Error during task: " + getDialogTitle()); + } + } + + @NotNull + public abstract List<Change> getChanges() throws VcsException; + + @NotNull + public abstract String getDialogTitle(); + + @Override + public void onSuccess() { + showChangesDialog(getDialogTitle(), ContainerUtil.notNullize(myChanges)); + } + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/DefaultFileIndexFacade.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/DefaultFileIndexFacade.java index a63bbdbf0a69..d4063478d373 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/DefaultFileIndexFacade.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/DefaultFileIndexFacade.java @@ -66,6 +66,11 @@ public class DefaultFileIndexFacade extends FileIndexFacade { } @Override + public boolean isUnderIgnored(@NotNull VirtualFile file) { + return false; + } + + @Override public Module getModuleForFile(@NotNull VirtualFile file) { return null; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java index 5cc3a8a9ca92..e699383321ae 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java @@ -132,7 +132,7 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme myBackgroundableActionHandlerMap = new EnumMap<VcsBackgroundableActions, BackgroundableActionEnabledHandler>(VcsBackgroundableActions.class); myInitialization = new VcsInitialization(myProject); - myMappings = new NewMappings(myProject, myMessageBus, this, manager, excludedFileIndex); + myMappings = new NewMappings(myProject, myMessageBus, this, manager); myMappingsToRoots = new MappingsToRoots(myMappings, myProject); if (!myProject.isDefault()) { @@ -843,12 +843,24 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme @Override public Boolean compute() { return vf != null && (myExcludedIndex.isInContent(vf) || isFileInBaseDir(vf) || vf.equals(myProject.getBaseDir()) || - hasExplicitMapping(vf) || isInDirectoryBasedRoot(vf)) && !myExcludedIndex.isExcludedFile(vf); + hasExplicitMapping(vf) || isInDirectoryBasedRoot(vf) + || !Registry.is("ide.hide.excluded.files") && myExcludedIndex.isExcludedFile(vf)) + && !isIgnored(vf); } }); } @Override + public boolean isIgnored(VirtualFile vf) { + if (Registry.is("ide.hide.excluded.files")) { + return myExcludedIndex.isExcludedFile(vf); + } + else { + return myExcludedIndex.isUnderIgnored(vf); + } + } + + @Override public boolean dvcsUsedInProject() { AbstractVcs[] allActiveVcss = getAllActiveVcss(); for (AbstractVcs activeVcs : allActiveVcss) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java index 122988896cb2..cfddcaa3e65d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java @@ -36,14 +36,17 @@ public class VcsRootIterator { // folder path to files to be excluded private final Map<String, MyRootFilter> myOtherVcsFolders; private final FileIndexFacade myExcludedFileIndex; + private final ProjectLevelVcsManager myVcsManager; + private final Project myProject; public VcsRootIterator(final Project project, final AbstractVcs vcs) { - final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(project); + myProject = project; + myVcsManager = ProjectLevelVcsManager.getInstance(project); myOtherVcsFolders = new HashMap<String, MyRootFilter>(); myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, FileIndexFacade.class); - final VcsRoot[] allRoots = plVcsManager.getAllVcsRoots(); - final VirtualFile[] roots = plVcsManager.getRootsUnderVcs(vcs); + final VcsRoot[] allRoots = myVcsManager.getAllVcsRoots(); + final VirtualFile[] roots = myVcsManager.getRootsUnderVcs(vcs); for (VirtualFile root : roots) { final MyRootFilter rootPresentFilter = new MyRootFilter(root, vcs.getName()); rootPresentFilter.init(allRoots); @@ -57,14 +60,14 @@ public class VcsRootIterator { if ((rootFilter != null) && (!rootFilter.accept(file))) { return false; } - return !isExcluded(myExcludedFileIndex, file); + return !isIgnoredByVcs(myVcsManager, myProject, file); } - private static boolean isExcluded(final FileIndexFacade indexFacade, final VirtualFile file) { + private static boolean isIgnoredByVcs(final ProjectLevelVcsManager vcsManager, final Project project, final VirtualFile file) { return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { - return indexFacade.isExcludedFile(file); + return !project.isDisposed() && vcsManager.isIgnored(file); } }); } @@ -140,7 +143,7 @@ public class VcsRootIterator { @Nullable private final VirtualFileFilter myDirectoryFilter; private final VirtualFile myRoot; private final MyRootFilter myRootPresentFilter; - private final FileIndexFacade myExcludedFileIndex; + private final ProjectLevelVcsManager myVcsManager; private MyRootIterator(final Project project, final VirtualFile root, @@ -153,13 +156,12 @@ public class VcsRootIterator { myDirectoryFilter = directoryFilter; myRoot = root; - final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(project); - final AbstractVcs vcs = plVcsManager.getVcsFor(root); - myRootPresentFilter = (vcs == null) ? null : new MyRootFilter(root, vcs.getName()); + myVcsManager = ProjectLevelVcsManager.getInstance(project); + final AbstractVcs vcs = myVcsManager.getVcsFor(root); + myRootPresentFilter = vcs == null ? null : new MyRootFilter(root, vcs.getName()); if (myRootPresentFilter != null) { - myRootPresentFilter.init(ProjectLevelVcsManager.getInstance(myProject).getAllVcsRoots()); + myRootPresentFilter.init(myVcsManager.getAllVcsRoots()); } - myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, FileIndexFacade.class); } public void iterate() { @@ -174,7 +176,7 @@ public class VcsRootIterator { @NotNull @Override public Result visitFileEx(@NotNull VirtualFile file) { - if (isExcluded(myExcludedFileIndex, file)) return SKIP_CHILDREN; + if (isIgnoredByVcs(myVcsManager, myProject, file)) return SKIP_CHILDREN; if (myRootPresentFilter != null && !myRootPresentFilter.accept(file)) return SKIP_CHILDREN; if (myProject.isDisposed() || !process(file)) return skipTo(myRoot); if (myDirectoryFilter != null && file.isDirectory() && !myDirectoryFilter.shouldGoIntoDirectory(file)) return SKIP_CHILDREN; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java index 32fe920fc4db..5ff541ebc67d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java @@ -19,7 +19,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Pair; @@ -52,18 +51,18 @@ public class NewMappings { private final DefaultVcsRootPolicy myDefaultVcsRootPolicy; private final MessageBus myMessageBus; + private final ProjectLevelVcsManager myVcsManager; private final FileStatusManager myFileStatusManager; - private final FileIndexFacade myFileIndexFacade; private final Project myProject; private boolean myActivated; - public NewMappings(final Project project, final MessageBus messageBus, - final ProjectLevelVcsManagerImpl vcsManager, FileStatusManager fileStatusManager, FileIndexFacade fileIndexFacade) { + public NewMappings(final Project project, final MessageBus messageBus, final ProjectLevelVcsManagerImpl vcsManager, + FileStatusManager fileStatusManager) { myProject = project; myMessageBus = messageBus; + myVcsManager = vcsManager; myFileStatusManager = fileStatusManager; - myFileIndexFacade = fileIndexFacade; myLock = new Object(); myVcsToPaths = new HashMap<String, List<VcsDirectoryMapping>>(); myFileWatchRequestsManager = new FileWatchRequestsManager(myProject, this, LocalFileSystem.getInstance()); @@ -235,7 +234,7 @@ public class NewMappings { @Nullable public VcsDirectoryMapping getMappingFor(final VirtualFile file, final Object parentModule) { // if parentModule is not null it means that file belongs to the module so it isn't excluded - if (parentModule == null && myFileIndexFacade.isExcludedFile(file)) { + if (parentModule == null && myVcsManager.isIgnored(file)) { return null; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java index 2769b3ca84cb..bb88f3dc3260 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java @@ -16,23 +16,21 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -/** - * @author Nadya Zabrodina - */ public class VcsRootErrorsFinder { - private final @NotNull Project myProject; - private final @NotNull ProjectLevelVcsManager myVcsManager; + @NotNull private final Project myProject; + @NotNull private final ProjectLevelVcsManager myVcsManager; + @NotNull private final VcsRootDetector myRootDetector; public VcsRootErrorsFinder(@NotNull Project project) { myProject = project; myVcsManager = ProjectLevelVcsManager.getInstance(project); + myRootDetector = ServiceManager.getService(myProject, VcsRootDetector.class); } @NotNull public Collection<VcsRootError> find() { List<VcsDirectoryMapping> mappings = myVcsManager.getDirectoryMappings(); - Collection<VcsRoot> vcsRoots = ServiceManager.getService(myProject, VcsRootDetector.class).detect(); - + Collection<VcsRoot> vcsRoots = myRootDetector.detect(); Collection<VcsRootError> errors = new ArrayList<VcsRootError>(); errors.addAll(findExtraMappings(mappings)); errors.addAll(findUnregisteredRoots(mappings, vcsRoots)); |