diff --git a/plugins/git4idea/src/git4idea/GitContentRevision.java b/plugins/git4idea/src/git4idea/GitContentRevision.java index 40ba200159cf..9f1c759d0902 100644 --- a/plugins/git4idea/src/git4idea/GitContentRevision.java +++ b/plugins/git4idea/src/git4idea/GitContentRevision.java @@ -146,7 +146,7 @@ public class GitContentRevision implements ContentRevision { */ public static ContentRevision createRevision(VirtualFile vcsRoot, String path, - VcsRevisionNumber revisionNumber, + @Nullable VcsRevisionNumber revisionNumber, Project project, boolean isDeleted, final boolean canBeDeleted, boolean unescapePath) throws VcsException { final FilePath file; diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index f2ae9c996918..b8e21d7dcd51 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -26,11 +26,13 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.Change; import com.intellij.util.ui.UIUtil; import git4idea.GitBranch; import git4idea.GitExecutionException; import git4idea.GitVcs; import git4idea.NotificationManager; +import git4idea.changes.GitChangeUtils; import git4idea.commands.Git; import git4idea.commands.GitCommandResult; import git4idea.commands.GitCompoundResult; @@ -390,10 +392,23 @@ public final class GitBranchOperationsProcessor { GitCommitCompareInfo compareInfo = new GitCommitCompareInfo(); for (GitRepository repository : repositories) { compareInfo.put(repository, loadCommitsToCompare(repository, branchName)); + compareInfo.put(repository, loadTotalDiff(repository, branchName)); } return compareInfo; } - + + @NotNull + private static Collection loadTotalDiff(@NotNull GitRepository repository, @NotNull String branchName) { + try { + return GitChangeUtils.getDiff(repository.getProject(), repository.getRoot(), null, branchName, null); + } + catch (VcsException e) { + // we treat it as critical and report an error + throw new GitExecutionException("Couldn't get [git diff " + branchName + "] on repository [" + repository.getRoot() + "]", e); + } + } + + @NotNull private Pair, List> loadCommitsToCompare(@NotNull GitRepository repository, @NotNull final String branchName) { final List headToBranch; final List branchToHead; @@ -418,20 +433,21 @@ public final class GitBranchOperationsProcessor { } } - public void merge(@NotNull final String branchName) { + public void merge(@NotNull final String branchName, final boolean localBranch) { new CommonBackgroundTask(myProject, "Merging " + branchName, myCallInAwtAfterExecution) { @Override public void execute(@NotNull ProgressIndicator indicator) { - doMerge(branchName, indicator); + doMerge(branchName, localBranch, indicator); } }.runInBackground(); } - private void doMerge(@NotNull String branchName, @NotNull ProgressIndicator indicator) { + private void doMerge(@NotNull String branchName, boolean localBranch, @NotNull ProgressIndicator indicator) { Map revisions = new HashMap(); for (GitRepository repository : myRepositories) { revisions.put(repository, repository.getCurrentRevision()); } - new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), mySelectedRepository, revisions, indicator).execute(); + new GitMergeOperation(myProject, myRepositories, branchName, localBranch, getCurrentBranchOrRev(), + mySelectedRepository, revisions, indicator).execute(); } /** diff --git a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java index 4c7fd4e27888..08d066516d80 100644 --- a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java @@ -54,6 +54,7 @@ class GitMergeOperation extends GitBranchOperation { @NotNull private final ChangeListManager myChangeListManager; @NotNull private final String myBranchToMerge; + private final boolean myLocalBranch; @NotNull private final String myCurrentBranch; @NotNull private final GitRepository myCurrentRepository; @NotNull private final Map myCurrentRevisionsBeforeMerge; @@ -62,12 +63,13 @@ class GitMergeOperation extends GitBranchOperation { @NotNull private final Map myConflictedRepositories = new HashMap(); private GitPreservingProcess myPreservingProcess; - protected GitMergeOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull String branchToMerge, @NotNull String currentBranch, @NotNull GitRepository currentRepository, - @NotNull Map currentRevisionsBeforeMerge, - @NotNull ProgressIndicator indicator) { + GitMergeOperation(@NotNull Project project, @NotNull Collection repositories, + @NotNull String branchToMerge, boolean localBranch, @NotNull String currentBranch, + @NotNull GitRepository currentRepository, @NotNull Map currentRevisionsBeforeMerge, + @NotNull ProgressIndicator indicator) { super(project, repositories, currentBranch, indicator); myBranchToMerge = branchToMerge; + myLocalBranch = localBranch; myCurrentBranch = currentBranch; myCurrentRepository = currentRepository; myCurrentRevisionsBeforeMerge = currentRevisionsBeforeMerge; @@ -157,20 +159,14 @@ class GitMergeOperation extends GitBranchOperation { @Override protected void notifySuccess(@NotNull String message) { - String description = message + "
Delete " + myBranchToMerge + ""; - NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", description, NotificationType.INFORMATION, - new NotificationListener() { - @Override - public void hyperlinkUpdate(@NotNull Notification notification, - @NotNull HyperlinkEvent event) { - if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && - event.getDescription().equalsIgnoreCase("delete")) { - new GitBranchOperationsProcessor(myProject, new ArrayList( - getRepositories()), myCurrentRepository). - deleteBranch(myBranchToMerge); - } - } - }); + if (!myLocalBranch) { + super.notifySuccess(message); + } + else { + String description = message + "
Delete " + myBranchToMerge + ""; + NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", description, NotificationType.INFORMATION, + new DeleteMergedLocalBranchNotificationListener()); + } } private boolean resolveConflicts() { @@ -369,4 +365,15 @@ class GitMergeOperation extends GitBranchOperation { getResolveLinkListener()); } } + + private class DeleteMergedLocalBranchNotificationListener implements NotificationListener { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, + @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equalsIgnoreCase("delete")) { + new GitBranchOperationsProcessor(myProject, new ArrayList(getRepositories()), myCurrentRepository). + deleteBranch(myBranchToMerge); + } + } + } } diff --git a/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java b/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java index c37f7eca50a6..4e06200c7d00 100644 --- a/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java +++ b/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java @@ -18,6 +18,7 @@ package git4idea.changes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; @@ -113,7 +114,7 @@ public class GitChangeUtils { */ public static void parseChanges(Project project, VirtualFile vcsRoot, - GitRevisionNumber thisRevision, + @Nullable GitRevisionNumber thisRevision, GitRevisionNumber parentRevision, String s, Collection changes, @@ -161,7 +162,7 @@ public class GitChangeUtils { */ public static void parseChanges(Project project, VirtualFile vcsRoot, - GitRevisionNumber thisRevision, + @Nullable GitRevisionNumber thisRevision, GitRevisionNumber parentRevision, StringScanner s, Collection changes, @@ -444,4 +445,52 @@ public class GitChangeUtils { public static long longForSHAHash(String revisionNumber) { return Long.parseLong(revisionNumber.substring(0, 15), 16) << 4 + Integer.parseInt(revisionNumber.substring(15, 16), 16); } + + @NotNull + public static Collection getDiff(@NotNull Project project, @NotNull VirtualFile root, + @Nullable String firstRevision, @NotNull String nextRevision, + @Nullable Collection dirtyPaths) throws VcsException { + Collection changes = new ArrayList(); + String range = firstRevision == null ? nextRevision : firstRevision + ".." + nextRevision; + String output = getDiffOutput(project, root, range, dirtyPaths); + GitRevisionNumber thisRevision = firstRevision == null ? null : loadRevision(project, root, firstRevision); + parseChanges(project, root, thisRevision, loadRevision(project, root, nextRevision), output, changes, Collections.emptySet()); + return changes; + } + + /** + * Calls {@code git diff} on the given range. + * @param project + * @param root + * @param diffRange range or just revision (will be compared with current working tree). + * @param dirtyPaths limit the command by paths if needed or pass null. + * @return output of the 'git diff' command. + * @throws VcsException + */ + @NotNull + public static String getDiffOutput(@NotNull Project project, @NotNull VirtualFile root, + @NotNull String diffRange, @Nullable Collection dirtyPaths) throws VcsException { + GitSimpleHandler handler = getDiffHandler(project, root, diffRange, dirtyPaths); + if (handler.isLargeCommandLine()) { + // if there are too much files, just get all changes for the project + handler = getDiffHandler(project, root, diffRange, null); + } + return handler.run(); + } + + @NotNull + private static GitSimpleHandler getDiffHandler(@NotNull Project project, @NotNull VirtualFile root, + @NotNull String diffRange, @Nullable Collection dirtyPaths) { + GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.DIFF); + handler.addParameters("--name-status", "--diff-filter=ADCMRUXT", "-M", diffRange); + handler.setNoSSH(true); + handler.setSilent(true); + handler.setStdoutSuppressed(true); + handler.endOptions(); + if (dirtyPaths != null) { + handler.addRelativePaths(dirtyPaths); + } + return handler; + } + } diff --git a/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java b/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java index b719ffc5b672..52ed9458f353 100644 --- a/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java +++ b/plugins/git4idea/src/git4idea/status/GitOldChangesCollector.java @@ -153,24 +153,8 @@ class GitOldChangesCollector extends GitChangesCollector { if (dirtyPaths.isEmpty()) { return; } - GitSimpleHandler handler = new GitSimpleHandler(myProject, myVcsRoot, GitCommand.DIFF); - handler.addParameters("--name-status", "--diff-filter=ADCMRUXT", "-M", "HEAD"); - handler.setNoSSH(true); - handler.setSilent(true); - handler.setStdoutSuppressed(true); - handler.endOptions(); - handler.addRelativePaths(dirtyPaths); - if (handler.isLargeCommandLine()) { - // if there are too much files, just get all changes for the project - handler = new GitSimpleHandler(myProject, myVcsRoot, GitCommand.DIFF); - handler.addParameters("--name-status", "--diff-filter=ADCMRUXT", "-M", "HEAD"); - handler.setNoSSH(true); - handler.setSilent(true); - handler.setStdoutSuppressed(true); - handler.endOptions(); - } try { - String output = handler.run(); + String output = GitChangeUtils.getDiffOutput(myProject, myVcsRoot, "HEAD", dirtyPaths); GitChangeUtils.parseChanges(myProject, myVcsRoot, null, GitChangeUtils.loadRevision(myProject, myVcsRoot, "HEAD"), output, myChanges, myUnmergedNames); } @@ -178,7 +162,7 @@ class GitOldChangesCollector extends GitChangesCollector { if (!GitChangeUtils.isHeadMissing(ex)) { throw ex; } - handler = new GitSimpleHandler(myProject, myVcsRoot, GitCommand.LS_FILES); + GitSimpleHandler handler = new GitSimpleHandler(myProject, myVcsRoot, GitCommand.LS_FILES); handler.addParameters("--cached"); handler.setNoSSH(true); handler.setSilent(true); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index 692bd47d525d..9e166994336e 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -197,7 +197,7 @@ class GitBranchPopupActions { new CheckoutAction(myProject, myRepositories, myBranchName, mySelectedRepository), new CheckoutAsNewBranch(myProject, myRepositories, myBranchName, mySelectedRepository), new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository), - new MergeAction(myProject, myRepositories, myBranchName, mySelectedRepository), + new MergeAction(myProject, myRepositories, myBranchName, mySelectedRepository, true), new DeleteAction(myProject, myRepositories, myBranchName, mySelectedRepository) }; } @@ -298,7 +298,7 @@ class GitBranchPopupActions { return new AnAction[] { new CheckoutRemoteBranchAction(myProject, myRepositories, myBranchName, mySelectedRepository), new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository), - new MergeAction(myProject, myRepositories, myBranchName, mySelectedRepository), + new MergeAction(myProject, myRepositories, myBranchName, mySelectedRepository, false), new RemoteDeleteAction(myProject, myRepositories, myBranchName, mySelectedRepository) }; } @@ -387,19 +387,21 @@ class GitBranchPopupActions { private final List myRepositories; private final String myBranchName; private final GitRepository mySelectedRepository; + private final boolean myLocalBranch; public MergeAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName, - @NotNull GitRepository selectedRepository) { + @NotNull GitRepository selectedRepository, boolean localBranch) { super("Merge"); myProject = project; myRepositories = repositories; myBranchName = branchName; mySelectedRepository = selectedRepository; + myLocalBranch = localBranch; } @Override public void actionPerformed(AnActionEvent e) { - new GitBranchOperationsProcessor(myProject, myRepositories, mySelectedRepository).merge(myBranchName); + new GitBranchOperationsProcessor(myProject, myRepositories, mySelectedRepository).merge(myBranchName, myLocalBranch); } } diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java index c761cc5c72aa..355412335b3e 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java @@ -17,28 +17,16 @@ package git4idea.ui.branch; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Splitter; -import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; -import com.intellij.ui.components.JBLabel; -import com.intellij.util.ArrayUtil; -import com.intellij.util.Consumer; -import com.intellij.util.ui.UIUtil; -import git4idea.history.browser.GitCommit; +import com.intellij.openapi.util.IconLoader; +import com.intellij.ui.components.JBTabbedPane; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; -import git4idea.ui.GitCommitListPanel; -import git4idea.ui.GitRepositoryComboboxListCellRenderer; import git4idea.util.GitCommitCompareInfo; import git4idea.util.GitUIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Collections; +import java.awt.event.KeyEvent; /** * Dialog for comparing two Git branches. @@ -52,11 +40,8 @@ public class GitCompareBranchesDialog extends DialogWrapper { private final GitCommitCompareInfo myCompareInfo; private final GitRepository myInitialRepo; - private GitCommitListPanel myHeadToBranchListPanel; - private GitCommitListPanel myBranchToHeadListPanel; - - public GitCompareBranchesDialog(@NotNull Project project, @NotNull String branchName, @NotNull String currentBranchName, @NotNull GitCommitCompareInfo compareInfo, - @NotNull GitRepository initialRepo) { + public GitCompareBranchesDialog(@NotNull Project project, @NotNull String branchName, @NotNull String currentBranchName, + @NotNull GitCommitCompareInfo compareInfo, @NotNull GitRepository initialRepo) { super(project, false); myCurrentBranchName = currentBranchName; myCompareInfo = compareInfo; @@ -77,93 +62,17 @@ public class GitCompareBranchesDialog extends DialogWrapper { @Override protected JComponent createCenterPanel() { - final ChangesBrowser changesBrowser = new ChangesBrowser(myProject, null, Collections.emptyList(), null, false, true, null, ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); + JPanel logPanel = new GitCompareBranchesLogPanel(myProject, myBranchName, myCurrentBranchName, myCompareInfo, myInitialRepo); + JPanel diffPanel = new GitCompareBranchesDiffPanel(myProject, myBranchName, myCurrentBranchName, myCompareInfo); - myHeadToBranchListPanel = new GitCommitListPanel(myProject, getHeadToBranchCommits(myInitialRepo)); - myBranchToHeadListPanel = new GitCommitListPanel(myProject, getBranchToHeadCommits(myInitialRepo)); - - addSelectionListener(myHeadToBranchListPanel, myBranchToHeadListPanel, changesBrowser); - addSelectionListener(myBranchToHeadListPanel, myHeadToBranchListPanel, changesBrowser); - - JPanel htb = layoutCommitListPanel(myCurrentBranchName, true); - JPanel bth = layoutCommitListPanel(myCurrentBranchName, false); - - Splitter lists = new Splitter(true, 0.5f); - lists.setFirstComponent(htb); - lists.setSecondComponent(bth); - - Splitter rootPanel = new Splitter(false, 0.7f); - rootPanel.setSecondComponent(changesBrowser); - rootPanel.setFirstComponent(lists); - return rootPanel; + JBTabbedPane tabbedPane = new JBTabbedPane(); + tabbedPane.addTab("Log", IconLoader.getIcon("/icons/branch.png"), logPanel); + tabbedPane.setMnemonicAt(0, KeyEvent.VK_L); + tabbedPane.addTab("Diff", IconLoader.getIcon("/actions/diff.png"), diffPanel); + tabbedPane.setMnemonicAt(1, KeyEvent.VK_D); + return tabbedPane; } - @Override - protected JComponent createNorthPanel() { - final JComboBox repoSelector = new JComboBox(ArrayUtil.toObjectArray(myCompareInfo.getRepositories(), GitRepository.class)); - repoSelector.setRenderer(new GitRepositoryComboboxListCellRenderer(repoSelector)); - repoSelector.setSelectedItem(myInitialRepo); - - repoSelector.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - GitRepository selectedRepo = (GitRepository)repoSelector.getSelectedItem(); - myHeadToBranchListPanel.setCommits(getHeadToBranchCommits(selectedRepo)); - myBranchToHeadListPanel.setCommits(getBranchToHeadCommits(selectedRepo)); - } - }); - - JPanel repoSelectorPanel = new JPanel(new BorderLayout()); - JBLabel label = new JBLabel("Repository: "); - label.setLabelFor(repoSelectorPanel); - repoSelectorPanel.add(label); - repoSelectorPanel.add(repoSelector); - - if (myCompareInfo.getRepositories().size() < 2) { - repoSelectorPanel.setVisible(false); - } - return repoSelectorPanel; - } - - private ArrayList getBranchToHeadCommits(GitRepository selectedRepo) { - return new ArrayList(myCompareInfo.getBranchToHeadCommits(selectedRepo)); - } - - private ArrayList getHeadToBranchCommits(GitRepository selectedRepo) { - return new ArrayList(myCompareInfo.getHeadToBranchCommits(selectedRepo)); - } - - private static void addSelectionListener(@NotNull GitCommitListPanel sourcePanel, - @NotNull final GitCommitListPanel otherPanel, - @NotNull final ChangesBrowser changesBrowser) { - sourcePanel.addListSelectionListener(new Consumer() { - @Override - public void consume(GitCommit commit) { - changesBrowser.setChangesToDisplay(commit.getChanges()); - otherPanel.clearSelection(); - } - }); - } - - private JPanel layoutCommitListPanel(@NotNull String currentBranch, boolean forward) { - String desc = makeDescription(currentBranch, forward); - - JPanel bth = new JPanel(new BorderLayout()); - JBLabel descriptionLabel = new JBLabel(desc, UIUtil.ComponentStyle.SMALL); - descriptionLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); - bth.add(descriptionLabel, BorderLayout.NORTH); - bth.add(forward ? myHeadToBranchListPanel : myBranchToHeadListPanel); - return bth; - } - - private String makeDescription(@NotNull String currentBranch, boolean forward) { - String firstBranch = forward ? currentBranch : myBranchName; - String secondBranch = forward ? myBranchName : currentBranch; - return String.format("Commits that exist in %s but don't exist in %s (git log %s..%s):", - secondBranch, firstBranch, firstBranch, secondBranch); - } - - // it is information dialog - no need to OK or Cancel. Close the dialog by clicking the cross button or pressing Esc. @Override protected Action[] createActions() { diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDiffPanel.java b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDiffPanel.java new file mode 100644 index 000000000000..83b4b836fcd0 --- /dev/null +++ b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDiffPanel.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2012 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 git4idea.ui.branch; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.ui.UIUtil; +import git4idea.util.GitCommitCompareInfo; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + * @author Kirill Likhodedov + */ +class GitCompareBranchesDiffPanel extends JPanel { + + private final Project myProject; + private final String myBranchName; + private final String myCurrentBranchName; + private final GitCommitCompareInfo myCompareInfo; + + public GitCompareBranchesDiffPanel(Project project, String branchName, String currentBranchName, GitCommitCompareInfo compareInfo) { + super(); + + myProject = project; + myCurrentBranchName = currentBranchName; + myCompareInfo = compareInfo; + myBranchName = branchName; + + setLayout(new BorderLayout(UIUtil.DEFAULT_VGAP, UIUtil.DEFAULT_HGAP)); + add(createNorthPanel(), BorderLayout.NORTH); + add(createCenterPanel()); + } + + private JComponent createNorthPanel() { + return new JBLabel(String.format("Difference between current working tree on %s " + + "and files in %s:", myCurrentBranchName, myBranchName), + UIUtil.ComponentStyle.REGULAR); + } + + private JComponent createCenterPanel() { + List diff = myCompareInfo.getTotalDiff(); + final ChangesBrowser changesBrowser = new ChangesBrowser(myProject, null, diff, null, false, true, + null, ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); + changesBrowser.setChangesToDisplay(diff); + return changesBrowser; + } + +} diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesLogPanel.java b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesLogPanel.java new file mode 100644 index 000000000000..b511ff39726e --- /dev/null +++ b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesLogPanel.java @@ -0,0 +1,154 @@ +/* + * Copyright 2000-2012 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 git4idea.ui.branch; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Splitter; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; +import com.intellij.util.ui.UIUtil; +import git4idea.history.browser.GitCommit; +import git4idea.repo.GitRepository; +import git4idea.ui.GitCommitListPanel; +import git4idea.ui.GitRepositoryComboboxListCellRenderer; +import git4idea.util.GitCommitCompareInfo; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collections; + +/** + * @author Kirill Likhodedov + */ +class GitCompareBranchesLogPanel extends JPanel { + + private final Project myProject; + private final String myBranchName; + private final String myCurrentBranchName; + private final GitCommitCompareInfo myCompareInfo; + private final GitRepository myInitialRepo; + + private GitCommitListPanel myHeadToBranchListPanel; + private GitCommitListPanel myBranchToHeadListPanel; + + GitCompareBranchesLogPanel(@NotNull Project project, @NotNull String branchName, @NotNull String currentBranchName, + @NotNull GitCommitCompareInfo compareInfo, @NotNull GitRepository initialRepo) { + super(new BorderLayout()); + myProject = project; + myBranchName = branchName; + myCurrentBranchName = currentBranchName; + myCompareInfo = compareInfo; + myInitialRepo = initialRepo; + + add(createNorthPanel(), BorderLayout.NORTH); + add(createCenterPanel()); + } + + private JComponent createCenterPanel() { + final ChangesBrowser changesBrowser = new ChangesBrowser(myProject, null, Collections.emptyList(), null, false, true, + null, ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); + + myHeadToBranchListPanel = new GitCommitListPanel(myProject, getHeadToBranchCommits(myInitialRepo)); + myBranchToHeadListPanel = new GitCommitListPanel(myProject, getBranchToHeadCommits(myInitialRepo)); + + addSelectionListener(myHeadToBranchListPanel, myBranchToHeadListPanel, changesBrowser); + addSelectionListener(myBranchToHeadListPanel, myHeadToBranchListPanel, changesBrowser); + + JPanel htb = layoutCommitListPanel(myCurrentBranchName, true); + JPanel bth = layoutCommitListPanel(myCurrentBranchName, false); + + Splitter lists = new Splitter(true, 0.5f); + lists.setFirstComponent(htb); + lists.setSecondComponent(bth); + + Splitter rootPanel = new Splitter(false, 0.7f); + rootPanel.setSecondComponent(changesBrowser); + rootPanel.setFirstComponent(lists); + return rootPanel; + } + + private JComponent createNorthPanel() { + final JComboBox repoSelector = new JComboBox(ArrayUtil.toObjectArray(myCompareInfo.getRepositories(), GitRepository.class)); + repoSelector.setRenderer(new GitRepositoryComboboxListCellRenderer(repoSelector)); + repoSelector.setSelectedItem(myInitialRepo); + + repoSelector.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + GitRepository selectedRepo = (GitRepository)repoSelector.getSelectedItem(); + myHeadToBranchListPanel.setCommits(getHeadToBranchCommits(selectedRepo)); + myBranchToHeadListPanel.setCommits(getBranchToHeadCommits(selectedRepo)); + } + }); + + JPanel repoSelectorPanel = new JPanel(new BorderLayout(UIUtil.DEFAULT_VGAP, UIUtil.DEFAULT_HGAP)); + JBLabel label = new JBLabel("Repository: "); + label.setLabelFor(repoSelectorPanel); + repoSelectorPanel.add(label, BorderLayout.WEST); + repoSelectorPanel.add(repoSelector); + + if (myCompareInfo.getRepositories().size() < 2) { + repoSelectorPanel.setVisible(false); + } + return repoSelectorPanel; + } + + private ArrayList getBranchToHeadCommits(GitRepository selectedRepo) { + return new ArrayList(myCompareInfo.getBranchToHeadCommits(selectedRepo)); + } + + private ArrayList getHeadToBranchCommits(GitRepository selectedRepo) { + return new ArrayList(myCompareInfo.getHeadToBranchCommits(selectedRepo)); + } + + + private static void addSelectionListener(@NotNull GitCommitListPanel sourcePanel, + @NotNull final GitCommitListPanel otherPanel, + @NotNull final ChangesBrowser changesBrowser) { + sourcePanel.addListSelectionListener(new Consumer() { + @Override + public void consume(GitCommit commit) { + changesBrowser.setChangesToDisplay(commit.getChanges()); + otherPanel.clearSelection(); + } + }); + } + + private JPanel layoutCommitListPanel(@NotNull String currentBranch, boolean forward) { + String desc = makeDescription(currentBranch, forward); + + JPanel bth = new JPanel(new BorderLayout()); + JBLabel descriptionLabel = new JBLabel(desc, UIUtil.ComponentStyle.SMALL); + descriptionLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); + bth.add(descriptionLabel, BorderLayout.NORTH); + bth.add(forward ? myHeadToBranchListPanel : myBranchToHeadListPanel); + return bth; + } + + private String makeDescription(@NotNull String currentBranch, boolean forward) { + String firstBranch = forward ? currentBranch : myBranchName; + String secondBranch = forward ? myBranchName : currentBranch; + return String.format("Commits that exist in %s but don't exist in %s (git log %s..%s):", + secondBranch, firstBranch, firstBranch, secondBranch); + } +} diff --git a/plugins/git4idea/src/git4idea/util/GitCommitCompareInfo.java b/plugins/git4idea/src/git4idea/util/GitCommitCompareInfo.java index 0a9bde9a16ed..bb567b349c58 100644 --- a/plugins/git4idea/src/git4idea/util/GitCommitCompareInfo.java +++ b/plugins/git4idea/src/git4idea/util/GitCommitCompareInfo.java @@ -17,6 +17,7 @@ package git4idea.util; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vcs.changes.Change; import git4idea.history.browser.GitCommit; import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; @@ -31,11 +32,16 @@ public class GitCommitCompareInfo { private static final Logger LOG = Logger.getInstance(GitCommitCompareInfo.class); private final Map, List>> myInfo = new HashMap, List>>(); - + private final Map> myTotalDiff = new HashMap>(); + public void put(@NotNull GitRepository repository, @NotNull Pair, List> commits) { myInfo.put(repository, commits); } + public void put(@NotNull GitRepository repository, @NotNull Collection totalDiff) { + myTotalDiff.put(repository, totalDiff); + } + @NotNull public List getHeadToBranchCommits(@NotNull GitRepository repo) { return getCompareInfo(repo).getFirst(); @@ -64,4 +70,13 @@ public class GitCommitCompareInfo { public boolean isEmpty() { return myInfo.isEmpty(); } + + @NotNull + public List getTotalDiff() { + List changes = new ArrayList(); + for (Collection changeCollection : myTotalDiff.values()) { + changes.addAll(changeCollection); + } + return changes; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java index 03a2536216e1..e5351d1c6dc2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.editor.actions; +import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.editorActions.JavaTypedHandler; import com.intellij.codeInsight.editorActions.TypedHandlerDelegate; @@ -23,8 +24,12 @@ import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; -import com.intellij.psi.*; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.tree.TokenSet; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; @@ -50,10 +55,41 @@ public class GroovyTypedHandler extends TypedHandlerDelegate { } } + if (c == '@' && file instanceof GroovyFile) { + autoPopupMemberLookup(project, editor, new Condition() { + public boolean value(final PsiFile file) { + int offset = editor.getCaretModel().getOffset(); + + PsiElement lastElement = file.findElementAt(offset - 1); + if (lastElement == null) return false; + + final PsiElement prevSibling = PsiTreeUtil.prevVisibleLeaf(lastElement); + return prevSibling != null && ".".equals(prevSibling.getText()); + } + }); + } + + if (c == '&' && file instanceof GroovyFile) { + autoPopupMemberLookup(project, editor, new Condition() { + public boolean value(final PsiFile file) { + int offset = editor.getCaretModel().getOffset(); + + PsiElement lastElement = file.findElementAt(offset - 1); + return lastElement != null && ".&".equals(lastElement.getText()); + } + }); + } + + return Result.CONTINUE; } - public Result charTyped(final char c, final Project project, final Editor editor, final PsiFile file) { + private static void autoPopupMemberLookup(Project project, final Editor editor, Condition condition) { + AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, condition); + } + + + public Result charTyped(final char c, final Project project, final Editor editor, @NotNull final PsiFile file) { if (myJavaLTTyped) { myJavaLTTyped = false; JavaTypedHandler.handleAfterJavaLT(editor, GroovyTokenTypes.mLT, GroovyTokenTypes.mGT, INVALID_INSIDE_REFERENCE); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MixinMemberContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MixinMemberContributor.java index 2e1d8fd17c47..45c436b49308 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MixinMemberContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MixinMemberContributor.java @@ -50,20 +50,19 @@ public class MixinMemberContributor extends NonCodeMembersContributor { final PsiModifierList modifierList = aClass.getModifierList(); if (modifierList == null) return; - final PsiAnnotation annotation = modifierList.findAnnotation(GroovyCommonClassNames.GROOVY_LANG_MIXIN); - if (annotation == null) return; - - final PsiAnnotationMemberValue value = annotation.findAttributeValue("value"); - List mixins = new ArrayList(); - if (value instanceof GrAnnotationArrayInitializer) { - final GrAnnotationMemberValue[] initializers = ((GrAnnotationArrayInitializer)value).getInitializers(); - for (GrAnnotationMemberValue initializer : initializers) { - addMixin(initializer, mixins); + for (PsiAnnotation annotation : getAllMixins(modifierList)) { + final PsiAnnotationMemberValue value = annotation.findAttributeValue("value"); + + if (value instanceof GrAnnotationArrayInitializer) { + final GrAnnotationMemberValue[] initializers = ((GrAnnotationArrayInitializer)value).getInitializers(); + for (GrAnnotationMemberValue initializer : initializers) { + addMixin(initializer, mixins); + } + } + else if (value instanceof GrExpression) { + addMixin((GrExpression)value, mixins); } - } - else if (value instanceof GrExpression) { - addMixin((GrExpression)value, mixins); } for (PsiClass mixin : mixins) { @@ -83,6 +82,16 @@ public class MixinMemberContributor extends NonCodeMembersContributor { } } + private static List getAllMixins(PsiModifierList modifierList) { + final ArrayList result = new ArrayList(); + for (PsiAnnotation annotation : modifierList.getApplicableAnnotations()) { + if (GroovyCommonClassNames.GROOVY_LANG_MIXIN.equals(annotation.getQualifiedName())) { + result.add(annotation); + } + } + return result; + } + private static boolean isCategoryMethod(PsiElement element, PsiType qualifierType) { if (!(element instanceof PsiMethod)) return false; if (!((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC)) return false; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy index 69b237df29b9..1d4650e9c13a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy @@ -789,9 +789,39 @@ print new B().foo() def resolved = ref.resolve() assertInstanceOf(resolved, GrMethod) - assertTrue(resolved.isPhysical()) + assertTrue(resolved.physical) } + void testTwoMixinsInModifierList() { + def ref = configureByText(""" +class PersonHelper { + def useThePerson() { + Person person = new Person() + + person.getUsername() + person.getName() + } +} + +@Mixin(PersonMixin) +@Mixin(OtherPersonMixin) +class Person { } + +class PersonMixin { + String getUsername() { } +} + +class OtherPersonMixin { + String getName() { } +} +""") + + def resolved = ref.resolve() + assertInstanceOf(resolved, GrMethod) + assertTrue(resolved.physical) + } + + void testDisjunctionType() { def ref = configureByText (""" import java.sql.SQLException diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/EditMavenPropertyDialog.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/EditMavenPropertyDialog.java index 9ef8c87e6679..54e62788f208 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/EditMavenPropertyDialog.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/EditMavenPropertyDialog.java @@ -15,7 +15,6 @@ */ package org.jetbrains.idea.maven.execution; -import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Pair; import com.intellij.util.ArrayUtil; @@ -34,8 +33,8 @@ public class EditMavenPropertyDialog extends DialogWrapper { private JTextField myValueField; private final Map myAvailableProperties; - public EditMavenPropertyDialog(Project p, Pair value, Map availableProperties) { - super(p, false); + public EditMavenPropertyDialog(Pair value, Map availableProperties) { + super(false); setTitle("Edit Maven Property"); myAvailableProperties = availableProperties; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenPropertiesPanel.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenPropertiesPanel.java new file mode 100644 index 000000000000..f5cf8e20184c --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenPropertiesPanel.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.maven.execution; + +import com.intellij.openapi.util.Pair; +import com.intellij.ui.AddEditRemovePanel; + +import java.awt.*; +import java.util.*; +import java.util.List; + +/** +* @author Sergey Evdokimov +*/ +public class MavenPropertiesPanel extends AddEditRemovePanel> { + private Map myAvailableProperties; + + public MavenPropertiesPanel(Map availableProperties) { + super(new MyPropertiesTableModel(), new ArrayList>(), null); + setPreferredSize(new Dimension(100, 100)); + myAvailableProperties = availableProperties; + } + + protected Pair addItem() { + return doAddOrEdit(new Pair("", "")); + } + + protected boolean removeItem(Pair o) { + return true; + } + + protected Pair editItem(Pair o) { + return doAddOrEdit(o); + } + + private Pair doAddOrEdit(Pair o) { + EditMavenPropertyDialog d = new EditMavenPropertyDialog(o, myAvailableProperties); + d.show(); + if (!d.isOK()) return null; + return d.getValue(); + } + + public Map getDataAsMap() { + Map result = new LinkedHashMap(); + for (Pair p : getData()) { + result.put(p.getFirst(), p.getSecond()); + } + return result; + } + + public void setDataFromMap(Map map) { + List> result = new ArrayList>(); + for (Map.Entry e : map.entrySet()) { + result.add(new Pair(e.getKey(), e.getValue())); + } + setData(result); + } + + private static class MyPropertiesTableModel extends AddEditRemovePanel.TableModel> { + public int getColumnCount() { + return 2; + } + + public String getColumnName(int c) { + return c == 0 ? "Name" : "Value"; + } + + public Object getField(Pair o, int c) { + return c == 0 ? o.getFirst() : o.getSecond(); + } + } + +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerConfigurable.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerConfigurable.java index 085fc93e248c..9179c008b610 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerConfigurable.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerConfigurable.java @@ -21,8 +21,6 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; -import com.intellij.ui.AddEditRemovePanel; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.RawCommandLineEditor; import org.jetbrains.annotations.Nls; @@ -35,8 +33,9 @@ import org.jetbrains.idea.maven.utils.ComboBoxUtil; import javax.swing.*; import java.awt.*; -import java.util.*; -import java.util.List; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; public abstract class MavenRunnerConfigurable implements SearchableConfigurable, Configurable.NoScroll { private final Project myProject; @@ -47,7 +46,7 @@ public abstract class MavenRunnerConfigurable implements SearchableConfigurable, private JComboBox myJdkCombo; private final DefaultComboBoxModel myJdkComboModel = new DefaultComboBoxModel(); private JCheckBox mySkipTestsCheckBox; - private MyPropertiesPanel myPropertiesPanel; + private MavenPropertiesPanel myPropertiesPanel; private Map myProperties; @@ -114,7 +113,9 @@ public abstract class MavenRunnerConfigurable implements SearchableConfigurable, propertiesPanel.add(mySkipTestsCheckBox = new JCheckBox("Skip tests"), BorderLayout.NORTH); mySkipTestsCheckBox.setMnemonic('t'); - propertiesPanel.add(myPropertiesPanel = new MyPropertiesPanel(), BorderLayout.CENTER); + + collectProperties(); + propertiesPanel.add(myPropertiesPanel = new MavenPropertiesPanel(myProperties), BorderLayout.CENTER); myPropertiesPanel.getEmptyText().setText("No properties defined"); c.gridx = 0; @@ -124,8 +125,6 @@ public abstract class MavenRunnerConfigurable implements SearchableConfigurable, c.fill = GridBagConstraints.BOTH; panel.add(propertiesPanel, c); - collectProperties(); - return panel; } @@ -135,9 +134,7 @@ public abstract class MavenRunnerConfigurable implements SearchableConfigurable, for (MavenProject each : s.getProjects()) { Properties properties = each.getProperties(); - for (Map.Entry p : properties.entrySet()) { - result.put((String)p.getKey(), (String)p.getValue()); - } + result.putAll((Map)properties); } myProperties = result; @@ -215,60 +212,4 @@ public abstract class MavenRunnerConfigurable implements SearchableConfigurable, data.setMavenProperties(myPropertiesPanel.getDataAsMap()); } - - private class MyPropertiesPanel extends AddEditRemovePanel> { - public MyPropertiesPanel() { - super(new MyPropertiesTableModel(), new ArrayList>(), null); - setPreferredSize(new Dimension(100, 100)); - } - - protected Pair addItem() { - return doAddOrEdit(new Pair("", "")); - } - - protected boolean removeItem(Pair o) { - return true; - } - - protected Pair editItem(Pair o) { - return doAddOrEdit(o); - } - - private Pair doAddOrEdit(Pair o) { - EditMavenPropertyDialog d = new EditMavenPropertyDialog(myProject, o, myProperties); - d.show(); - if (!d.isOK()) return null; - return d.getValue(); - } - - public Map getDataAsMap() { - Map result = new LinkedHashMap(); - for (Pair p : getData()) { - result.put(p.getFirst(), p.getSecond()); - } - return result; - } - - public void setDataFromMap(Map map) { - List> result = new ArrayList>(); - for (Map.Entry e : map.entrySet()) { - result.add(new Pair(e.getKey(), e.getValue())); - } - setData(result); - } - } - - private static class MyPropertiesTableModel extends AddEditRemovePanel.TableModel> { - public int getColumnCount() { - return 2; - } - - public String getColumnName(int c) { - return c == 0 ? "Name" : "Value"; - } - - public Object getField(Pair o, int c) { - return c == 0 ? o.getFirst() : o.getSecond(); - } - } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenFrameworkSupportProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenFrameworkSupportProvider.java index 78c3533f2dff..3b7d2b570a40 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenFrameworkSupportProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenFrameworkSupportProvider.java @@ -67,7 +67,7 @@ public class MavenFrameworkSupportProvider extends FrameworkSupportProvider { } else { new MavenModuleBuilderHelper(new MavenId("groupId", module.getName(), "1.0-SNAPSHOT"), null, null, false, false, null, - "Add Maven Support").configure(model.getProject(), root, true); + null, "Add Maven Support").configure(model.getProject(), root, true); } } }; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilder.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilder.java index 0d7273eac2ae..1fcd564002be 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilder.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilder.java @@ -33,6 +33,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.maven.model.MavenArchetype; import org.jetbrains.idea.maven.model.MavenId; +import org.jetbrains.idea.maven.project.MavenEnvironmentForm; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenUtil; @@ -41,6 +42,7 @@ import javax.swing.*; import java.io.File; import java.util.Collections; import java.util.List; +import java.util.Map; public class MavenModuleBuilder extends ModuleBuilder implements SourcePathsBuilder { private static final Icon BIG_ICON = IconLoader.getIcon("/modules/javaModule.png"); @@ -54,6 +56,10 @@ public class MavenModuleBuilder extends ModuleBuilder implements SourcePathsBuil private MavenId myProjectId; private MavenArchetype myArchetype; + private MavenEnvironmentForm myEnvironmentForm; + + private Map myPropertiesToCreateByArtifact; + public void setupRootModel(ModifiableRootModel rootModel) throws ConfigurationException { final Project project = rootModel.getProject(); @@ -64,8 +70,12 @@ public class MavenModuleBuilder extends ModuleBuilder implements SourcePathsBuil MavenUtil.runWhenInitialized(project, new DumbAwareRunnable() { public void run() { + if (myEnvironmentForm != null) { + myEnvironmentForm.setData(MavenProjectsManager.getInstance(project).getGeneralSettings()); + } + new MavenModuleBuilderHelper(myProjectId, myAggregatorProject, myParentProject, myInheritGroupId, - myInheritVersion, myArchetype, "Create new Maven module").configure(project, root, false); + myInheritVersion, myArchetype, myPropertiesToCreateByArtifact, "Create new Maven module").configure(project, root, false); } }); } @@ -96,7 +106,8 @@ public class MavenModuleBuilder extends ModuleBuilder implements SourcePathsBuil @Override public ModuleWizardStep[] createWizardSteps(WizardContext wizardContext, ModulesProvider modulesProvider) { - return new ModuleWizardStep[]{new MavenModuleWizardStep(wizardContext.getProject(), this)}; + return new ModuleWizardStep[]{new MavenModuleWizardStep(wizardContext.getProject(), this), + new SelectPropertiesStep(wizardContext.getProject(), this)}; } public MavenProject findPotentialParentProject(Project project) { @@ -170,4 +181,20 @@ public class MavenModuleBuilder extends ModuleBuilder implements SourcePathsBuil public MavenArchetype getArchetype() { return myArchetype; } + + public MavenEnvironmentForm getEnvironmentForm() { + return myEnvironmentForm; + } + + public void setEnvironmentForm(MavenEnvironmentForm environmentForm) { + myEnvironmentForm = environmentForm; + } + + public Map getPropertiesToCreateByArtifact() { + return myPropertiesToCreateByArtifact; + } + + public void setPropertiesToCreateByArtifact(Map propertiesToCreateByArtifact) { + myPropertiesToCreateByArtifact = propertiesToCreateByArtifact; + } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java index 7480bccbd758..c194329c73ac 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java @@ -61,6 +61,7 @@ public class MavenModuleBuilderHelper { private final boolean myInheritVersion; private final MavenArchetype myArchetype; + private final Map myPropertiesToCreateByArtifact; private final String myCommandName; @@ -70,6 +71,7 @@ public class MavenModuleBuilderHelper { boolean inheritGroupId, boolean inheritVersion, MavenArchetype archetype, + Map propertiesToCreateByArtifact, String commaneName) { myProjectId = projectId; myAggregatorProject = aggregatorProject; @@ -77,6 +79,8 @@ public class MavenModuleBuilderHelper { myInheritGroupId = inheritGroupId; myInheritVersion = inheritVersion; myArchetype = archetype; + myPropertiesToCreateByArtifact = propertiesToCreateByArtifact; + assert (archetype == null) == (propertiesToCreateByArtifact == null); myCommandName = commaneName; } @@ -194,14 +198,16 @@ public class MavenModuleBuilderHelper { Map props = settings.getMavenProperties(); props.put("interactiveMode", "false"); - props.put("archetypeGroupId", myArchetype.groupId); - props.put("archetypeArtifactId", myArchetype.artifactId); - props.put("archetypeVersion", myArchetype.version); - if (myArchetype.repository != null) props.put("archetypeRepository", myArchetype.repository); + //props.put("archetypeGroupId", myArchetype.groupId); + //props.put("archetypeArtifactId", myArchetype.artifactId); + //props.put("archetypeVersion", myArchetype.version); + //if (myArchetype.repository != null) props.put("archetypeRepository", myArchetype.repository); - props.put("groupId", myProjectId.getGroupId()); - props.put("artifactId", myProjectId.getArtifactId()); - props.put("version", myProjectId.getVersion()); + //props.put("groupId", myProjectId.getGroupId()); + //props.put("artifactId", myProjectId.getArtifactId()); + //props.put("version", myProjectId.getVersion()); + + props.putAll(myPropertiesToCreateByArtifact); runner.run(params, settings, new Runnable() { public void run() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java index e78e2d495aee..c52e04c20cac 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java @@ -24,7 +24,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.containers.Convertor; -import com.intellij.util.ui.AbstractLayoutManager; import com.intellij.util.ui.AsyncProcessIcon; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; @@ -45,7 +44,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.*; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; public class MavenModuleWizardStep extends ModuleWizardStep { private static final Icon WIZARD_ICON = IconLoader.getIcon("/addmodulewizard.png"); @@ -91,6 +89,8 @@ public class MavenModuleWizardStep extends ModuleWizardStep { private Object myCurrentUpdaterMarker; private final AsyncProcessIcon myLoadingIcon = new AsyncProcessIcon.Big(getClass() + ".loading"); + private boolean skipUpdateUI; + public MavenModuleWizardStep(@Nullable Project project, MavenModuleBuilder builder) { myProjectOrNull = project; myBuilder = builder; @@ -140,6 +140,12 @@ public class MavenModuleWizardStep extends ModuleWizardStep { myInheritVersionCheckBox.addActionListener(updatingListener); myUseArchetypeCheckBox.addActionListener(updatingListener); + myUseArchetypeCheckBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + archetypeMayBeChanged(); + } + }); myAddArchetypeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -155,6 +161,7 @@ public class MavenModuleWizardStep extends ModuleWizardStep { myArchetypesTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { updateArchetypeDescription(); + archetypeMayBeChanged(); } }); @@ -169,6 +176,20 @@ public class MavenModuleWizardStep extends ModuleWizardStep { myArchetypeDescriptionField.setBackground(UIUtil.getPanelBackground()); } + private void archetypeMayBeChanged() { + MavenArchetype selectedArchetype = getSelectedArchetype(); + if (((myBuilder.getArchetype() == null) != (selectedArchetype == null))) { + myBuilder.setArchetype(selectedArchetype); + skipUpdateUI = true; + try { + fireStateChanged(); + } + finally { + skipUpdateUI = false; + } + } + } + @Override public JComponent getPreferredFocusedComponent() { return myGroupIdField; @@ -253,6 +274,8 @@ public class MavenModuleWizardStep extends ModuleWizardStep { @Override public void updateStep() { + if (skipUpdateUI) return; + if (isMavenizedProject()) { MavenProject parent = myBuilder.findPotentialParentProject(myProjectOrNull); myAggregator = parent; @@ -429,7 +452,7 @@ public class MavenModuleWizardStep extends ModuleWizardStep { myArchetypesTree.setBackground(archetypesEnabled ? UIUtil.getListBackground() : UIUtil.getPanelBackground()); } - private String formatProjectString(MavenProject project) { + private static String formatProjectString(MavenProject project) { if (project == null) return ""; return project.getMavenId().getDisplayString(); } @@ -448,12 +471,13 @@ public class MavenModuleWizardStep extends ModuleWizardStep { myBuilder.setArchetype(getSelectedArchetype()); } + @Nullable private MavenArchetype getSelectedArchetype() { if (!myUseArchetypeCheckBox.isSelected() || myArchetypesTree.isSelectionEmpty()) return null; return getArchetypeInfoFromPathComponent(myArchetypesTree.getLastSelectedPathComponent()); } - private MavenArchetype getArchetypeInfoFromPathComponent(Object sel) { + private static MavenArchetype getArchetypeInfoFromPathComponent(Object sel) { return (MavenArchetype)((DefaultMutableTreeNode)sel).getUserObject(); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectPropertiesStep.form b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectPropertiesStep.form new file mode 100644 index 000000000000..fc42a0ccb4b5 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectPropertiesStep.form @@ -0,0 +1,36 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectPropertiesStep.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectPropertiesStep.java new file mode 100644 index 000000000000..7f18f9426189 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectPropertiesStep.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.maven.wizards; + +import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.util.containers.hash.HashMap; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.execution.MavenPropertiesPanel; +import org.jetbrains.idea.maven.indices.MavenIndex; +import org.jetbrains.idea.maven.model.MavenArchetype; +import org.jetbrains.idea.maven.model.MavenId; +import org.jetbrains.idea.maven.project.MavenEnvironmentForm; +import org.jetbrains.idea.maven.project.MavenGeneralSettings; +import org.jetbrains.idea.maven.project.MavenProjectsManager; + +import javax.swing.*; +import java.awt.*; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Sergey Evdokimov + */ +public class SelectPropertiesStep extends ModuleWizardStep { + + private final Project myProjectOrNull; + private final MavenModuleBuilder myBuilder; + + private JPanel myMainPanel; + private JPanel myEnvironmentPanel; + private JPanel myPropertiesPanel; + + private MavenEnvironmentForm myEnvironmentForm; + private MavenPropertiesPanel myMavenPropertiesPanel; + + private Map myAvailableProperties = new HashMap(); + + public SelectPropertiesStep(@Nullable Project project, MavenModuleBuilder builder) { + myProjectOrNull = project; + myBuilder = builder; + + initComponents(); + } + + private void initComponents() { + myEnvironmentForm = new MavenEnvironmentForm(); + + Project project = myProjectOrNull == null ? ProjectManager.getInstance().getDefaultProject() : myProjectOrNull; + myEnvironmentForm.getData(MavenProjectsManager.getInstance(project).getGeneralSettings().clone()); + + myEnvironmentPanel.add(myEnvironmentForm.createComponent(), BorderLayout.CENTER); + + myMavenPropertiesPanel = new MavenPropertiesPanel(myAvailableProperties); + myPropertiesPanel.add(myMavenPropertiesPanel); + } + + @Override + public void updateStep() { + MavenArchetype archetype = myBuilder.getArchetype(); + + Map props = new LinkedHashMap(); + + MavenId projectId = myBuilder.getProjectId(); + + props.put("groupId", projectId.getGroupId()); + props.put("artifactId", projectId.getArtifactId()); + props.put("version", projectId.getVersion()); + + props.put("archetypeGroupId", archetype.groupId); + props.put("archetypeArtifactId", archetype.artifactId); + props.put("archetypeVersion", archetype.version); + if (archetype.repository != null) props.put("archetypeRepository", archetype.repository); + + myMavenPropertiesPanel.setDataFromMap(props); + } + + @Override + public JComponent getComponent() { + return myMainPanel; + } + + @Override + public boolean isStepVisible() { + return myBuilder.getArchetype() != null; + } + + @Override + public void updateDataModel() { + myBuilder.setEnvironmentForm(myEnvironmentForm); + myBuilder.setPropertiesToCreateByArtifact(myMavenPropertiesPanel.getDataAsMap()); + } +} diff --git a/plugins/svn4idea/lib/svnkit-javahl.jar b/plugins/svn4idea/lib/svnkit-javahl.jar index f5615cf20595..00f40fa3353f 100644 Binary files a/plugins/svn4idea/lib/svnkit-javahl.jar and b/plugins/svn4idea/lib/svnkit-javahl.jar differ diff --git a/plugins/svn4idea/lib/svnkit-javahl16.zip b/plugins/svn4idea/lib/svnkit-javahl16.zip index 9104eeabdd42..d8cff562d17b 100644 Binary files a/plugins/svn4idea/lib/svnkit-javahl16.zip and b/plugins/svn4idea/lib/svnkit-javahl16.zip differ diff --git a/plugins/svn4idea/lib/svnkit.jar b/plugins/svn4idea/lib/svnkit.jar index e7f60fae5f49..6863da269bc1 100644 Binary files a/plugins/svn4idea/lib/svnkit.jar and b/plugins/svn4idea/lib/svnkit.jar differ diff --git a/plugins/svn4idea/lib/svnkitsrc.zip b/plugins/svn4idea/lib/svnkitsrc.zip index 49b3ac842c71..d2b77aa393c8 100644 Binary files a/plugins/svn4idea/lib/svnkitsrc.zip and b/plugins/svn4idea/lib/svnkitsrc.zip differ diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnChangeProviderContext.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnChangeProviderContext.java index 1b41336aff40..aad0f0d5d762 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnChangeProviderContext.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnChangeProviderContext.java @@ -30,6 +30,7 @@ import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLock; import org.tmatesoft.svn.core.SVNNodeKind; +import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb; import org.tmatesoft.svn.core.wc.*; import java.io.File; @@ -191,7 +192,8 @@ class SvnChangeProviderContext implements StatusReceiver { } void processStatus(final FilePath filePath, final SVNStatus status) throws SVNException { - if (WorkingCopyFormat.ONE_DOT_SEVEN.getFormat() != status.getWorkingCopyFormat()) { + final int wcFormat = status.getWorkingCopyFormat(); + if (WorkingCopyFormat.ONE_DOT_SEVEN.getFormat() != wcFormat && ISVNWCDb.WC_FORMAT_17 != wcFormat) { loadEntriesFile(filePath); } if (status != null) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SVNLockWrapper.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SVNLockWrapper.java new file mode 100644 index 000000000000..ab83dc2d2933 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SVNLockWrapper.java @@ -0,0 +1,99 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn17.commandLine; + +import org.tmatesoft.svn.core.SVNLock; + +import java.util.Date; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/21/12 + * Time: 2:33 PM + */ +public class SVNLockWrapper { + private String myPath; + private String myID; + private String myOwner; + private String myComment; + private Date myCreationDate; + private Date myExpirationDate; + + public SVNLockWrapper(String path, String ID, String owner, String comment, Date creationDate, Date expirationDate) { + myPath = path; + myID = ID; + myOwner = owner; + myComment = comment; + myCreationDate = creationDate; + myExpirationDate = expirationDate; + } + + public SVNLockWrapper() { + } + + public SVNLock create() { + return new SVNLock(myPath, myID, myOwner, myComment, myCreationDate, myExpirationDate); + } + + public String getPath() { + return myPath; + } + + public void setPath(String path) { + myPath = path; + } + + public String getID() { + return myID; + } + + public void setID(String ID) { + myID = ID; + } + + public String getOwner() { + return myOwner; + } + + public void setOwner(String owner) { + myOwner = owner; + } + + public String getComment() { + return myComment; + } + + public void setComment(String comment) { + myComment = comment; + } + + public Date getCreationDate() { + return myCreationDate; + } + + public void setCreationDate(Date creationDate) { + myCreationDate = creationDate; + } + + public Date getExpirationDate() { + return myExpirationDate; + } + + public void setExpirationDate(Date expirationDate) { + myExpirationDate = expirationDate; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommandLineStatusClient.java index 24a2763c6ded..bd2aec69a803 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommandLineStatusClient.java @@ -123,7 +123,7 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { final String[] changelistName = new String[1]; final SvnStatusHandler[] svnHandl = new SvnStatusHandler[1]; - svnHandl[0] = new SvnStatusHandler(new SvnStatusHandler.DataCallback() { + svnHandl[0] = new SvnStatusHandler(new SvnStatusHandler.ExternalDataCallback() { @Override public void switchPath() { final PortableStatus pending = svnHandl[0].getPending(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java index 4f7e42060b68..7188681c8472 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java @@ -44,6 +44,8 @@ public class SvnStatusHandler extends DefaultHandler { private List myDefaultListStatuses; private MultiMap myCurrentListChanges; private PortableStatus myPending; + private boolean myInRemoteStatus; + private SVNLockWrapper myLockWrapper; private final List myParseStack; private final Map> myElementsMap; @@ -52,7 +54,7 @@ public class SvnStatusHandler extends DefaultHandler { private final StringBuilder mySb; private boolean myAnythingReported; - public SvnStatusHandler(final DataCallback dataCallback, File base, final Convertor infoGetter) { + public SvnStatusHandler(final ExternalDataCallback dataCallback, File base, final Convertor infoGetter) { myBase = base; myParseStack = new ArrayList(); myParseStack.add(new Fake()); @@ -62,6 +64,31 @@ public class SvnStatusHandler extends DefaultHandler { if (dataCallback != null) { myDataCallback = new DataCallback() { + @Override + public void startLock() { + myLockWrapper = new SVNLockWrapper(); + } + + @Override + public void endLock() { + if (myInRemoteStatus) { + myPending.setRemoteLock(myLockWrapper.create()); + } else { + myPending.setLocalLock(myLockWrapper.create()); + } + myLockWrapper = null; + } + + @Override + public void startRemoteStatus() { + myInRemoteStatus = true; + } + + @Override + public void endRemoteStatus() { + myInRemoteStatus = false; + } + @Override public void switchPath() { myAnythingReported = true; @@ -76,6 +103,31 @@ public class SvnStatusHandler extends DefaultHandler { }; } else { myDataCallback = new DataCallback() { + @Override + public void startLock() { + myLockWrapper = new SVNLockWrapper(); + } + + @Override + public void endLock() { + if (myInRemoteStatus) { + myPending.setRemoteLock(myLockWrapper.create()); + } else { + myPending.setLocalLock(myLockWrapper.create()); + } + myLockWrapper = null; + } + + @Override + public void startRemoteStatus() { + myInRemoteStatus = true; + } + + @Override + public void endRemoteStatus() { + myInRemoteStatus = false; + } + @Override public void switchPath() { myAnythingReported = true; @@ -125,6 +177,44 @@ public class SvnStatusHandler extends DefaultHandler { } private void fillElements() { + myElementsMap.put("repos-status", new Getter() { + @Override + public ElementHandlerBase get() { + return new ReposStatus(); + } + }); + myElementsMap.put("lock", new Getter() { + @Override + public ElementHandlerBase get() { + return new Lock(); + } + }); + + myElementsMap.put("token", new Getter() { + @Override + public ElementHandlerBase get() { + return new LockToken(); + } + }); + myElementsMap.put("owner", new Getter() { + @Override + public ElementHandlerBase get() { + return new LockOwner(); + } + }); + myElementsMap.put("comment", new Getter() { + @Override + public ElementHandlerBase get() { + return new LockComment(); + } + }); + myElementsMap.put("created", new Getter() { + @Override + public ElementHandlerBase get() { + return new LockCreatedDate(); + } + }); +// -- myElementsMap.put("status", new Getter() { @Override public ElementHandlerBase get() { @@ -185,7 +275,7 @@ public class SvnStatusHandler extends DefaultHandler { assertSAX(! myParseStack.isEmpty()); ElementHandlerBase current = myParseStack.get(myParseStack.size() - 1); if (mySb.length() > 0) { - current.characters(mySb.toString().trim(), myPending); + current.characters(mySb.toString().trim(), myPending, myLockWrapper); mySb.setLength(0); } @@ -194,7 +284,8 @@ public class SvnStatusHandler extends DefaultHandler { if (createNewChild) { assertSAX(myElementsMap.containsKey(qName)); final ElementHandlerBase newChild = myElementsMap.get(qName).get(); - newChild.updateStatus(attributes, myPending); + newChild.preEffect(myDataCallback); + newChild.updateStatus(attributes, myPending, myLockWrapper); myParseStack.add(newChild); return; } else { @@ -235,7 +326,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { } @Override @@ -247,7 +338,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { } } @@ -257,7 +348,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { } @Override @@ -269,7 +360,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { final SVNDate date = SVNDate.parseDate(s); //if (SVNDate.NULL.equals(date)) return; pending.setRemoteDate(date); @@ -282,7 +373,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { } @Override @@ -294,7 +385,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { pending.setRemoteAuthor(s); } } @@ -310,7 +401,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { final String revision = attributes.getValue("revision"); if (! StringUtil.isEmptyOrSpaces(revision)) { try { @@ -331,7 +422,177 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { + } + } + + /* + opaquelocktoken:27ee743a-5376-fc4a-a209-b7834e1a3f39 + admin + LLL + 2012-02-21T09:59:39.771077Z + */ + + /* + opaquelocktoken:e21e93d2-0623-b347-bb39-900b01387555 + admin + 787878 + 2012-02-21T10:17:29.160005Z + + + + + opaquelocktoken:e21e93d2-0623-b347-bb39-900b01387555 + admin + 787878 + 2012-02-21T10:17:29.160005Z + + + */ + + private static class LockCreatedDate extends ElementHandlerBase { + private LockCreatedDate() { + super(new String[]{}, new String[]{}); + } + + @Override + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { + } + + @Override + public void postEffect(DataCallback callback) { + } + + @Override + public void preEffect(DataCallback callback) { + } + + @Override + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { + final SVNDate date = SVNDate.parseDate(s); + lock.setCreationDate(date); + } + } + + private static class LockComment extends ElementHandlerBase { + private LockComment() { + super(new String[]{}, new String[]{}); + } + + @Override + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { + } + + @Override + public void postEffect(DataCallback callback) { + } + + @Override + public void preEffect(DataCallback callback) { + } + + @Override + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { + lock.setComment(s); + } + } + + private static class LockOwner extends ElementHandlerBase { + private LockOwner() { + super(new String[]{}, new String[]{}); + } + + @Override + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { + } + + @Override + public void postEffect(DataCallback callback) { + } + + @Override + public void preEffect(DataCallback callback) { + } + + @Override + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { + lock.setOwner(s); + } + } + + private static class LockToken extends ElementHandlerBase { + private LockToken() { + super(new String[]{}, new String[]{}); + } + + @Override + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { + } + + @Override + public void postEffect(DataCallback callback) { + } + + @Override + public void preEffect(DataCallback callback) { + } + + @Override + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { + lock.setID(s); + } + } + + private static class Lock extends ElementHandlerBase { + private Lock() { + super(new String[]{"token","owner","comment","created"}, new String[]{}); + } + + @Override + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { + // todo check inside-repository path + lock.setPath(status.getPath()); + } + + @Override + public void postEffect(DataCallback callback) { + callback.endLock(); + } + + @Override + public void preEffect(DataCallback callback) { + callback.startLock(); + } + + @Override + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { + } + } + + private static class ReposStatus extends ElementHandlerBase { + private ReposStatus() { + super(new String[]{"lock"}, new String[]{}); + } + + @Override + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { + //not used now + } + + @Override + public void postEffect(DataCallback callback) { + callback.endRemoteStatus(); + } + + @Override + public void preEffect(DataCallback callback) { + callback.startRemoteStatus(); + } + + @Override + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { } } @@ -343,7 +604,7 @@ public class SvnStatusHandler extends DefaultHandler { */ private static class WcStatus extends ElementHandlerBase { private WcStatus() { - super(new String[]{"commit"}, new String[]{}); + super(new String[]{"commit", "lock"}, new String[]{}); } /**/ @Override - protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { final String props = attributes.getValue("props"); assertSAX(props != null); final SVNStatusType propertiesStatus = StatusCallbackConvertor.convert(org.apache.subversion.javahl.types.Status.Kind.valueOf(props)); @@ -401,7 +662,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { } } @@ -414,7 +675,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { final String path = attributes.getValue("path"); assertSAX(path != null); final File file = new File(myBase, path); @@ -438,7 +699,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { } } @@ -450,7 +711,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException { final String name = attributes.getValue("name"); assertSAX(! StringUtil.isEmptyOrSpaces(name)); myName = name; @@ -466,7 +727,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { } } @@ -476,7 +737,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) { } @Override @@ -488,7 +749,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { } } @@ -498,7 +759,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - protected void updateStatus(Attributes attributes, PortableStatus status) { + protected void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) { } @Override @@ -510,7 +771,7 @@ public class SvnStatusHandler extends DefaultHandler { } @Override - public void characters(String s, PortableStatus pending) { + public void characters(String s, PortableStatus pending, SVNLockWrapper lock) { } } @@ -523,7 +784,7 @@ public class SvnStatusHandler extends DefaultHandler { myAwaitedChildrenMultiple = new HashSet(Arrays.asList(awaitedChildrenMultiple)); } - protected abstract void updateStatus(Attributes attributes, PortableStatus status) throws SAXException; + protected abstract void updateStatus(Attributes attributes, PortableStatus status, SVNLockWrapper lock) throws SAXException; public abstract void postEffect(final DataCallback callback); public abstract void preEffect(final DataCallback callback); @@ -534,10 +795,19 @@ public class SvnStatusHandler extends DefaultHandler { return myAwaitedChildren.remove(qName); } - public abstract void characters(String s, PortableStatus pending); + public abstract void characters(String s, PortableStatus pending, SVNLockWrapper lock); } - public interface DataCallback { + public interface ExternalDataCallback { + void switchPath(); + void switchChangeList(final String newList); + } + + private interface DataCallback extends ExternalDataCallback { + void startRemoteStatus(); + void endRemoteStatus(); + void startLock(); + void endLock(); void switchPath(); void switchChangeList(final String newList); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnChangeList.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnChangeList.java index 3a12a1efa815..eba00c54ea7a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnChangeList.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnChangeList.java @@ -25,6 +25,7 @@ package org.jetbrains.idea.svn17.history; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FilePathImpl; @@ -477,7 +478,7 @@ public class SvnChangeList implements CommittedChangeList { final SimpleContentRevision after = createRevisionForProperty(becameUrl, change.getAfterRevision(), filePath); final String beforeText = before == null ? null : before.getContent(); final String afterText = after == null ? null : after.getContent(); - if (Comparing.equal(beforeText, afterText)) return; + if (Comparing.equal(beforeText, afterText) || StringUtil.isEmptyOrSpaces(beforeText) && StringUtil.isEmptyOrSpaces(afterText)) return; final Change additional = new Change(before, after); change.addAdditionalLayerElement(SvnChangeProvider.PROPERTY_LAYER, additional); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/UpdateEventHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/UpdateEventHandler.java index 52639ff773bb..44e71a60f19e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/UpdateEventHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/UpdateEventHandler.java @@ -129,6 +129,9 @@ public class UpdateEventHandler implements ISVNEventHandler { else if (event.getContentsStatus() == SVNStatusType.UNCHANGED && (event.getPropertiesStatus() == SVNStatusType.UNCHANGED || event.getPropertiesStatus() == SVNStatusType.UNKNOWN)) { myText2 = SvnBundle.message("progres.text2.updated", displayPath); + } else if (SVNStatusType.INAPPLICABLE.equals(event.getContentsStatus()) && + (event.getPropertiesStatus() == SVNStatusType.UNCHANGED || event.getPropertiesStatus() == SVNStatusType.UNKNOWN)) { + myText2 = SvnBundle.message("progres.text2.updated", displayPath); } else { myText2 = "";