diff options
Diffstat (limited to 'platform/vcs-impl/src')
23 files changed, 370 insertions, 296 deletions
diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java index dfce14728906..7db646c94b5b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -43,6 +43,7 @@ import com.intellij.ui.components.JBLoadingPanel; import com.intellij.ui.table.JBTable; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.StatusText; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -826,6 +827,7 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode return true; } + @NotNull @Override public String getDoNotShowMessage() { return "Do not ask me again"; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/CommitCompletionContributor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/CommitCompletionContributor.java index 5bcb5fbf165d..0b09f753168f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/CommitCompletionContributor.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/CommitCompletionContributor.java @@ -29,6 +29,7 @@ import com.intellij.openapi.vcs.ui.CommitMessage; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.ui.TextFieldWithAutoCompletionListProvider; +import org.jetbrains.annotations.NotNull; /** * @author Dmitry Avdeev @@ -36,7 +37,7 @@ import com.intellij.ui.TextFieldWithAutoCompletionListProvider; public class CommitCompletionContributor extends CompletionContributor { @Override - public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) { + public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) { PsiFile file = parameters.getOriginalFile(); Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); if (document != null) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java index 97f5277ab6e5..025795eb08ed 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java @@ -171,7 +171,8 @@ public class ChangesFragmentedDiffPanel implements Disposable { descriptor = new OpenFileDescriptor(myProject, myFragmentedContent.getFile(), converted, position.column); } else { if (((DiffPanelImpl) panel).getEditor1().getDocument().getTextLength() == 0) { - FileEditorManager.getInstance(myProject).openTextEditor(new OpenFileDescriptor(myProject, myFragmentedContent.getFile(), 0), true); + FileEditorManager.getInstance(myProject).openTextEditor(new OpenFileDescriptor(myProject, myFragmentedContent.getFile(), 0), + true); return; } @@ -281,11 +282,13 @@ public class ChangesFragmentedDiffPanel implements Disposable { FragmentedEditorHighlighter bh = fragmentedContent.getBeforeHighlighter(); if (bh != null) { - ((EditorEx) ((DiffPanelImpl) currentPanel).getEditor1()).setHighlighter(bh); + ((EditorEx) ((DiffPanelImpl) myHorizontal).getEditor1()).setHighlighter(bh); + ((EditorEx) ((DiffPanelImpl) myVertical).getEditor1()).setHighlighter(bh); } FragmentedEditorHighlighter ah = fragmentedContent.getAfterHighlighter(); if (ah != null) { - ((EditorEx) ((DiffPanelImpl) currentPanel).getEditor2()).setHighlighter(ah); + ((EditorEx) ((DiffPanelImpl) myHorizontal).getEditor2()).setHighlighter(ah); + ((EditorEx) ((DiffPanelImpl) myVertical).getEditor2()).setHighlighter(ah); } if (((DiffPanelImpl) currentPanel).getEditor1() != null) { highlightTodo(true, fragmentedContent.getBeforeTodoRanges()); @@ -335,7 +338,7 @@ public class ChangesFragmentedDiffPanel implements Disposable { final DiffPanel diffPanel = new DiffPanelImpl(null, myProject, false, horizontal, SHORT_DIFF_DIVIDER_POLYGONS_OFFSET, null) { @Override protected DiffPanelState createDiffPanelState(@NotNull Disposable parentDisposable) { - return new FragmentedDiffPanelState(this, myProject, ! horizontal, parentDisposable); + return new FragmentedDiffPanelState(this, myProject, getDiffDividerPolygonsOffset(), ! horizontal, parentDisposable); } }; diffPanel.enableToolbar(false); @@ -403,7 +406,7 @@ public class ChangesFragmentedDiffPanel implements Disposable { } private static final Icon ourIcon = PlatformIcons.CHECK_ICON; - + private class PopupAction extends DumbAwareAction { private final AnAction myUsual; private final AnAction myNumbered; @@ -680,7 +683,7 @@ public class ChangesFragmentedDiffPanel implements Disposable { private class MyNextDiffAction extends DumbAwareAction { private boolean myEnabled; - + private MyNextDiffAction() { super("Next Change", "Next Change", AllIcons.Actions.NextOccurence); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsConfirmationDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsConfirmationDialog.java index 5b3860523a91..00c9c6c1a0c5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsConfirmationDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsConfirmationDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -36,7 +36,7 @@ public class VcsConfirmationDialog extends OptionsDialog { private final String myMessage; private final String myDoNotShowMessage; - protected VcsConfirmationDialog(Project project, VcsShowConfirmationOption option, String message, String doNotShowMessage) { + protected VcsConfirmationDialog(Project project, VcsShowConfirmationOption option, String message, @NotNull String doNotShowMessage) { super(project); myOption = option; myMessage = message; @@ -68,6 +68,7 @@ public class VcsConfirmationDialog extends OptionsDialog { return panel; } + @NotNull @Override protected String getDoNotShowMessage() { return myDoNotShowMessage; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/BrowseChangesAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/BrowseChangesAction.java index 87bb5a338ca7..521071b0faf4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/BrowseChangesAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/BrowseChangesAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -41,7 +41,12 @@ public class BrowseChangesAction extends AnAction implements DumbAware { assert vcs != null; final CommittedChangesProvider provider = vcs.getCommittedChangesProvider(); assert provider != null; - ChangeBrowserSettings settings = provider.createDefaultSettings(); + final VcsConfiguration vcsConfiguration = VcsConfiguration.getInstance(project); + ChangeBrowserSettings settings = vcsConfiguration.CHANGE_BROWSER_SETTINGS.get(vcs.getName()); + if (settings == null) { + settings = provider.createDefaultSettings(); + vcsConfiguration.CHANGE_BROWSER_SETTINGS.put(vcs.getName(), settings); + } CommittedChangesFilterDialog dlg = new CommittedChangesFilterDialog(project, provider.createFilterUI(true), settings); dlg.show(); if (!dlg.isOK()) return; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/conflicts/ChangelistConflictNotificationProvider.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/conflicts/ChangelistConflictNotificationProvider.java index 99c8d796c38b..60750b1cdbad 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/conflicts/ChangelistConflictNotificationProvider.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/conflicts/ChangelistConflictNotificationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -20,6 +20,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotifications; +import org.jetbrains.annotations.NotNull; /** * @author Dmitry Avdeev @@ -34,11 +35,14 @@ public class ChangelistConflictNotificationProvider extends EditorNotifications. myConflictTracker = changeListManager.getConflictTracker(); } + @Override + @NotNull public Key<ChangelistConflictNotificationPanel> getKey() { return KEY; } - public ChangelistConflictNotificationPanel createNotificationPanel(VirtualFile file, FileEditor fileEditor) { + @Override + public ChangelistConflictNotificationPanel createNotificationPanel(@NotNull VirtualFile file, @NotNull FileEditor fileEditor) { return myConflictTracker.hasConflict(file) ? ChangelistConflictNotificationPanel.create(myConflictTracker, file) : null; } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java index c213feb38c40..e76ba194672e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java @@ -294,7 +294,9 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD } private void notifyStateChanged() { - myBus.syncPublisher(SHELF_TOPIC).stateChanged(new ChangeEvent(this)); + if (!myProject.isDisposed()) { + myBus.syncPublisher(SHELF_TOPIC).stateChanged(new ChangeEvent(this)); + } } private File getPatchPath(@NonNls final String commitMessage) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java index ffa8b2a97fc5..497db3da7d9f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java @@ -85,7 +85,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj private String myLastKnownComment = ""; private final boolean myAllOfDefaultChangeListChangesIncluded; @NonNls private static final String SPLITTER_PROPORTION_OPTION = "CommitChangeListDialog.SPLITTER_PROPORTION_" + LAYOUT_VERSION; - private final Action[] myExecutorActions; + private final CommitExecutorAction[] myExecutorActions; private final boolean myShowVcsCommit; private final Map<AbstractVcs, JPanel> myPerVcsOptionsPanels = new HashMap<AbstractVcs, JPanel>(); @@ -103,7 +103,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj private final PseudoMap<Object, Object> myAdditionalData; private String myHelpId; - + private SplitterWithSecondHideable myDetailsSplitter; private static final String DETAILS_SPLITTER_PROPORTION_OPTION = "CommitChangeListDialog.DETAILS_SPLITTER_PROPORTION_" + LAYOUT_VERSION; private static final String DETAILS_SHOW_OPTION = "CommitChangeListDialog.DETAILS_SHOW_OPTION_"; @@ -142,9 +142,15 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj private final MyUpdateButtonsRunnable myUpdateButtonsRunnable = new MyUpdateButtonsRunnable(this); - private static boolean commit(final Project project, final List<Change> changes, final LocalChangeList initialSelection, - final List<CommitExecutor> executors, final boolean showVcsCommit, final String comment, - @Nullable CommitResultHandler customResultHandler) { + public static boolean commitChanges(final Project project, final List<Change> changes, final LocalChangeList initialSelection, + final List<CommitExecutor> executors, final boolean showVcsCommit, final String comment, + @Nullable CommitResultHandler customResultHandler, boolean cancelIfNoChanges) { + if (cancelIfNoChanges && changes.isEmpty() && !ApplicationManager.getApplication().isUnitTestMode()) { + Messages.showInfoMessage(project, VcsBundle.message("commit.dialog.no.changes.detected.text"), + VcsBundle.message("commit.dialog.no.changes.detected.title")); + return false; + } + for (BaseCheckinHandlerFactory factory : getCheckInFactories(project)) { BeforeCheckinDialogHandler handler = factory.createSystemReadyHandler(project); if (handler != null && !handler.beforeCommitDialogShown(project, changes, executors, showVcsCommit)) { @@ -208,13 +214,8 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj public static boolean commitChanges(final Project project, final Collection<Change> changes, final LocalChangeList initialSelection, final List<CommitExecutor> executors, final boolean showVcsCommit, final String comment, @Nullable CommitResultHandler customResultHandler) { - if (changes.isEmpty() && !ApplicationManager.getApplication().isUnitTestMode()) { - Messages.showInfoMessage(project, VcsBundle.message("commit.dialog.no.changes.detected.text") , - VcsBundle.message("commit.dialog.no.changes.detected.title")); - return false; - } - - return commit(project, new ArrayList<Change>(changes), initialSelection, executors, showVcsCommit, comment, customResultHandler); + return commitChanges(project, new ArrayList<Change>(changes), initialSelection, executors, showVcsCommit, comment, + customResultHandler, true); } public static void commitAlienChanges(final Project project, final List<Change> changes, final AbstractVcs vcs, @@ -317,7 +318,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj myZipperUpdater.queue(myRefreshDetails); } }); - + myBrowserExtender.addToolbarActions(this); myBrowserExtender.addSelectedListChangeListener(new SelectedListChangeListener() { @@ -447,7 +448,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj restoreState(); if (myExecutors != null) { - myExecutorActions = new Action[myExecutors.size()]; + myExecutorActions = new CommitExecutorAction[myExecutors.size()]; for (int i = 0; i < myExecutors.size(); i++) { final CommitExecutor commitExecutor = myExecutors.get(i); @@ -466,10 +467,10 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj init(); updateButtons(); updateVcsOptionsVisibility(); - + updateOnListSelection(); myCommitMessageArea.requestFocusInMessage(); - + for (EditChangelistSupport support : Extensions.getExtensions(EditChangelistSupport.EP_NAME, project)) { support.installSearch(myCommitMessageArea.getEditorField(), myCommitMessageArea.getEditorField()); } @@ -829,7 +830,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj if (configuration != null) { configuration.CHECK_COMMIT_MESSAGE_SPELLING = checkSpelling; } - myCommitMessageArea.setCheckSpelling(checkSpelling); + myCommitMessageArea.setCheckSpelling(checkSpelling); } private boolean checkComment() { @@ -853,7 +854,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj myDisposed = false; myUpdateButtonsRunnable.restart(this); } - + private CheckinHandler.ReturnResult runBeforeCommitHandlers(final Runnable okAction, final CommitExecutor executor) { final Computable<CheckinHandler.ReturnResult> proceedRunnable = new Computable<CheckinHandler.ReturnResult>() { @Override @@ -1244,8 +1245,8 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj myCommitAction.setEnabled(enabled); } if (myExecutorActions != null) { - for (Action executorAction : myExecutorActions) { - executorAction.setEnabled(enabled); + for (CommitExecutorAction executorAction : myExecutorActions) { + executorAction.updateEnabled(enabled); } } myOKButtonUpdateAlarm.cancelAllRequests(); @@ -1268,7 +1269,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj protected String getDimensionServiceKey() { return "CommitChangelistDialog" + LAYOUT_VERSION; } - + @Override public JComponent getPreferredFocusedComponent() { return myCommitMessageArea.getEditorField(); @@ -1323,6 +1324,11 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj callExecutor.run(); } } + + public void updateEnabled(boolean hasDiffs) { + setEnabled(hasDiffs + || (myCommitExecutor instanceof CommitExecutorBase) && !((CommitExecutorBase)myCommitExecutor).areChangesRequired()); + } } private static class DiffCommitMessageEditor extends CommitMessage implements Disposable { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java index 2e34d7819e77..19b1420ddda9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java @@ -41,6 +41,7 @@ import com.intellij.openapi.vcs.checkin.CheckinHandler; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vcs.update.RefreshVFsSynchronously; import com.intellij.util.Consumer; +import com.intellij.util.Function; import com.intellij.util.NullableFunction; import com.intellij.util.WaitForProgressToShow; import com.intellij.util.concurrency.Semaphore; @@ -581,7 +582,7 @@ public class CommitHelper { } else { if (myCustomResultHandler == null) { - showErrorDialogAndMoveToAnotherList(processor, errorsSize, warningsSize); + showErrorDialogAndMoveToAnotherList(processor, errorsSize, warningsSize, errors); } else { myCustomResultHandler.onFailure(); @@ -589,19 +590,26 @@ public class CommitHelper { } } - private void showErrorDialogAndMoveToAnotherList(final GeneralCommitProcessor processor, final int errorsSize, final int warningsSize) { + private void showErrorDialogAndMoveToAnotherList(final GeneralCommitProcessor processor, final int errorsSize, final int warningsSize, + @NotNull final List<VcsException> errors) { WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() { public void run() { - final String message; + String message; if (errorsSize > 0 && warningsSize > 0) { message = VcsBundle.message("message.text.commit.failed.with.errors.and.warnings"); } else if (errorsSize > 0) { - message = VcsBundle.message("message.text.commit.failed.with.errors"); + message = StringUtil.pluralize(VcsBundle.message("message.text.commit.failed.with.error"), errorsSize); } else { - message = VcsBundle.message("message.text.commit.finished.with.warnings"); + message = StringUtil.pluralize(VcsBundle.message("message.text.commit.finished.with.warning"), warningsSize); } + message += ":\n" + StringUtil.join(errors, new Function<VcsException, String>() { + @Override + public String fun(VcsException e) { + return e.getMessage(); + } + }, "\n"); //new VcsBalloonProblemNotifier(myProject, message, MessageType.ERROR).run(); Messages.showErrorDialog(message, VcsBundle.message("message.title.commit")); 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 new file mode 100644 index 000000000000..fe9c12036596 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/FilePathChangesTreeList.java @@ -0,0 +1,52 @@ +/* + * 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.changes.ui; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.FilePath; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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) { + return new TreeModelBuilder(myProject, false).buildModelFromFilePaths(changes); + } + + protected List<FilePath> getSelectedObjects(final ChangesBrowserNode<FilePath> node) { + return node.getAllFilePathsUnder(); + } + + @Nullable + protected FilePath getLeadSelectedObject(final ChangesBrowserNode node) { + final Object userObject = node.getUserObject(); + if (userObject instanceof FilePath) { + return (FilePath) userObject; + } + return null; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilePathsDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilePathsDialog.java index b27dc2e64d63..61bcd6ea2ae6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilePathsDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilePathsDialog.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.tree.DefaultTreeModel; import java.util.Collection; import java.util.List; @@ -38,24 +37,7 @@ public class SelectFilePathsDialog extends AbstractSelectFilesDialog<FilePath> { final VcsShowConfirmationOption confirmationOption, @Nullable String okActionName, @Nullable String cancelActionName, boolean showDoNotAskOption) { super(project, false, confirmationOption, prompt, showDoNotAskOption); - myFileList = new ChangesTreeList<FilePath>(project, originalFiles, true, true, null, null) { - protected DefaultTreeModel buildTreeModel(final List<FilePath> changes, ChangeNodeDecorator changeNodeDecorator) { - return new TreeModelBuilder(project, false).buildModelFromFilePaths(changes); - } - - protected List<FilePath> getSelectedObjects(final ChangesBrowserNode node) { - return node.getAllFilePathsUnder(); - } - - @Nullable - protected FilePath getLeadSelectedObject(final ChangesBrowserNode node) { - final Object userObject = node.getUserObject(); - if (userObject instanceof FilePath) { - return (FilePath) userObject; - } - return null; - } - }; + myFileList = new FilePathChangesTreeList(project, originalFiles, true, true, null, null); if (okActionName != null) { getOKAction().putValue(Action.NAME, okActionName); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilesDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilesDialog.java index 6c139f9d069f..8806e4544a9c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilesDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/SelectFilesDialog.java @@ -93,7 +93,7 @@ public class SelectFilesDialog extends AbstractSelectFilesDialog<VirtualFile> { return defaultGroup; } - private static class VirtualFileList extends ChangesTreeList<VirtualFile> { + public static class VirtualFileList extends ChangesTreeList<VirtualFile> { private final Project myProject; @Nullable private final DeleteProvider myDeleteProvider; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurable.java index 587628a27c0b..304275d732d7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurable.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurable.java @@ -78,6 +78,11 @@ public class VcsManagerConfigurable extends SearchableConfigurable.Parent.Abstra } @Override + public boolean isVisible() { + return ProjectLevelVcsManager.getInstance(myProject).getAllVcss().length > 0; + } + + @Override public void disposeUIResources() { super.disposeUIResources(); if (myMappings != null) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsUpdateInfoScopeFilterConfigurable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsUpdateInfoScopeFilterConfigurable.java index e43a499f9a33..3ddfe8d9b188 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsUpdateInfoScopeFilterConfigurable.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsUpdateInfoScopeFilterConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -22,6 +22,7 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.newEditor.OptionsEditor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.VcsConfiguration; @@ -31,6 +32,7 @@ import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -42,28 +44,25 @@ import java.awt.*; * @author Kirill Likhodedov */ class VcsUpdateInfoScopeFilterConfigurable implements Configurable, NamedScopesHolder.ScopeListener { - private final JCheckBox myCheckbox; private final JComboBox myComboBox; - private final Project myProject; private final VcsConfiguration myVcsConfiguration; private final NamedScopesHolder[] myNamedScopeHolders; VcsUpdateInfoScopeFilterConfigurable(Project project, VcsConfiguration vcsConfiguration) { - myProject = project; myVcsConfiguration = vcsConfiguration; myCheckbox = new JCheckBox(VcsBundle.getString("settings.filter.update.project.info.by.scope")); - myComboBox = new JComboBox(); + myComboBox = new ComboBox(); myComboBox.setEnabled(myCheckbox.isSelected()); myCheckbox.addChangeListener(new ChangeListener() { @Override - public void stateChanged(ChangeEvent e) { + public void stateChanged(@NotNull ChangeEvent e) { myComboBox.setEnabled(myCheckbox.isSelected()); } }); - myNamedScopeHolders = NamedScopesHolder.getAllNamedScopeHolders(myProject); + myNamedScopeHolders = NamedScopesHolder.getAllNamedScopeHolders(project); for (NamedScopesHolder holder : myNamedScopeHolders) { holder.addScopeListener(this); } @@ -93,12 +92,12 @@ class VcsUpdateInfoScopeFilterConfigurable implements Configurable, NamedScopesH panel.add(myCheckbox); panel.add(myComboBox); panel.add(Box.createHorizontalStrut(UIUtil.DEFAULT_HGAP)); - panel.add(new LinkLabel("Edit scopes", null, new LinkListener() { + panel.add(new LinkLabel("Manage Scopes", null, new LinkListener() { @Override public void linkSelected(LinkLabel aSource, Object aLinkData) { - final OptionsEditor optionsEditor = OptionsEditor.KEY.getData(DataManager.getInstance().getDataContext(panel)); + OptionsEditor optionsEditor = OptionsEditor.KEY.getData(DataManager.getInstance().getDataContext(panel)); if (optionsEditor != null) { - SearchableConfigurable configurable = optionsEditor.findConfigurableById(new ScopeChooserConfigurable(myProject).getId()); + SearchableConfigurable configurable = optionsEditor.findConfigurableById(ScopeChooserConfigurable.PROJECT_SCOPES); if (configurable != null) { optionsEditor.select(configurable); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java index bf71a2ffee7c..d6362ffe19c9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.ex; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -27,7 +28,7 @@ import java.util.List; public class DocumentWrapper { private final Document myDocument; - public DocumentWrapper(Document document) { + public DocumentWrapper(@NotNull Document document) { myDocument = document; } @@ -35,10 +36,12 @@ public class DocumentWrapper { return myDocument.getLineNumber(offset); } + @NotNull public List<String> getLines() { return getLines(0, myDocument.getLineCount() - 1); } + @NotNull public List<String> getLines(int from, int to) { ArrayList<String> result = new ArrayList<String>(); for (int i = from; i <= to; i++) { @@ -54,6 +57,7 @@ public class DocumentWrapper { return result; } + @NotNull private String getLine(final int i) { TextRange range = new TextRange(myDocument.getLineStartOffset(i), myDocument.getLineEndOffset(i)); if (range.getLength() < 0) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 548cc514b300..ac0bc8608368 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -38,26 +38,26 @@ import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotificationPanel; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** * @author irengrig - * author: lesya + * author: lesya */ public class LineStatusTracker { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.ex.LineStatusTracker"); - private static final Key<CanNotCalculateDiffPanel> PANEL_KEY = new Key<CanNotCalculateDiffPanel>("LineStatusTracker.CanNotCalculateDiffPanel"); + private static final Key<CanNotCalculateDiffPanel> PANEL_KEY = + new Key<CanNotCalculateDiffPanel>("LineStatusTracker.CanNotCalculateDiffPanel"); private final Object myLock = new Object(); - // true -> have contents private BaseLoadState myBaseLoaded; private final Document myDocument; @@ -71,15 +71,17 @@ public class LineStatusTracker { private boolean myBulkUpdate; private final Application myApplication; - @Nullable - private RevisionPack myBaseRevisionNumber; + @Nullable private RevisionPack myBaseRevisionNumber; private String myPreviousBaseRevision; private boolean myAnathemaThrown; private FileEditorManager myFileEditorManager; private final VirtualFile myVirtualFile; private boolean myReleased = false; - private LineStatusTracker(final Document document, final Document upToDateDocument, final Project project, final VirtualFile virtualFile) { + private LineStatusTracker(@NotNull final Document document, + @NotNull final Document upToDateDocument, + final Project project, + @Nullable final VirtualFile virtualFile) { myVirtualFile = virtualFile; myApplication = ApplicationManager.getApplication(); myDocument = document; @@ -156,7 +158,7 @@ public class LineStatusTracker { } private void removeAnathema() { - if (! myAnathemaThrown) return; + if (!myAnathemaThrown) return; myAnathemaThrown = false; final FileEditor[] editors = myFileEditorManager.getEditors(myVirtualFile); for (FileEditor editor : editors) { @@ -171,6 +173,7 @@ public class LineStatusTracker { @SuppressWarnings({"AutoBoxing"}) private RangeHighlighter createHighlighter(final Range range) { LOG.assertTrue(!myReleased, "Already released"); + int first = range.getOffset1() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset1()); @@ -179,6 +182,7 @@ public class LineStatusTracker { final RangeHighlighter highlighter = DocumentMarkupModel.forDocument(myDocument, myProject, true) .addRangeHighlighter(first, second, HighlighterLayer.FIRST - 1, null, HighlighterTargetArea.LINES_IN_RANGE); + final TextAttributes attr = LineStatusTrackerDrawing.getAttributesFor(range); highlighter.setErrorStripeMarkColor(attr.getErrorStripeColor()); highlighter.setThinErrorStripeMark(true); @@ -186,14 +190,21 @@ public class LineStatusTracker { highlighter.setGreedyToRight(true); highlighter.setLineMarkerRenderer(LineStatusTrackerDrawing.createRenderer(range, this)); highlighter.setEditorFilter(MarkupEditorFilterFactory.createIsNotDiffFilter()); - final int line1 = myDocument.getLineNumber(first); - final int line2 = myDocument.getLineNumber(second); + final String tooltip; - if (line1 == line2) { - tooltip = VcsBundle.message("tooltip.text.line.changed", line1); + if (range.getOffset1() == range.getOffset2()) { + if (range.getUOffset1() + 1 == range.getUOffset2()) { + tooltip = VcsBundle.message("tooltip.text.line.before.deleted", range.getOffset1() + 1); + } + else { + tooltip = VcsBundle.message("tooltip.text.lines.before.deleted", range.getOffset1() + 1, range.getUOffset2() - range.getUOffset1()); + } + } + else if (range.getOffset1() + 1 == range.getOffset2()) { + tooltip = VcsBundle.message("tooltip.text.line.changed", range.getOffset1() + 1); } else { - tooltip = VcsBundle.message("tooltip.text.lines.changed", line1, line2); + tooltip = VcsBundle.message("tooltip.text.lines.changed", range.getOffset1() + 1, range.getOffset2()); } highlighter.setErrorStripeTooltip(tooltip); @@ -285,11 +296,15 @@ public class LineStatusTracker { } private class MyDocumentListener extends DocumentAdapter { + // We have 3 document versions: + // * VCS version - upToDate* + // * before change - my* + // * after change - current* + private int myFirstChangedLine; - private int myUpToDateFirstLine; - private int myUpToDateLastLine; private int myLastChangedLine; - private int myLinesBeforeChange; + private int myChangedLines; + private int myTotalLines; private final VcsDirtyScopeManager myVcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject); @Override @@ -302,50 +317,15 @@ public class LineStatusTracker { try { myFirstChangedLine = myDocument.getLineNumber(e.getOffset()); myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength()); + myChangedLines = myLastChangedLine - myFirstChangedLine; if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++; - - myLinesBeforeChange = myDocument.getLineNumber(e.getOffset() + e.getOldLength()) - myDocument.getLineNumber(e.getOffset()); - - Range firstChangedRange = getLastRangeBeforeLine(myFirstChangedLine); - - if (firstChangedRange == null) { - myUpToDateFirstLine = myFirstChangedLine; - } - else if (firstChangedRange.containsLine(myFirstChangedLine)) { - myFirstChangedLine = firstChangedRange.getOffset1(); - myUpToDateFirstLine = firstChangedRange.getUOffset1(); - } - else { - myUpToDateFirstLine = firstChangedRange.getUOffset2() + myFirstChangedLine - firstChangedRange.getOffset2(); - } - - Range myLastChangedRange = getLastRangeBeforeLine(myLastChangedLine); - - if (myLastChangedRange == null) { - myUpToDateLastLine = myLastChangedLine; - } - else if (myLastChangedRange.containsLine(myLastChangedLine)) { - myUpToDateLastLine = myLastChangedRange.getUOffset2(); - myLastChangedLine = myLastChangedRange.getOffset2(); - } - else { - myUpToDateLastLine = myLastChangedRange.getUOffset2() + myLastChangedLine - myLastChangedRange.getOffset2(); - } - } catch (ProcessCanceledException ignore) { + myTotalLines = e.getDocument().getLineCount(); + } + catch (ProcessCanceledException ignore) { } } } - @Nullable - private Range getLastRangeBeforeLine(int line) { - Range result = null; - for (Range range : myRanges) { - if (range.isAfter(line)) return result; - result = range; - } - return result; - } - @Override public void documentChanged(final DocumentEvent e) { myApplication.assertWriteAccessAllowed(); @@ -354,41 +334,46 @@ public class LineStatusTracker { if (myReleased) return; if (myBulkUpdate || myAnathemaThrown || BaseLoadState.LOADED != myBaseLoaded) return; try { + int currentChangedLines = myDocument.getLineNumber(e.getOffset() + e.getNewLength()) - myDocument.getLineNumber(e.getOffset()); + int linesShift = currentChangedLines - myChangedLines; + int upToDateTotalLine = myUpToDateDocument.getLineCount(); - int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength()); - int linesAfterChange = line - myDocument.getLineNumber(e.getOffset()); - int linesShift = linesAfterChange - myLinesBeforeChange; - - List<Range> rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine); - List<Range> rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine); + List<Range> rangesBeforeChange = new ArrayList<Range>(); + List<Range> rangesAfterChange = new ArrayList<Range>(); + List<Range> changedRanges = new ArrayList<Range>(); + sortRanges(myRanges, myFirstChangedLine, myLastChangedLine, rangesBeforeChange, changedRanges, rangesAfterChange); - List<Range> changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine); + Range firstChangedRange = ContainerUtil.getFirstItem(changedRanges); + Range lastChangedRange = ContainerUtil.getLastItem(changedRanges); + Range lastRangeBefore = ContainerUtil.getLastItem(rangesBeforeChange); + Range firstRangeAfter = ContainerUtil.getFirstItem(rangesAfterChange); - int newSize = rangesBeforeChange.size() + changedRanges.size() + rangesAfterChange.size(); - if (myRanges.size() != newSize) { - LOG.info("Ranges: " + myRanges + "; first changed line: " + myFirstChangedLine + "; last changed line: " + myLastChangedLine); - LOG.assertTrue(false); + if (firstChangedRange != null && firstChangedRange.getOffset1() < myFirstChangedLine) { + myFirstChangedLine = firstChangedRange.getOffset1(); + } + if (lastChangedRange != null && lastChangedRange.getOffset2() > myLastChangedLine) { + myLastChangedLine = lastChangedRange.getOffset2() - 1; } + int currentFirstLine = myFirstChangedLine; + int currentLastLine = myLastChangedLine + linesShift; - myLastChangedLine += linesShift; - + int upToDateFirstLine = getUpToDateLine1(lastRangeBefore, myFirstChangedLine); + int upToDateLastLine = getUpToDateLine2(firstRangeAfter, myLastChangedLine, myTotalLines, upToDateTotalLine); - List<Range> newChangedRanges = getNewChangedRanges(); + List<Range> newChangedRanges = getNewChangedRanges(currentFirstLine, currentLastLine, upToDateFirstLine, upToDateLastLine); shiftRanges(rangesAfterChange, linesShift); if (!changedRanges.equals(newChangedRanges)) { replaceRanges(changedRanges, newChangedRanges); - myRanges = new ArrayList<Range>(); + myRanges = new ArrayList<Range>(rangesBeforeChange.size() + newChangedRanges.size() + rangesAfterChange.size()); myRanges.addAll(rangesBeforeChange); myRanges.addAll(newChangedRanges); myRanges.addAll(rangesAfterChange); - myRanges = mergeRanges(myRanges); - for (Range range : myRanges) { if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range)); } @@ -410,49 +395,36 @@ public class LineStatusTracker { }); } } - } catch (ProcessCanceledException ignore) { - } catch (FilesTooBigForDiffException e1) { + } + catch (ProcessCanceledException ignore) { + } + catch (FilesTooBigForDiffException e1) { installAnathema(); removeHighlightersFromMarkupModel(); } } } - private List<Range> getNewChangedRanges() throws FilesTooBigForDiffException { - List<String> lines = new DocumentWrapper(myDocument).getLines(myFirstChangedLine, myLastChangedLine); - List<String> uLines = new DocumentWrapper(myUpToDateDocument) - .getLines(myUpToDateFirstLine, myUpToDateLastLine); - return new RangesBuilder(lines, uLines, myFirstChangedLine, myUpToDateFirstLine).getRanges(); + private int getUpToDateLine1(@Nullable Range range, int line) { + return range == null ? line : line + range.getUOffset2() - range.getOffset2(); } - private List<Range> mergeRanges(List<Range> ranges) { - ArrayList<Range> result = new ArrayList<Range>(); - Iterator<Range> iterator = ranges.iterator(); - if (!iterator.hasNext()) return result; - Range prev = iterator.next(); - while (iterator.hasNext()) { - Range range = iterator.next(); - if (prev.canBeMergedWith(range)) { - if (range.getHighlighter() != null) { - range.getHighlighter().dispose(); - } - if (prev.getHighlighter() != null) { - prev.getHighlighter().dispose(); - } - prev = prev.mergeWith(range); - } - else { - result.add(prev); - prev = range; - } - } - result.add(prev); - return result; + private int getUpToDateLine2(@Nullable Range range, int line, int totalLinesBefore, int totalLinesAfter) { + return range == null ? totalLinesAfter - totalLinesBefore + line : line + range.getUOffset1() - range.getOffset1(); + } + + private List<Range> getNewChangedRanges(int firstChangedLine, int lastChangedLine, int upToDateFirstLine, int upToDateLastLine) + throws FilesTooBigForDiffException { + List<String> lines = new DocumentWrapper(myDocument).getLines(firstChangedLine, lastChangedLine); + List<String> uLines = new DocumentWrapper(myUpToDateDocument).getLines(upToDateFirstLine, upToDateLastLine); + return new RangesBuilder(lines, uLines, firstChangedLine, upToDateFirstLine).getRanges(); } - private void replaceRanges(List<Range> rangesInChange, List<Range> newRangesInChange) { + private void replaceRanges(@NotNull List<Range> rangesInChange, @NotNull List<Range> newRangesInChange) { for (Range range : rangesInChange) { - range.getHighlighter().dispose(); + if (range.getHighlighter() != null) { + range.getHighlighter().dispose(); + } range.setHighlighter(null); } for (Range range : newRangesInChange) { @@ -460,25 +432,33 @@ public class LineStatusTracker { } } - private void shiftRanges(List<Range> rangesAfterChange, int shift) { + private void shiftRanges(@NotNull List<Range> rangesAfterChange, int shift) { for (final Range aRangesAfterChange : rangesAfterChange) { aRangesAfterChange.shift(shift); } } - - } - - private List<Range> getChangedRanges(int from, int to) { - return getChangedRanges(myRanges, from, to); } - public static List<Range> getChangedRanges(List<Range> ranges, int from, int to) { - ArrayList<Range> result = new ArrayList<Range>(); + public static void sortRanges(@NotNull List<Range> ranges, + int firstChangedLine, + int lastChangedLine, + @NotNull List<Range> rangesBeforeChange, + @NotNull List<Range> changedRanges, + @NotNull List<Range> rangesAfterChange) { for (Range range : ranges) { - if (range.getOffset1() <= to && range.getOffset2() >= from) result.add(range); -// if (range.getOffset1() > to) break; + int offset1 = range.getOffset1() - 1; + int offset2 = range.getOffset2(); + + if (offset2 < firstChangedLine) { + rangesBeforeChange.add(range); + } + else if (offset1 > lastChangedLine) { + rangesAfterChange.add(range); + } + else { + changedRanges.add(range); + } } - return result; } @Nullable @@ -525,7 +505,7 @@ public class LineStatusTracker { return getPrevRange(currentRange); } - for (ListIterator<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) { + for (ListIterator<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious(); ) { final Range range = iterator.previous(); if (range.getOffset1() > line) { continue; @@ -536,24 +516,6 @@ public class LineStatusTracker { } } - public static List<Range> getRangesBefore(List<Range> ranges, int line) { - ArrayList<Range> result = new ArrayList<Range>(); - - for (Range range : ranges) { - if (range.getOffset2() < line) result.add(range); - //if (range.getOffset2() > line) break; - } - return result; - } - - public static List<Range> getRangesAfter(List<Range> ranges, int line) { - ArrayList<Range> result = new ArrayList<Range>(); - for (Range range : ranges) { - if (range.getOffset1() > line) result.add(range); - } - return result; - } - @Nullable public Range getRangeForLine(final int line) { synchronized (myLock) { @@ -573,25 +535,33 @@ public class LineStatusTracker { myApplication.assertWriteAccessAllowed(); synchronized (myLock) { - TextRange currentTextRange = getCurrentTextRange(range); + TextRange currentTextRange = getCurrentTextRangeWithMagic(range); + int offset1 = currentTextRange.getStartOffset(); + int offset2 = Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()); if (range.getType() == Range.INSERTED) { - myDocument - .replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), ""); + myDocument.replaceString(offset1, offset2, ""); } else if (range.getType() == Range.DELETED) { - String upToDateContent = getUpToDateContent(range); - myDocument.insertString(currentTextRange.getStartOffset(), upToDateContent); + String upToDateContent = getUpToDateContentWithMagic(range); + myDocument.insertString(offset1, upToDateContent); } else { - - String upToDateContent = getUpToDateContent(range); - myDocument.replaceString(currentTextRange.getStartOffset(), Math.min(currentTextRange.getEndOffset() + 1, myDocument.getTextLength()), - upToDateContent); + String upToDateContent = getUpToDateContentWithMagic(range); + myDocument.replaceString(offset1, offset2, upToDateContent); } } } + public String getUpToDateContentWithMagic(Range range) { + synchronized (myLock) { + TextRange textRange = getUpToDateRangeWithMagic(range); + final int startOffset = textRange.getStartOffset(); + final int endOffset = Math.min(textRange.getEndOffset() + 1, myUpToDateDocument.getTextLength()); + return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString(); + } + } + public String getUpToDateContent(Range range) { synchronized (myLock) { TextRange textRange = getUpToDateRange(range); @@ -605,25 +575,28 @@ public class LineStatusTracker { return myProject; } - TextRange getCurrentTextRange(Range range) { - return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument, false); + @NotNull + TextRange getCurrentTextRangeWithMagic(@NotNull Range range) { + return getRangeWithMagic(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument); } - TextRange getUpToDateRange(Range range) { - return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, false); + @NotNull + TextRange getUpToDateRangeWithMagic(@NotNull Range range) { + return getRangeWithMagic(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument); } - TextRange getCurrentTextRangeWithEndSymbol(Range range) { - return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument, true); + @NotNull + TextRange getCurrentTextRange(@NotNull Range range) { + return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument); } - // a hack - TextRange getUpToDateRangeWithEndSymbol(Range range) { - return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, true); + @NotNull + TextRange getUpToDateRange(@NotNull Range range) { + return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument); } - private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document, - final boolean keepEnd) { + @NotNull + private static TextRange getRangeWithMagic(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) { if (rangeType == emptyRangeCondition) { int lineStartOffset; if (offset1 == 0) { @@ -634,23 +607,33 @@ public class LineStatusTracker { } //if (lineStartOffset > 0) lineStartOffset--; return new TextRange(lineStartOffset, lineStartOffset); - } else { int startOffset = document.getLineStartOffset(offset1); int endOffset = document.getLineEndOffset(offset2 - 1); if (startOffset > 0) { - -- startOffset; - if (! keepEnd) { - -- endOffset; - } + --startOffset; + --endOffset; } return new TextRange(startOffset, endOffset); } } - public static LineStatusTracker createOn(@Nullable VirtualFile virtualFile, final Document doc, final Project project) { - final Document document = new DocumentImpl("",true); + @NotNull + private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) { + if (rangeType == emptyRangeCondition) { + int lineStartOffset = offset1 < document.getLineCount() ? document.getLineStartOffset(offset1) : document.getTextLength(); + return new TextRange(lineStartOffset, lineStartOffset); + } + else { + int startOffset = document.getLineStartOffset(offset1); + int endOffset = document.getLineEndOffset(offset2 - 1); + return new TextRange(startOffset, endOffset); + } + } + + public static LineStatusTracker createOn(@Nullable VirtualFile virtualFile, @NotNull final Document doc, final Project project) { + final Document document = new DocumentImpl("", true); return new LineStatusTracker(doc, document, project, virtualFile); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java index 6900d46c9f10..5727c62f4d14 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java @@ -31,6 +31,10 @@ public class Range { public static final byte INSERTED = 2; public static final byte DELETED = 3; + // offset1/offset2 - line numbers + // (2,3) - modified 2nd line + // (2,2) - empty range between 1 and 2 lines + // index of first line is 0 private int myOffset1; private int myOffset2; private final int myUpToDateOffset1; @@ -154,22 +158,4 @@ public class Range { public RangeHighlighter getHighlighter() { return myRangeHighlighter; } - - public boolean contains(int offset1, int offset2) { - return getOffset1() <= offset1 && getOffset2() >= offset2; - } - - public boolean containsLine(int line) { - if (myType == DELETED) return (myOffset1 - 1) <= line - && (myOffset2) >= line; - return myOffset1 <= line && myOffset2 >= line; - } - - public boolean isAfter(int line) { - if (myType == DELETED) - return (getOffset1() - 1) > line; - else - return getOffset1() > line; - } - } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java index e17f868ffad4..74f9e43d08ad 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java @@ -19,6 +19,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.util.ArrayUtil; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; +import org.jetbrains.annotations.NotNull; import java.util.LinkedList; import java.util.List; @@ -30,22 +31,20 @@ import java.util.List; public class RangesBuilder { private List<Range> myRanges; - public RangesBuilder(Document current, Document upToDate) throws FilesTooBigForDiffException { + public RangesBuilder(@NotNull Document current, @NotNull Document upToDate) throws FilesTooBigForDiffException { this(new DocumentWrapper(current).getLines(), new DocumentWrapper(upToDate).getLines(), 0, 0); } - public RangesBuilder(List<String> current, List<String> upToDate, int shift, int uShift) throws FilesTooBigForDiffException { + public RangesBuilder(@NotNull List<String> current, @NotNull List<String> upToDate, int shift, int uShift) throws FilesTooBigForDiffException { myRanges = new LinkedList<Range>(); Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(upToDate), ArrayUtil.toStringArray(current)); - while (ch != null) { Range range = Range.createOn(ch, shift, uShift); myRanges.add(range); ch = ch.link; } - } public List<Range> getRanges() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java index 50622b27d0ce..c5dba0cab29c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java @@ -56,10 +56,10 @@ public class ShowLineStatusRangeDiffAction extends BaseLineStatusRangeAction { public DiffContent[] getContents() { return new DiffContent[]{ createDiffContent(myLineStatusTracker.getUpToDateDocument(), - myLineStatusTracker.getUpToDateRangeWithEndSymbol(myRange), + myLineStatusTracker.getUpToDateRange(myRange), null), createDiffContent(myLineStatusTracker.getDocument(), - myLineStatusTracker.getCurrentTextRangeWithEndSymbol(myRange), + myLineStatusTracker.getCurrentTextRange(myRange), myLineStatusTracker.getVirtualFile())}; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java index f8daa55b0e8f..a1fa2baeb1d2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java @@ -794,18 +794,7 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton { } result.add(new RefreshFileHistoryAction()); if (! myIsStaticAndEmbedded) { - result.add(new ToggleAction("Show Details", "Display details panel", AllIcons.Actions.Preview) { - @Override - public boolean isSelected(AnActionEvent e) { - return getConfiguration().SHOW_FILE_HISTORY_DETAILS; - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - getConfiguration().SHOW_FILE_HISTORY_DETAILS = state; - setupDetails(); - } - }); + result.add(new MyToggleAction()); } if (!popup && supportsTree()) { @@ -1119,7 +1108,7 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton { } - private class MyAnnotateAction extends AnAction { + private class MyAnnotateAction extends AnAction implements DumbAware { public MyAnnotateAction() { super(VcsBundle.message("annotate.action.name"), VcsBundle.message("annotate.action.description"), AllIcons.Actions.Annotate); @@ -1825,4 +1814,21 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton { } } + private class MyToggleAction extends ToggleAction implements DumbAware { + + public MyToggleAction() { + super("Show Details", "Display details panel", AllIcons.Actions.Preview); + } + + @Override + public boolean isSelected(AnActionEvent e) { + return getConfiguration().SHOW_FILE_HISTORY_DETAILS; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + getConfiguration().SHOW_FILE_HISTORY_DETAILS = state; + setupDetails(); + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsEP.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsEP.java index 7eda8accaa93..8be62f10953d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsEP.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsEP.java @@ -25,6 +25,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.VcsActiveEnvironmentsProxy; import com.intellij.util.xmlb.annotations.Attribute; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author yole @@ -47,29 +49,43 @@ public class VcsEP extends AbstractExtensionPointBean { public boolean crawlUpToCheckUnderVcs; private AbstractVcs myVcs; + private final Object LOCK = new Object(); - public AbstractVcs getVcs(Project project) { - if (myVcs == null) { - try { - final Class<? extends AbstractVcs> foundClass = findClass(vcsClass); - final Class<?>[] interfaces = foundClass.getInterfaces(); - for (Class<?> anInterface : interfaces) { - if (BaseComponent.class.isAssignableFrom(anInterface)) { - myVcs = PeriodicalTasksCloser.getInstance().safeGetComponent(project, foundClass); - myVcs = VcsActiveEnvironmentsProxy.proxyVcs(myVcs); - return myVcs; - } - } - myVcs = VcsActiveEnvironmentsProxy.proxyVcs((AbstractVcs)instantiate(vcsClass, project.getPicoContainer())); + @Nullable + public AbstractVcs getVcs(@NotNull Project project) { + synchronized (LOCK) { + if (myVcs != null) { + return myVcs; + } + } + AbstractVcs vcs = getInstance(project, vcsClass); + synchronized (LOCK) { + if (myVcs == null) { + myVcs = VcsActiveEnvironmentsProxy.proxyVcs(vcs); } - catch(Exception e) { - LOG.error(e); - return null; + return myVcs; + } + } + + @Nullable + private AbstractVcs getInstance(@NotNull Project project, @NotNull String vcsClass) { + try { + final Class<? extends AbstractVcs> foundClass = findClass(vcsClass); + final Class<?>[] interfaces = foundClass.getInterfaces(); + for (Class<?> anInterface : interfaces) { + if (BaseComponent.class.isAssignableFrom(anInterface)) { + return PeriodicalTasksCloser.getInstance().safeGetComponent(project, foundClass); + } } + return instantiate(vcsClass, project.getPicoContainer()); + } + catch(Exception e) { + LOG.error(e); + return null; } - return myVcs; } + @NotNull public VcsDescriptor createDescriptor() { return new VcsDescriptor(administrativeAreaName, displayName, name, crawlUpToCheckUnderVcs); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/AllVcses.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/AllVcses.java index f357321d9a00..0a47656491df 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/AllVcses.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/AllVcses.java @@ -91,14 +91,23 @@ public class AllVcses implements AllVcsesI, Disposable { if (vcs != null) { return vcs; } - final VcsEP ep = myExtensions.get(name); - if (ep != null) { - final AbstractVcs vcs1 = ep.getVcs(myProject); - LOG.assertTrue(vcs1 != null, name); + } + + // unmodifiable map => no sync needed + final VcsEP ep = myExtensions.get(name); + if (ep == null) { + return null; + } + + // VcsEP guarantees to always return the same vcs value + final AbstractVcs vcs1 = ep.getVcs(myProject); + LOG.assertTrue(vcs1 != null, name); + + synchronized (myLock) { + if (!myVcses.containsKey(name)) { addVcs(vcs1); - return vcs1; } - return null; + return vcs1; } } diff --git a/platform/vcs-impl/src/com/intellij/vcsUtil/AuthDialog.java b/platform/vcs-impl/src/com/intellij/vcsUtil/AuthDialog.java index e61b229302f1..d3ed9a84de2c 100644 --- a/platform/vcs-impl/src/com/intellij/vcsUtil/AuthDialog.java +++ b/platform/vcs-impl/src/com/intellij/vcsUtil/AuthDialog.java @@ -35,16 +35,17 @@ public class AuthDialog extends DialogWrapper { public AuthDialog(@NotNull Project project, @NotNull String title, @Nullable String description, @Nullable String login, @Nullable String password, boolean rememberByDefault) { super(project, false); setTitle(title); - boolean rememberPassword = decideOnShowRememberPasswordOption(password, rememberByDefault); + Boolean rememberPassword = decideOnShowRememberPasswordOption(password, rememberByDefault); authPanel = new AuthenticationPanel(description, login, password, rememberPassword); init(); } - private static boolean decideOnShowRememberPasswordOption(@Nullable String password, boolean rememberByDefault) { + @Nullable + private static Boolean decideOnShowRememberPasswordOption(@Nullable String password, boolean rememberByDefault) { final PasswordSafeImpl passwordSafe = (PasswordSafeImpl)PasswordSafe.getInstance(); // if password saving is disabled, don't show the checkbox. if (passwordSafe.getSettings().getProviderType().equals(PasswordSafeSettings.ProviderType.DO_NOT_STORE)) { - return false; + return null; } // if password is prefilled, it is expected to continue remembering it. if (!StringUtil.isEmptyOrSpaces(password)) { |