mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
@@ -2065,10 +2065,6 @@ public class CompileDriver {
|
||||
try {
|
||||
for (FileProcessingCompiler.ProcessingItem item : items) {
|
||||
final VirtualFile file = item.getFile();
|
||||
if (file == null) {
|
||||
LOG.error("FileProcessingCompiler.ProcessingItem.getFile() must not return null: compiler " + adapter.getCompiler().getDescription());
|
||||
continue;
|
||||
}
|
||||
final String url = file.getUrl();
|
||||
allUrls.add(url);
|
||||
if (!forceCompile && cache.getTimestamp(url) == file.getTimeStamp()) {
|
||||
|
||||
@@ -28,22 +28,18 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiShortNamesCache;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 8/5/11
|
||||
* Time: 8:36 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
* User: Irina.Chernushina
|
||||
* Date: 8/5/11
|
||||
* Time: 8:36 PM
|
||||
*/
|
||||
public class ExceptionWorker {
|
||||
@NonNls private static final String AT = "at";
|
||||
private static final String AT_PREFIX = AT + " ";
|
||||
|
||||
private static final TextAttributes HYPERLINK_ATTRIBUTES = EditorColorsManager
|
||||
.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES);
|
||||
@@ -54,7 +50,7 @@ public class ExceptionWorker {
|
||||
private PsiClass myClass;
|
||||
private PsiFile myFile;
|
||||
private String myMethod;
|
||||
private Trinity<TextRange,TextRange,TextRange> myInfo;
|
||||
private Trinity<TextRange, TextRange, TextRange> myInfo;
|
||||
|
||||
public ExceptionWorker(Project project, final GlobalSearchScope searchScope) {
|
||||
myProject = project;
|
||||
@@ -71,31 +67,32 @@ public class ExceptionWorker {
|
||||
myMethod = myInfo.getSecond().substring(line);
|
||||
String className = myInfo.first.substring(line).trim();
|
||||
final int dollarIndex = className.indexOf('$');
|
||||
if (dollarIndex >= 0){
|
||||
if (dollarIndex >= 0) {
|
||||
className = className.substring(0, dollarIndex);
|
||||
}
|
||||
|
||||
final int lparenthIndex = myInfo.third.getStartOffset();
|
||||
final int rparenthIndex = myInfo.third.getEndOffset();
|
||||
final String fileAndLine = line.substring(lparenthIndex + 1, rparenthIndex).trim();
|
||||
final String fileAndLine = line.substring(lparenthIndex + 1, rparenthIndex);
|
||||
|
||||
final int colonIndex = fileAndLine.lastIndexOf(':');
|
||||
if (colonIndex < 0) return;
|
||||
if (colonIndex <= 0) return;
|
||||
|
||||
final String lineString = fileAndLine.substring(colonIndex + 1);
|
||||
try{
|
||||
final String lineString = fileAndLine.substring(colonIndex + 1).trim();
|
||||
try {
|
||||
final int lineNumber = Integer.parseInt(lineString);
|
||||
final PsiManager manager = PsiManager.getInstance(myProject);
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(manager.getProject());
|
||||
myClass = psiFacade.findClass(className, mySearchScope);
|
||||
if (myClass == null) {
|
||||
myClass = psiFacade.findClass(className, GlobalSearchScope.allScope(myProject));
|
||||
/*if (myClass == null) {//try to find class according to all dollars in package name
|
||||
myClass = psiFacade.findClass(className, GlobalSearchScope.allScope(myProject));
|
||||
}*/
|
||||
if (myClass == null) return;
|
||||
myClass = myClass != null ? myClass : psiFacade.findClass(className, GlobalSearchScope.allScope(myProject));
|
||||
myFile = myClass == null ? null : (PsiFile)myClass.getContainingFile().getNavigationElement();
|
||||
if (myFile == null) {
|
||||
// try find the file with the required name
|
||||
PsiFile[] files = PsiShortNamesCache.getInstance(myProject).getFilesByName(fileAndLine.substring(0, colonIndex).trim());
|
||||
if (files.length > 0) {
|
||||
myFile = files[0];
|
||||
}
|
||||
}
|
||||
myFile = (PsiFile) myClass.getContainingFile().getNavigationElement();
|
||||
if (myFile == null) return;
|
||||
|
||||
/*
|
||||
@@ -120,7 +117,7 @@ public class ExceptionWorker {
|
||||
}
|
||||
myResult = new Filter.Result(highlightStartOffset, highlightEndOffset, linkInfo, attributes);
|
||||
}
|
||||
catch(NumberFormatException e){
|
||||
catch (NumberFormatException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -147,34 +144,27 @@ public class ExceptionWorker {
|
||||
|
||||
@Nullable
|
||||
static Trinity<TextRange, TextRange, TextRange> parseExceptionLine(final String line) {
|
||||
int atIndex = line.indexOf(AT_PREFIX);
|
||||
if (atIndex < 0) return null;
|
||||
int lparenIdx = line.indexOf('(');
|
||||
int rparenIdx = line.indexOf(')', lparenIdx + 1);
|
||||
if (lparenIdx < 0 || rparenIdx <= lparenIdx) return null;
|
||||
|
||||
final int lparenthIndex = line.indexOf('(', atIndex);
|
||||
if (lparenthIndex < 0) return null;
|
||||
final int lastDotIndex = line.lastIndexOf('.', lparenthIndex);
|
||||
if (lastDotIndex < 0 || lastDotIndex < atIndex) return null;
|
||||
|
||||
final int rparenthIndex = line.indexOf(')', lparenthIndex);
|
||||
if (rparenthIndex < 0) return null;
|
||||
int dotIdx = line.lastIndexOf('.', lparenIdx);
|
||||
int startIdx = handleSpaces(line, dotIdx, -1, false);
|
||||
if (startIdx == dotIdx) return null;
|
||||
|
||||
// class, method, link
|
||||
return Trinity.create(adjustedRange(line, atIndex + AT_PREFIX.length(), lastDotIndex),
|
||||
adjustedRange(line, lastDotIndex + 1, lparenthIndex), new TextRange(lparenthIndex, rparenthIndex));
|
||||
return Trinity.create(new TextRange(startIdx + 1, handleSpaces(line, dotIdx, -1, true)),
|
||||
new TextRange(handleSpaces(line, dotIdx + 1, 1, true), handleSpaces(line, lparenIdx + 1, -1, true)),
|
||||
new TextRange(lparenIdx, rparenIdx));
|
||||
}
|
||||
|
||||
private static TextRange adjustedRange(final String line, final int start, final int end) {
|
||||
String sub = line.substring(start, end);
|
||||
return new TextRange(start, end - spacesEnd(sub));
|
||||
}
|
||||
|
||||
private static int spacesEnd(final String s) {
|
||||
int cnt = 0;
|
||||
for (int i = s.length() - 1; i >= 0; i--) {
|
||||
final char c = s.charAt(i);
|
||||
if (! Character.isSpaceChar(c)) return cnt;
|
||||
++ cnt;
|
||||
private static int handleSpaces(String line, int pos, int delta, boolean skip) {
|
||||
int len = line.length();
|
||||
while (pos >= 0 && pos < len) {
|
||||
final char c = line.charAt(pos);
|
||||
if (skip != Character.isSpaceChar(c)) break;
|
||||
pos += delta;
|
||||
}
|
||||
return 0;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ class ServerState {
|
||||
lib.setClasspath(library.getPaths());
|
||||
}
|
||||
else {
|
||||
LOG.info("Failed to load global library " + lib.getName());
|
||||
LOG.info("Failed to load global library " + library.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -104,6 +104,8 @@ public interface ActionToolbar extends SwitchProvider, QuickActionProvider {
|
||||
*/
|
||||
void updateActionsImmediately();
|
||||
|
||||
boolean hasVisibleActions();
|
||||
|
||||
/**
|
||||
* @param component will be used for datacontext computations
|
||||
*/
|
||||
|
||||
+5
@@ -870,6 +870,11 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleActions() {
|
||||
return !myVisibleActions.isEmpty();
|
||||
}
|
||||
|
||||
public void setTargetComponent(final JComponent component) {
|
||||
myTargetComponent = component;
|
||||
|
||||
|
||||
@@ -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.roots;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitRootError {
|
||||
|
||||
private final Type myType;
|
||||
@NotNull private final VirtualFile myRoot;
|
||||
|
||||
enum Type {
|
||||
EXTRA_ROOT,
|
||||
UNREGISTERED_ROOT
|
||||
}
|
||||
|
||||
GitRootError(@NotNull Type type, @NotNull VirtualFile root) {
|
||||
myType = type;
|
||||
myRoot = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GitRootError{" +
|
||||
"myType=" + myType +
|
||||
", myRoot=" + myRoot +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GitRootError error = (GitRootError)o;
|
||||
|
||||
if (!myRoot.equals(error.myRoot)) return false;
|
||||
if (myType != error.myType) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myType != null ? myType.hashCode() : 0;
|
||||
result = 31 * result + myRoot.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.roots;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.PlatformFacade;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Detects actual Git roots and compares them to the ones registered in Settings | Version Control.
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitRootErrorsFinder {
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
private final PlatformFacade myPlatformFacade;
|
||||
|
||||
GitRootErrorsFinder(@NotNull Project project, @NotNull PlatformFacade platformFacade) {
|
||||
myProject = project;
|
||||
myPlatformFacade = platformFacade;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Collection<GitRootError> find() {
|
||||
ProjectLevelVcsManager vcsManager = myPlatformFacade.getVcsManager(myProject);
|
||||
Collection<VirtualFile> vcsRoots = Arrays.asList(vcsManager.getRootsUnderVcs(myPlatformFacade.getVcs(myProject)));
|
||||
Collection<VirtualFile> gitRoots = new GitRootDetector(myProject).detect().getRoots();
|
||||
Collection<GitRootError> errors = new ArrayList<GitRootError>();
|
||||
for (VirtualFile vcsRoot : vcsRoots) {
|
||||
if (!gitRoots.contains(vcsRoot)) {
|
||||
errors.add(new GitRootError(GitRootError.Type.EXTRA_ROOT, vcsRoot));
|
||||
}
|
||||
}
|
||||
for (VirtualFile gitRoot : gitRoots) {
|
||||
if (!vcsRoots.contains(gitRoot)) {
|
||||
errors.add(new GitRootError(GitRootError.Type.UNREGISTERED_ROOT, gitRoot));
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -107,13 +107,15 @@ public class GitMergeUpdater extends GitUpdater {
|
||||
final GitMerger merger,
|
||||
GitLineHandler mergeHandler) {
|
||||
final MergeError error = mergeLineListener.getMergeError();
|
||||
LOG.info("doUpdate merge error: " + error);
|
||||
LOG.info("merge error: " + error);
|
||||
if (error == MergeError.CONFLICT) {
|
||||
LOG.info("Conflict detected");
|
||||
final boolean allMerged =
|
||||
new MyConflictResolver(myProject, merger, myRoot).merge();
|
||||
return allMerged ? GitUpdateResult.SUCCESS : GitUpdateResult.INCOMPLETE;
|
||||
}
|
||||
else if (error == MergeError.LOCAL_CHANGES) {
|
||||
LOG.info("Local changes would be overwritten by merge");
|
||||
final List<FilePath> paths = getFilesOverwrittenByMerge(mergeLineListener.getOutput());
|
||||
final Collection<Change> changes = getLocalChangesFilteredByFiles(paths);
|
||||
final ChangeListViewerDialog dialog = new ChangeListViewerDialog(myProject, changes, false) {
|
||||
@@ -129,12 +131,16 @@ public class GitMergeUpdater extends GitUpdater {
|
||||
}
|
||||
});
|
||||
return GitUpdateResult.ERROR;
|
||||
} else if (untrackedFilesWouldBeOverwrittenByMergeDetector.wasMessageDetected()) {
|
||||
}
|
||||
else if (untrackedFilesWouldBeOverwrittenByMergeDetector.wasMessageDetected()) {
|
||||
LOG.info("handleMergeFailure: untracked files would be overwritten by merge");
|
||||
UntrackedFilesNotifier.notifyUntrackedFilesOverwrittenBy(myProject, untrackedFilesWouldBeOverwrittenByMergeDetector.getFiles(), "merge");
|
||||
return GitUpdateResult.ERROR;
|
||||
} else {
|
||||
GitUIUtil.notifyImportantError(myProject, "Error merging", GitUIUtil.stringifyErrors(mergeHandler.errors()));
|
||||
}
|
||||
else {
|
||||
String errors = GitUIUtil.stringifyErrors(mergeHandler.errors());
|
||||
LOG.info("Unknown error: " + errors);
|
||||
GitUIUtil.notifyImportantError(myProject, "Error merging", errors);
|
||||
return GitUpdateResult.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,11 +193,12 @@ public class GitUpdateProcess {
|
||||
notifyImportantError(myProject, "Error updating " + rootName,
|
||||
"Updating " + rootName + " failed with an error: " + e.getLocalizedMessage());
|
||||
} finally {
|
||||
if (!incomplete) {
|
||||
restoreLocalChanges(context);
|
||||
} else {
|
||||
if (incomplete || !success) {
|
||||
mySaver.notifyLocalChangesAreNotRestored();
|
||||
}
|
||||
else {
|
||||
restoreLocalChanges(context);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.roots
|
||||
|
||||
import git4idea.test.GitMockVirtualFile
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class AbstractGitRootTest {
|
||||
|
||||
/**
|
||||
* Creates the necessary temporary directories in the filesystem with empty ".git" directories for given roots.
|
||||
* And creates an instance of the project.
|
||||
* @param gitRoots path to actual .git roots, relative to the project dir.
|
||||
*/
|
||||
Project initProject(Collection<String> gitRoots, Collection<String> projectStructure) {
|
||||
String projectDir = createDirs(gitRoots)
|
||||
Project project = [
|
||||
getBaseDir: { new GitMockVirtualFile(projectDir) }
|
||||
] as Project
|
||||
createProjectStructure(project, projectStructure);
|
||||
project
|
||||
}
|
||||
|
||||
void createProjectStructure(Project project, Collection<String> paths) {
|
||||
paths.each { String path ->
|
||||
File file = new File(project.baseDir.path + "/" + path)
|
||||
file.mkdir()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return path to the project
|
||||
*/
|
||||
private static String createDirs(Collection<String> gitRoots) {
|
||||
if (gitRoots.empty) {
|
||||
return FileUtil.createTempDirectory("grdt", null);
|
||||
}
|
||||
|
||||
File baseDir = createBaseTempDir()
|
||||
int maxDepth = findMaxDepthAboveProject(gitRoots)
|
||||
File projectDir = createChild(baseDir, maxDepth)
|
||||
gitRoots.each { String path ->
|
||||
File file = new File(projectDir.path + "/" + path)
|
||||
file.mkdirs()
|
||||
file.deleteOnExit()
|
||||
|
||||
File gitDir = new File(file, ".git")
|
||||
gitDir.mkdir()
|
||||
gitDir.deleteOnExit()
|
||||
}
|
||||
return projectDir.path
|
||||
}
|
||||
|
||||
private static File createBaseTempDir() {
|
||||
FileUtil.createTempDirectory("pref", null)
|
||||
}
|
||||
|
||||
private static File createChild(File base, int depth) {
|
||||
File dir = base
|
||||
depth.times { dir = FileUtil.createTempDirectory(dir, "grdt", null)}
|
||||
dir
|
||||
}
|
||||
|
||||
// Assuming that there are no ".." inside the path - only in the beginning
|
||||
static int findMaxDepthAboveProject(Collection<String> paths) {
|
||||
def len = { String path -> path.split("/").count("..") }
|
||||
len(paths.max(len))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,13 +58,13 @@ class GitIntegrationEnablerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Simplest case - 1 root for the whole project => just add VCS root"() {
|
||||
void "1 root for the whole project, then just add VCS root"() {
|
||||
doTest given(["."]),
|
||||
expect(git_init: [])
|
||||
}
|
||||
|
||||
@Test
|
||||
void "No Git roots => init & notify"() {
|
||||
void "No Git roots, then init & notify"() {
|
||||
doTest given( [], false ),
|
||||
expect( git_init: ["."],
|
||||
vcs_roots: ["."],
|
||||
@@ -72,28 +72,28 @@ class GitIntegrationEnablerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Below Git, no inside => notify"() {
|
||||
void "Below Git, no inside, then notify"() {
|
||||
doTest given([".."], true, true),
|
||||
expect( git_init: [],
|
||||
notification("Added Git root: ${path("..")}"))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Git for project, some inside => notify"() {
|
||||
void "Git for project, some inside, then notify"() {
|
||||
doTest given( [".", "community"]),
|
||||
expect(git_init: [],
|
||||
notification("Added Git roots: ${path(".")}, ${path("community")}"))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Below Git, some inside => notify"() {
|
||||
void "Below Git, some inside, then notify"() {
|
||||
doTest given(["..", "community"], true, true),
|
||||
expect(git_init: [],
|
||||
notification("Added Git roots: ${path("..")}, ${path("community")}"))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Not under Git, some inside => notify"() {
|
||||
void "Not under Git, some inside, then notify"() {
|
||||
doTest given( ["community", "contrib"], false, false),
|
||||
expect(git_init: [],
|
||||
notification("Added Git roots: ${path("community")}, ${path("contrib")}"))
|
||||
|
||||
@@ -16,20 +16,18 @@
|
||||
package git4idea.roots
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import git4idea.test.GitMockVirtualFile
|
||||
import git4idea.test.GitGTestUtil
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.assertEquals
|
||||
import static org.junit.Assert.fail
|
||||
import git4idea.test.GitGTestUtil
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitRootDetectorTest {
|
||||
class GitRootDetectorTest extends AbstractGitRootTest {
|
||||
|
||||
Project myProject
|
||||
|
||||
@@ -126,7 +124,7 @@ class GitRootDetectorTest {
|
||||
* @param map
|
||||
*/
|
||||
private void doTest(Map map) {
|
||||
initProject(map.gits, map.project)
|
||||
myProject = initProject(map.gits, map.project)
|
||||
testInfo empty: map.expected.empty,
|
||||
full : map.full,
|
||||
roots: map.expected,
|
||||
@@ -144,65 +142,6 @@ class GitRootDetectorTest {
|
||||
below: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the necessary temporary directories in the filesystem with empty ".git" directories for given roots.
|
||||
* And creates an instance of the project.
|
||||
* @param gitRoots path to actual .git roots, relative to the project dir.
|
||||
*/
|
||||
private void initProject(Collection<String> gitRoots, Collection<String> projectStructure) {
|
||||
String projectDir = createDirs(gitRoots)
|
||||
myProject = [
|
||||
getBaseDir: { new GitMockVirtualFile(projectDir) }
|
||||
] as Project
|
||||
createProjectStructure(projectStructure);
|
||||
}
|
||||
|
||||
void createProjectStructure(Collection<String> paths) {
|
||||
paths.each { String path ->
|
||||
File file = new File(myProject.baseDir.path + "/" + path)
|
||||
file.mkdir()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return path to the project
|
||||
*/
|
||||
private static String createDirs(Collection<String> gitRoots) {
|
||||
if (gitRoots.empty) {
|
||||
return FileUtil.createTempDirectory("grdt", null);
|
||||
}
|
||||
|
||||
File baseDir = createBaseTempDir()
|
||||
int maxDepth = findMaxDepthAboveProject(gitRoots)
|
||||
File projectDir = createChild(baseDir, maxDepth)
|
||||
gitRoots.each { String path ->
|
||||
File file = new File(projectDir.path + "/" + path)
|
||||
file.mkdirs()
|
||||
file.deleteOnExit()
|
||||
|
||||
File gitDir = new File(file, ".git")
|
||||
gitDir.mkdir()
|
||||
gitDir.deleteOnExit()
|
||||
}
|
||||
return projectDir.path
|
||||
}
|
||||
|
||||
private static File createBaseTempDir() {
|
||||
FileUtil.createTempDirectory("pref", null)
|
||||
}
|
||||
|
||||
private static File createChild(File base, int depth) {
|
||||
File dir = base
|
||||
depth.times { dir = FileUtil.createTempDirectory(dir, "grdt", null)}
|
||||
dir
|
||||
}
|
||||
|
||||
// Assuming that there are no ".." inside the path - only in the beginning
|
||||
static int findMaxDepthAboveProject(Collection<String> paths) {
|
||||
def len = { String path -> path.split("/").count("..") }
|
||||
len(paths.max(len))
|
||||
}
|
||||
|
||||
void testInfo(Map expected) {
|
||||
assertInfo(expected, detect())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.roots
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import git4idea.test.GitMockVcsManager
|
||||
import git4idea.test.GitTestPlatformFacade
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
import static git4idea.test.GitGTestUtil.toAbsolute
|
||||
import static junit.framework.Assert.assertEquals
|
||||
import git4idea.test.GitMockVirtualFile
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitRootErrorsFinderTest extends AbstractGitRootTest {
|
||||
|
||||
Project myProject
|
||||
GitTestPlatformFacade myPlatformFacade
|
||||
GitMockVcsManager myVcsManager
|
||||
|
||||
@Before
|
||||
void setUp() {
|
||||
myPlatformFacade = new GitTestPlatformFacade()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "No roots => no errors"() {
|
||||
doTest git: [],
|
||||
roots: [],
|
||||
errors: []
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Same 1 root in both => no errors"() {
|
||||
doTest git: ["."],
|
||||
roots: ["."],
|
||||
errors: []
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Same 2 roots in both => no errors"() {
|
||||
doTest git: ["..", "community"],
|
||||
roots: ["..", "community"],
|
||||
errors: []
|
||||
}
|
||||
|
||||
@Test
|
||||
void "One git, no VCS roots => error"() {
|
||||
doTest git: ["."],
|
||||
roots: [],
|
||||
errors: [unreg : ["."]]
|
||||
}
|
||||
|
||||
@Test
|
||||
void "One VCS root, no gits => error"() {
|
||||
doTest git: [],
|
||||
roots: ["."],
|
||||
errors: [extra: ["."]]
|
||||
}
|
||||
|
||||
@Test
|
||||
void "One root, but different => 2 errors"() {
|
||||
doTest git: ["."],
|
||||
roots: ["community"],
|
||||
errors: [unreg: ["."], extra: ["community"]]
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Two roots, one matching, one different => 2 errors"() {
|
||||
doTest git: [".", "community"],
|
||||
roots: [".", "contrib"],
|
||||
errors: [unreg: ["community"], extra: ["contrib"]]
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Two roots in git, one matching in VCS => error"() {
|
||||
doTest git: [".", "community"],
|
||||
roots: ["."],
|
||||
errors: [unreg: ["community"]]
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Two roots, both not matching => 4 errors"() {
|
||||
doTest git: ["..", "community"],
|
||||
roots: [".", "contrib"],
|
||||
errors: [unreg: ["..", "community"], extra: [".", "contrib"]]
|
||||
}
|
||||
|
||||
private void doTest(Map map) {
|
||||
myProject = initProject(map.git, [])
|
||||
myVcsManager = (GitMockVcsManager) myPlatformFacade.getVcsManager(myProject)
|
||||
|
||||
addVcsRoots(map.roots)
|
||||
|
||||
Collection<GitRootError> expected = new ArrayList<GitRootError>();
|
||||
expected.addAll map.errors.unreg.collect { unreg(it) }
|
||||
expected.addAll map.errors.extra.collect { extra(it) }
|
||||
|
||||
Collection<GitRootError> actual = new GitRootErrorsFinder(myProject, myPlatformFacade).find()
|
||||
assertEquals expected.toSet(), actual.toSet()
|
||||
}
|
||||
|
||||
void addVcsRoots(Collection<String> relativeRoots) {
|
||||
relativeRoots.each {
|
||||
String root = toAbsolute(it, myProject)
|
||||
myVcsManager.addRoots(root)
|
||||
}
|
||||
}
|
||||
|
||||
GitRootError unreg(String path) {
|
||||
return new GitRootError(GitRootError.Type.UNREGISTERED_ROOT, new GitMockVirtualFile(toAbsolute(path, myProject)))
|
||||
}
|
||||
|
||||
GitRootError extra(String path) {
|
||||
return new GitRootError(GitRootError.Type.EXTRA_ROOT, new GitMockVirtualFile(toAbsolute(path, myProject)))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -34,6 +34,10 @@ public class GitMockVcsManager extends ProjectLevelVcsManager {
|
||||
|
||||
Collection<String> myRoots = []
|
||||
|
||||
void addRoots(String... roots) {
|
||||
roots.each { myRoots << it }
|
||||
}
|
||||
|
||||
@Override
|
||||
VirtualFile[] getRootsUnderVcs(AbstractVcs vcs) {
|
||||
myRoots.collect { new GitMockVirtualFile(it) }
|
||||
|
||||
@@ -122,4 +122,15 @@ class GitMockVirtualFile extends VirtualFile {
|
||||
myPath;
|
||||
}
|
||||
|
||||
boolean equals(o) {
|
||||
if (this.is(o)) return true
|
||||
if (getClass() != o.class) return false
|
||||
GitMockVirtualFile file = (GitMockVirtualFile)o
|
||||
if (myPath != file.myPath) return false
|
||||
return true
|
||||
}
|
||||
|
||||
int hashCode() {
|
||||
return (myPath != null ? myPath.hashCode() : 0)
|
||||
}
|
||||
}
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package org.jetbrains.plugins.gradle.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskManager;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskType;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleDataKeys;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode;
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Common super class for actions that are invoked on 'sync project structures' tree nodes.
|
||||
* <p/>
|
||||
* Not thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/29/12 4:15 PM
|
||||
*/
|
||||
public abstract class AbstractGradleSyncTreeNodeAction extends AnAction {
|
||||
|
||||
private static final Map<String, Helper> HELPERS = new HashMap<String, Helper>();
|
||||
static {
|
||||
HELPERS.put(GradleConstants.SYNC_TREE_CONTEXT_MENU_PLACE, new ContextMenuHelper());
|
||||
HELPERS.put(GradleConstants.SYNC_TREE_FLOATING_TOOLBAR_PLACE, new FloatingToolbarHelper());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
|
||||
final Helper helper = HELPERS.get(e.getPlace());
|
||||
if (project == null || helper == null) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
e.getPresentation().setVisible(false);
|
||||
return;
|
||||
}
|
||||
Collection<GradleProjectStructureNode<?>> nodes = helper.getTargetNodes(e);
|
||||
if (nodes != null) {
|
||||
filterNodes(nodes);
|
||||
}
|
||||
helper.updatePresentation(nodes, e.getPresentation());
|
||||
if (e.getPresentation().isEnabled()) {
|
||||
final GradleTaskManager taskManager = ServiceManager.getService(GradleTaskManager.class);
|
||||
if (taskManager != null && taskManager.hasTaskOfTypeInProgress(GradleTaskType.RESOLVE_PROJECT)) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
|
||||
final Helper helper = HELPERS.get(e.getPlace());
|
||||
if (project == null || helper == null) {
|
||||
return;
|
||||
}
|
||||
final Collection<GradleProjectStructureNode<?>> nodes = helper.getTargetNodes(e);
|
||||
if (nodes == null || nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
doActionPerformed(nodes, project);
|
||||
}
|
||||
|
||||
protected abstract void doActionPerformed(@NotNull Collection<GradleProjectStructureNode<?>> nodes, @NotNull Project project);
|
||||
|
||||
protected void filterNodes(@NotNull Collection<GradleProjectStructureNode<?>> nodes) {
|
||||
}
|
||||
|
||||
private interface Helper {
|
||||
|
||||
@Nullable
|
||||
Collection<GradleProjectStructureNode<?>> getTargetNodes(@NotNull AnActionEvent e);
|
||||
|
||||
void updatePresentation(@Nullable Collection<GradleProjectStructureNode<?>> nodes, @NotNull Presentation presentation);
|
||||
}
|
||||
|
||||
private static class ContextMenuHelper implements Helper {
|
||||
@Nullable
|
||||
@Override
|
||||
public Collection<GradleProjectStructureNode<?>> getTargetNodes(@NotNull AnActionEvent e) {
|
||||
return GradleDataKeys.SYNC_TREE_SELECTED_NODE.getData(e.getDataContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePresentation(@Nullable Collection<GradleProjectStructureNode<?>> nodes, @NotNull Presentation presentation) {
|
||||
presentation.setVisible(true);
|
||||
presentation.setEnabled(nodes != null && !nodes.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
private static class FloatingToolbarHelper implements Helper {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
@Override
|
||||
public Collection<GradleProjectStructureNode<?>> getTargetNodes(@NotNull AnActionEvent e) {
|
||||
List<GradleProjectStructureNode<?>> result = new ArrayList<GradleProjectStructureNode<?>>();
|
||||
final GradleProjectStructureNode<?> node = GradleDataKeys.SYNC_TREE_NODE_UNDER_MOUSE.getData(e.getDataContext());
|
||||
if (node != null) {
|
||||
result.add(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePresentation(@Nullable Collection<GradleProjectStructureNode<?>> nodes, @NotNull Presentation presentation) {
|
||||
boolean active = nodes != null && !nodes.isEmpty();
|
||||
presentation.setVisible(active);
|
||||
presentation.setEnabled(active);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-34
@@ -1,21 +1,15 @@
|
||||
package org.jetbrains.plugins.gradle.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.config.GradleTextAttributes;
|
||||
import org.jetbrains.plugins.gradle.importing.GradleLocalNodeImportHelper;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleDataKeys;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -26,46 +20,32 @@ import java.util.List;
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/7/12 10:32 AM
|
||||
*/
|
||||
public class GradleImportEntityAction extends AnAction {
|
||||
public class GradleImportEntityAction extends AbstractGradleSyncTreeNodeAction {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#" + GradleImportEntityAction.class.getName());
|
||||
|
||||
public GradleImportEntityAction() {
|
||||
getTemplatePresentation().setText(GradleBundle.message("gradle.action.import.entity.text"));
|
||||
getTemplatePresentation().setDescription(GradleBundle.message("gradle.action.import.entity.description"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
final Collection<GradleProjectStructureNode<?>> nodes = getInterestedNodes(e.getDataContext());
|
||||
e.getPresentation().setEnabled(!nodes.isEmpty());
|
||||
protected void filterNodes(@NotNull Collection<GradleProjectStructureNode<?>> nodes) {
|
||||
for (Iterator<GradleProjectStructureNode<?>> iterator = nodes.iterator(); iterator.hasNext(); ) {
|
||||
GradleProjectStructureNode<?> node = iterator.next();
|
||||
if (node.getDescriptor().getAttributes() != GradleTextAttributes.GRADLE_LOCAL_CHANGE) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
|
||||
if (project == null) {
|
||||
LOG.warn("Can't import gradle-local entities. Reason: target intellij project is undefined");
|
||||
return;
|
||||
}
|
||||
|
||||
final Collection<GradleProjectStructureNode<?>> nodes = getInterestedNodes(e.getDataContext());
|
||||
protected void doActionPerformed(@NotNull Collection<GradleProjectStructureNode<?>> nodes, @NotNull Project project) {
|
||||
final GradleLocalNodeImportHelper importHelper = project.getComponent(GradleLocalNodeImportHelper.class);
|
||||
importHelper.importNodes(nodes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<GradleProjectStructureNode<?>> getInterestedNodes(@NotNull DataContext context) {
|
||||
final Collection<GradleProjectStructureNode<?>> selectedNodes = GradleDataKeys.SYNC_TREE_NODE.getData(context);
|
||||
if (selectedNodes == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<GradleProjectStructureNode<?>> result = new ArrayList<GradleProjectStructureNode<?>>();
|
||||
for (GradleProjectStructureNode<?> node : selectedNodes) {
|
||||
final List<GradleProjectStructureNode<?>> interestedNodes = new ArrayList<GradleProjectStructureNode<?>>();
|
||||
for (GradleProjectStructureNode<?> node : nodes) {
|
||||
if (node.getDescriptor().getAttributes() == GradleTextAttributes.GRADLE_LOCAL_CHANGE) {
|
||||
result.add(node);
|
||||
interestedNodes.add(node);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
importHelper.importNodes(interestedNodes);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,6 +39,6 @@ public class GradleRefreshProjectAction extends AbstractGradleLinkedProjectActio
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(@NotNull final Project project, @NotNull final String linkedProjectPath) {
|
||||
GradleUtil.refreshProject(project);
|
||||
GradleUtil.refreshProject(project);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
*/
|
||||
public class GradleProjectStructureChangesDetector extends AbstractProjectComponent {
|
||||
|
||||
private static final int REFRESH_DELAY_MILLIS = (int)TimeUnit.SECONDS.toMillis(2);
|
||||
private static final int REFRESH_DELAY_MILLIS = (int)500;
|
||||
|
||||
private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
|
||||
private final AtomicLong myStartRefreshTime = new AtomicLong();
|
||||
@@ -78,7 +78,7 @@ public class GradleProjectStructureChangesDetector extends AbstractProjectCompon
|
||||
}
|
||||
myStartRefreshTime.set(System.currentTimeMillis() + REFRESH_DELAY_MILLIS);
|
||||
myAlarm.cancelAllRequests();
|
||||
myAlarm.addRequest(myRequest, REFRESH_DELAY_MILLIS + 16);
|
||||
myAlarm.addRequest(myRequest, REFRESH_DELAY_MILLIS);
|
||||
}
|
||||
|
||||
private class RefreshRequest implements Runnable {
|
||||
|
||||
+130
-3
@@ -1,8 +1,16 @@
|
||||
package org.jetbrains.plugins.gradle.sync;
|
||||
|
||||
import com.intellij.ide.ui.customization.CustomizationUtil;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
|
||||
import com.intellij.openapi.actionSystem.ex.AnActionListener;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.ColoredSideBorder;
|
||||
import com.intellij.ui.HintHint;
|
||||
import com.intellij.ui.HintListener;
|
||||
import com.intellij.ui.LightweightHint;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -19,8 +27,10 @@ import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -30,10 +40,14 @@ import java.util.List;
|
||||
* @since 11/3/11 3:58 PM
|
||||
*/
|
||||
public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
|
||||
|
||||
private final Alarm myToolbarAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
|
||||
|
||||
private Tree myTree;
|
||||
private GradleProjectStructureTreeModel myTreeModel;
|
||||
private GradleProjectStructureContext myContext;
|
||||
private Object myNodeUnderMouse;
|
||||
private LightweightHint myHint;
|
||||
|
||||
public GradleProjectStructureChangesPanel(@NotNull Project project, @NotNull GradleProjectStructureContext context) {
|
||||
super(project, GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE);
|
||||
@@ -75,7 +89,8 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
result.add(myTree, constraints);
|
||||
result.setBackground(myTree.getBackground());
|
||||
|
||||
CustomizationUtil.installPopupHandler(myTree, GradleConstants.ACTION_GROUP_SYNC_TREE, GradleConstants.SYNC_TREE_PLACE);
|
||||
CustomizationUtil.installPopupHandler(myTree, GradleConstants.ACTION_GROUP_SYNC_TREE, GradleConstants.SYNC_TREE_CONTEXT_MENU_PLACE);
|
||||
setupActionHint();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -85,10 +100,119 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
int i = 1;
|
||||
}
|
||||
|
||||
private void setupActionHint() {
|
||||
final ActionManagerEx actionManager = ActionManagerEx.getInstanceEx();
|
||||
actionManager.addAnActionListener(new AnActionListener.Adapter() {
|
||||
@Override
|
||||
public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
|
||||
if (event != null && GradleConstants.SYNC_TREE_FLOATING_TOOLBAR_PLACE.equals(event.getPlace())) {
|
||||
hideHind();
|
||||
}
|
||||
}
|
||||
}, getProject());
|
||||
|
||||
final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(GradleConstants.ACTION_GROUP_SYNC_TREE);
|
||||
final ActionToolbar toolbar = actionManager.createActionToolbar(GradleConstants.SYNC_TREE_FLOATING_TOOLBAR_PLACE, actionGroup, true);
|
||||
toolbar.setTargetComponent(this);
|
||||
final JComponent toolbarComponent = toolbar.getComponent();
|
||||
toolbarComponent.setOpaque(true);
|
||||
final Color foreground = myTree.getForeground();
|
||||
toolbarComponent.setForeground(foreground);
|
||||
toolbarComponent.setBackground(myTree.getBackground());
|
||||
toolbarComponent.setBorder(new ColoredSideBorder(foreground, foreground, foreground, foreground, 1));
|
||||
|
||||
myTree.addMouseMotionListener(new MouseMotionAdapter() {
|
||||
|
||||
Object activeNode;
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
final TreePath path = myTree.getPathForLocation(e.getX(), e.getY());
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
final Object node = path.getLastPathComponent();
|
||||
myNodeUnderMouse = node;
|
||||
LightweightHint hint = myHint;
|
||||
if (node == activeNode && hint.isVisible()) {
|
||||
return;
|
||||
}
|
||||
hideHind();
|
||||
if (!actionManager.isActionPopupStackEmpty()) {
|
||||
return;
|
||||
}
|
||||
toolbar.updateActionsImmediately();
|
||||
if (!toolbar.hasVisibleActions()) {
|
||||
activeNode = null;
|
||||
return;
|
||||
}
|
||||
activeNode = node;
|
||||
final LightweightHint lightweightHint = new LightweightHint(toolbarComponent);
|
||||
lightweightHint.addHintListener(new HintListener() {
|
||||
@Override
|
||||
public void hintHidden(EventObject event) {
|
||||
activeNode = null;
|
||||
}
|
||||
});
|
||||
final Rectangle bounds = myTree.getPathBounds(path);
|
||||
if (bounds == null) {
|
||||
assert false;
|
||||
return;
|
||||
}
|
||||
final Icon icon = ((GradleProjectStructureNode)node).getDescriptor().getOpenIcon();
|
||||
int xAdjustment = 0;
|
||||
if (icon != null) {
|
||||
xAdjustment = icon.getIconWidth();
|
||||
}
|
||||
lightweightHint.show(myTree, bounds.x + xAdjustment, bounds.y + bounds.height, myTree, new HintHint(e));
|
||||
myHint = lightweightHint;
|
||||
startToolbarTracking();
|
||||
}
|
||||
});
|
||||
myTree.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
// Hide hint on context menu opening.
|
||||
if (e.isPopupTrigger()) {
|
||||
hideHind();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startToolbarTracking() {
|
||||
myToolbarAlarm.cancelAllRequests();
|
||||
final int delayMillis = 300;
|
||||
myToolbarAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myHint == null) {
|
||||
return;
|
||||
}
|
||||
final Point location = MouseInfo.getPointerInfo().getLocation();
|
||||
SwingUtilities.convertPointFromScreen(location, GradleProjectStructureChangesPanel.this);
|
||||
if (GradleProjectStructureChangesPanel.this.contains(location)) {
|
||||
myToolbarAlarm.addRequest(this, delayMillis);
|
||||
}
|
||||
else {
|
||||
hideHind();
|
||||
}
|
||||
}
|
||||
}, delayMillis);
|
||||
}
|
||||
|
||||
private void hideHind() {
|
||||
final LightweightHint hint = myHint;
|
||||
if (hint != null && hint.isVisible()) {
|
||||
hint.hide();
|
||||
myToolbarAlarm.cancelAllRequests();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(@NonNls String dataId) {
|
||||
if (GradleDataKeys.SYNC_TREE_NODE.is(dataId)) {
|
||||
if (GradleDataKeys.SYNC_TREE_SELECTED_NODE.is(dataId)) {
|
||||
TreePath[] paths = myTree.getSelectionPaths();
|
||||
if (paths == null) {
|
||||
return null;
|
||||
@@ -99,6 +223,9 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if (GradleDataKeys.SYNC_TREE_NODE_UNDER_MOUSE.is(dataId)) {
|
||||
return myNodeUnderMouse;
|
||||
}
|
||||
else {
|
||||
return super.getData(dataId);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,12 @@ import java.util.Collection;
|
||||
public class GradleDataKeys {
|
||||
|
||||
/** Key for obtaining currently selected nodes at the gradle 'sync project structure' tree. */
|
||||
public static final DataKey<Collection<GradleProjectStructureNode<?>>> SYNC_TREE_NODE = DataKey.create("gradle.sync.tree.node");
|
||||
public static final DataKey<Collection<GradleProjectStructureNode<?>>> SYNC_TREE_SELECTED_NODE
|
||||
= DataKey.create("gradle.sync.tree.node.selected");
|
||||
|
||||
/** Key for obtaining node under mouse cursor at the gradle 'sync project structure' tree. */
|
||||
public static final DataKey<GradleProjectStructureNode<?>> SYNC_TREE_NODE_UNDER_MOUSE
|
||||
= DataKey.create("gradle.sync.tree.node.under.mouse");
|
||||
|
||||
private GradleDataKeys() {
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@ public class GradleConstants {
|
||||
@NonNls public static final String EXTENSION = "gradle";
|
||||
@NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle";
|
||||
|
||||
@NonNls public static final String TOOL_WINDOW_TOOLBAR_PLACE = "GRADLE_SYNC_CHANGES_TOOLBAR";
|
||||
@NonNls public static final String SYNC_TREE_PLACE = "GRADLE_SYNC_TREE_PLACE";
|
||||
@NonNls public static final String TOOL_WINDOW_TOOLBAR_PLACE = "GRADLE_SYNC_CHANGES_TOOLBAR";
|
||||
@NonNls public static final String SYNC_TREE_CONTEXT_MENU_PLACE = "GRADLE_SYNC_TREE_CONTEXT_MENU_PLACE";
|
||||
@NonNls public static final String SYNC_TREE_FLOATING_TOOLBAR_PLACE = "GRADLE_SYNC_TREE_FLOATING_TOOLBAR_PLACE";
|
||||
|
||||
@NonNls public static final String ACTION_GROUP_SYNC_TREE = "Gradle.SyncTreeGroup";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user