mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
Generated
-1
@@ -56,7 +56,6 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/core-api/core-api.iml" filepath="$PROJECT_DIR$/platform/core-api/core-api.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/core-impl/core-impl.iml" filepath="$PROJECT_DIR$/platform/core-impl/core-impl.iml" group="platform" />
|
||||
<module fileurl="file://$PROJECT_DIR$/python/educational-core/course-creator/course-creator.iml" filepath="$PROJECT_DIR$/python/educational-core/course-creator/course-creator.iml" group="python/educational/educational-core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/python/educational-python/course-creator-python/course-creator-python.iml" filepath="$PROJECT_DIR$/python/educational-python/course-creator-python/course-creator-python.iml" group="python/educational/educational-python" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/coverage/coverage.iml" filepath="$PROJECT_DIR$/plugins/coverage/coverage.iml" group="plugins/coverage" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/coverage-common/coverage-common.iml" filepath="$PROJECT_DIR$/plugins/coverage-common/coverage-common.iml" group="plugins/coverage" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/coverage/coverage_rt/coverage_rt.iml" filepath="$PROJECT_DIR$/plugins/coverage/coverage_rt/coverage_rt.iml" group="plugins/coverage" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -29,6 +29,12 @@ target(compile: "Compile project") {
|
||||
loadProject()
|
||||
prepareOutputFolder()
|
||||
|
||||
if (System.getProperty("tests.only")) {
|
||||
ant.delete(dir: "$home/out")
|
||||
ant.unzip(src: "$home/out.zip", dest: "$home/out")
|
||||
return
|
||||
}
|
||||
|
||||
if (!isDefined("avoid.project.rebuild")) {
|
||||
clearBuildCaches()
|
||||
projectBuilder.cleanOutput()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.debugger.engine.events;
|
||||
|
||||
import com.intellij.debugger.impl.DebuggerTaskImpl;
|
||||
import org.jetbrains.annotations.Debugger;
|
||||
|
||||
/**
|
||||
* @author lex
|
||||
@@ -40,6 +41,7 @@ public abstract class DebuggerCommandImpl extends DebuggerTaskImpl {
|
||||
}
|
||||
}
|
||||
|
||||
@Debugger.Insert
|
||||
public final void run() throws Exception{
|
||||
try {
|
||||
action();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.sun.jdi.VMDisconnectedException;
|
||||
import org.jetbrains.annotations.Debugger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
@@ -191,7 +192,7 @@ public abstract class InvokeThread<E extends PrioritizedTask> {
|
||||
return request != null? request.getOwner() : null;
|
||||
}
|
||||
|
||||
public boolean schedule(E r) {
|
||||
public boolean schedule(@Debugger.Capture E r) {
|
||||
if(LOG.isDebugEnabled()) {
|
||||
LOG.debug("schedule " + r + " in " + this);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
package com.intellij.debugger.settings;
|
||||
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.engine.JVMNameUtil;
|
||||
import com.intellij.debugger.jdi.DecompiledLocalVariable;
|
||||
import com.intellij.debugger.ui.JavaDebuggerSupport;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -27,10 +30,16 @@ import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWrapper;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
@@ -42,6 +51,7 @@ import one.util.streamex.IntStreamEx;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.Debugger;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -214,7 +224,92 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
|
||||
static final String[] COLUMN_NAMES =
|
||||
new String[]{"", "Capture class name", "Capture method name", "Capture key expression", "Insert class name", "Insert method name", "Insert key expression"};
|
||||
List<CapturePoint> myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
|
||||
List<CapturePoint> myCapturePoints;
|
||||
|
||||
private MyTableModel() {
|
||||
myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
|
||||
scanPoints();
|
||||
}
|
||||
|
||||
private void scanPoints() {
|
||||
if (Registry.is("debugger.capture.points.annotations")) {
|
||||
scanPointsInt(true);
|
||||
scanPointsInt(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void scanPointsInt(boolean capture) {
|
||||
try {
|
||||
String annotationName = (capture ? Debugger.Capture.class : Debugger.Insert.class).getName().replace("$", ".");
|
||||
Project project = JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables();
|
||||
GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
|
||||
PsiClass annotationClass = JavaPsiFacade.getInstance(project).findClass(annotationName, allScope);
|
||||
if (annotationClass != null) {
|
||||
AnnotatedElementsSearch.searchElements(annotationClass, allScope, PsiMethod.class, PsiParameter.class).forEach(e -> {
|
||||
if (e instanceof PsiMethod) {
|
||||
addCapturePointIfNeeded(e, (PsiMethod)e, annotationName, "this", capture);
|
||||
}
|
||||
else if (e instanceof PsiParameter) {
|
||||
PsiParameter psiParameter = (PsiParameter)e;
|
||||
PsiMethod psiMethod = (PsiMethod)psiParameter.getDeclarationScope();
|
||||
addCapturePointIfNeeded(psiParameter, psiMethod, annotationName,
|
||||
DecompiledLocalVariable.PARAM_PREFIX + psiMethod.getParameterList().getParameterIndex(psiParameter),
|
||||
capture);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addCapturePointIfNeeded(PsiModifierListOwner psiElement,
|
||||
PsiMethod psiMethod,
|
||||
String annotationName,
|
||||
String defaultExpression,
|
||||
boolean capture) {
|
||||
CapturePoint capturePoint = new CapturePoint();
|
||||
capturePoint.myEnabled = false;
|
||||
if (capture) {
|
||||
capturePoint.myClassName = JVMNameUtil.getNonAnonymousClassName(psiMethod.getContainingClass());
|
||||
capturePoint.myMethodName = JVMNameUtil.getJVMMethodName(psiMethod);
|
||||
}
|
||||
else {
|
||||
capturePoint.myInsertClassName = JVMNameUtil.getNonAnonymousClassName(psiMethod.getContainingClass());
|
||||
capturePoint.myInsertMethodName = JVMNameUtil.getJVMMethodName(psiMethod);
|
||||
}
|
||||
|
||||
PsiModifierList modifierList = psiElement.getModifierList();
|
||||
if (modifierList != null) {
|
||||
PsiAnnotation annotation = modifierList.findAnnotation(annotationName);
|
||||
if (annotation != null) {
|
||||
PsiAnnotationMemberValue attributeValue = annotation.findAttributeValue("keyExpression");
|
||||
String keyExpression = attributeValue != null ? StringUtil.unquoteString(attributeValue.getText()) : null;
|
||||
if (StringUtil.isEmpty(keyExpression)) {
|
||||
keyExpression = defaultExpression;
|
||||
}
|
||||
if (capture) {
|
||||
capturePoint.myCaptureKeyExpression = keyExpression;
|
||||
}
|
||||
else {
|
||||
capturePoint.myInsertKeyExpression = keyExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CapturePoint clone = capturePoint;
|
||||
try {
|
||||
clone = capturePoint.clone();
|
||||
clone.myEnabled = !clone.myEnabled;
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
if (!myCapturePoints.contains(capturePoint) && !myCapturePoints.contains(clone)) {
|
||||
myCapturePoints.add(capturePoint);
|
||||
}
|
||||
}
|
||||
|
||||
public String getColumnName(int column) {
|
||||
return COLUMN_NAMES[column];
|
||||
@@ -325,6 +420,7 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
public void reset() {
|
||||
myCaptureVariables.setSelected(DebuggerSettings.getInstance().CAPTURE_VARIABLES);
|
||||
myTableModel.myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
|
||||
myTableModel.scanPoints();
|
||||
myTableModel.fireTableDataChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -17,6 +17,10 @@ package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.AutoPopupController;
|
||||
import com.intellij.codeInsight.completion.util.MethodParenthesesHandler;
|
||||
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
|
||||
import com.intellij.codeInsight.hint.ParameterInfoController;
|
||||
import com.intellij.codeInsight.hint.ShowParameterInfoContext;
|
||||
import com.intellij.codeInsight.hint.api.impls.MethodParameterInfoHandler;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.codeInsight.lookup.impl.JavaElementLookupRenderer;
|
||||
import com.intellij.codeInsight.template.*;
|
||||
@@ -26,10 +30,13 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateState;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.Inlay;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ClassConditionKey;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
@@ -44,6 +51,8 @@ import com.intellij.psi.util.TypeConversionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
@@ -175,6 +184,7 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
|
||||
}
|
||||
|
||||
startArgumentLiveTemplate(context, method);
|
||||
showParameterHints(context, method, methodCall);
|
||||
}
|
||||
|
||||
static PsiCallExpression findCallAtOffset(InsertionContext context, int offset) {
|
||||
@@ -270,6 +280,45 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void showParameterHints(InsertionContext context, PsiMethod method, PsiCallExpression methodCall) {
|
||||
PsiParameterList parameterList = method.getParameterList();
|
||||
int parametersCount = parameterList.getParametersCount();
|
||||
if (methodCall == null ||
|
||||
parametersCount == 0 ||
|
||||
context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR ||
|
||||
Registry.is("java.completion.argument.live.template") ||
|
||||
!Registry.is("java.completion.argument.hints")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Editor editor = context.getEditor();
|
||||
CaretModel caretModel = editor.getCaretModel();
|
||||
int offset = caretModel.getOffset();
|
||||
caretModel.moveToOffset(offset - 1); // avoid caret impact on hints location
|
||||
editor.getDocument().insertString(offset, StringUtil.repeat(", ", parametersCount - 1));
|
||||
List<Inlay> addedHints = new ArrayList<>(parametersCount);
|
||||
for (PsiParameter parameter : parameterList.getParameters()) {
|
||||
String name = parameter.getName();
|
||||
if (name != null) {
|
||||
addedHints.add(ParameterHintsPresentationManager.getInstance().addHint(editor, offset, name + ":", false, true));
|
||||
}
|
||||
offset += 2;
|
||||
}
|
||||
int braceOffset = caretModel.getOffset();
|
||||
caretModel.moveToLogicalPosition(editor.offsetToLogicalPosition(braceOffset + 1).leanForward(true));
|
||||
|
||||
Project project = context.getProject();
|
||||
MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
|
||||
ShowParameterInfoContext infoContext = new ShowParameterInfoContext(editor, project, context.getFile(), braceOffset, braceOffset);
|
||||
handler.findElementForParameterInfo(infoContext);
|
||||
|
||||
Disposer.register(new ParameterInfoController(project, editor, braceOffset, infoContext.getItemsToShow(), null, methodCall.getArgumentList(), handler, false, false), () -> {
|
||||
for (Inlay inlay : addedHints) {
|
||||
if (inlay != null) ParameterHintsPresentationManager.getInstance().unpin(inlay);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void setupNonFilledArgumentRemoving(final Editor editor, final TemplateState templateState) {
|
||||
AtomicInteger maxEditedVariable = new AtomicInteger(-1);
|
||||
editor.getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionPromoter;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JavaMethodOverloadSwitchActionPromoter implements ActionPromoter {
|
||||
@Override
|
||||
public List<AnAction> promote(List<AnAction> actions, DataContext context) {
|
||||
return ContainerUtil.findAll(actions, a -> a instanceof JavaMethodOverloadSwitchUpAction ||
|
||||
a instanceof JavaMethodOverloadSwitchDownAction);
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.openapi.editor.actionSystem.EditorAction;
|
||||
|
||||
public class JavaMethodOverloadSwitchDownAction extends EditorAction {
|
||||
public JavaMethodOverloadSwitchDownAction() {
|
||||
super(new JavaMethodOverloadSwitchHandler(false));
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionMemory;
|
||||
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
|
||||
import com.intellij.codeInsight.hint.ParameterInfoController;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Caret;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.Inlay;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class JavaMethodOverloadSwitchHandler extends EditorWriteActionHandler {
|
||||
private static final Key<Map<String, String>> ENTERED_PARAMETERS = Key.create("entered.parameters");
|
||||
private final boolean mySwitchUp;
|
||||
|
||||
public JavaMethodOverloadSwitchHandler(boolean up) {
|
||||
mySwitchUp = up;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledForCaret(@NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) {
|
||||
if (!Registry.is("java.completion.argument.hints") || !ParameterInfoController.existsForEditor(editor)) return false;
|
||||
|
||||
Project project = CommonDataKeys.PROJECT.getData(dataContext);
|
||||
if (project == null) return false;
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
|
||||
PsiElement exprList = getExpressionList(editor, caret.getOffset(), project);
|
||||
if (exprList == null) return false;
|
||||
|
||||
int lbraceOffset = exprList.getTextRange().getStartOffset();
|
||||
return ParameterInfoController.findControllerAtOffset(editor, lbraceOffset) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement getExpressionList(@NotNull Editor editor, int offset, @NotNull Project project) {
|
||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||
return file != null ? ParameterInfoController.findArgumentList(file, offset, -1) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeWriteAction(Editor editor, @Nullable Caret caret, DataContext dataContext) {
|
||||
if (caret == null) caret = editor.getCaretModel().getPrimaryCaret();
|
||||
Project project = CommonDataKeys.PROJECT.getData(dataContext);
|
||||
if (project == null) return;
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
PsiElement exprList = getExpressionList(editor, caret.getOffset(), project);
|
||||
if (!(exprList instanceof PsiExpressionList)) return;
|
||||
|
||||
int lbraceOffset = exprList.getTextRange().getStartOffset();
|
||||
ParameterInfoController controller = ParameterInfoController.findControllerAtOffset(editor, lbraceOffset);
|
||||
if (controller == null) return;
|
||||
Object[] objects = controller.getObjects();
|
||||
Object highlighted = controller.getHighlighted();
|
||||
if (objects == null || objects.length <= 1 || highlighted == null) return;
|
||||
|
||||
int currentIndex = ContainerUtil.indexOf(Arrays.asList(objects), highlighted);
|
||||
if (currentIndex < 0) return;
|
||||
|
||||
PsiMethod currentMethod = (PsiMethod)((CandidateInfo)objects[currentIndex]).getElement();
|
||||
|
||||
Map<String, String> enteredParameters = exprList.getUserData(ENTERED_PARAMETERS);
|
||||
if (enteredParameters == null) {
|
||||
exprList.putUserData(ENTERED_PARAMETERS, enteredParameters = new HashMap<>());
|
||||
}
|
||||
PsiExpression[] enteredExpressions = ((PsiExpressionList)exprList).getExpressions();
|
||||
assert enteredExpressions.length == 0 || enteredExpressions.length == currentMethod.getParameterList().getParametersCount();
|
||||
for (int i = 0; i < enteredExpressions.length; i++) {
|
||||
PsiExpression expression = enteredExpressions[i];
|
||||
String value = expression.getText().trim();
|
||||
if (!value.isEmpty()) {
|
||||
String key = getParameterKey(currentMethod, i);
|
||||
enteredParameters.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
PsiMethod targetMethod = (PsiMethod)((CandidateInfo)objects[(currentIndex + (mySwitchUp ? -1 : 1) + objects.length) % objects.length]).getElement();
|
||||
PsiParameterList parameterList = targetMethod.getParameterList();
|
||||
int parametersCount = parameterList.getParametersCount();
|
||||
caret.moveToOffset(lbraceOffset); // avoid caret impact on hints location
|
||||
int offset = lbraceOffset + 1;
|
||||
int endOffset = exprList.getTextRange().getEndOffset() - 1;
|
||||
List<Inlay> oldInlays = editor.getInlayModel().getInlineElementsInRange(offset, endOffset);
|
||||
for (Inlay inlay : oldInlays) {
|
||||
Disposer.dispose(inlay);
|
||||
}
|
||||
editor.getDocument().deleteString(offset, endOffset);
|
||||
int targetCaretPosition = -1;
|
||||
List<Inlay> addedHints = new ArrayList<>(parametersCount);
|
||||
for (int i = 0; i < parametersCount; i++) {
|
||||
String key = getParameterKey(targetMethod, i);
|
||||
String value = enteredParameters.getOrDefault(key, "");
|
||||
if (value.isEmpty() && targetCaretPosition == -1) targetCaretPosition = offset;
|
||||
if (i < parametersCount - 1) value += ", ";
|
||||
editor.getDocument().insertString(offset, value);
|
||||
String name = parameterList.getParameters()[i].getName();
|
||||
if (name != null) {
|
||||
addedHints.add(ParameterHintsPresentationManager.getInstance().addHint(editor, offset, name + ":", false, true));
|
||||
}
|
||||
offset += value.length();
|
||||
}
|
||||
if (targetCaretPosition == -1) targetCaretPosition = offset;
|
||||
caret.moveToLogicalPosition(editor.offsetToLogicalPosition(targetCaretPosition).leanForward(true));
|
||||
Disposer.register(controller, () -> {
|
||||
for (Inlay hint : addedHints) {
|
||||
if (hint != null) ParameterHintsPresentationManager.getInstance().unpin(hint);
|
||||
}
|
||||
});
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
CompletionMemory.registerChosenMethod(targetMethod, (PsiCall)exprList.getParent());
|
||||
controller.updateComponent(); // update popup immediately (otherwise, it will be updated only after delay)
|
||||
}
|
||||
|
||||
private static String getParameterKey(PsiMethod method, int parameterIndex) {
|
||||
PsiParameter parameter = method.getParameterList().getParameters()[parameterIndex];
|
||||
return parameter.getName() + ":" + parameter.getType().getCanonicalText();
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.openapi.editor.actionSystem.EditorAction;
|
||||
|
||||
public class JavaMethodOverloadSwitchUpAction extends EditorAction {
|
||||
public JavaMethodOverloadSwitchUpAction() {
|
||||
super(new JavaMethodOverloadSwitchHandler(true));
|
||||
}
|
||||
}
|
||||
@@ -107,13 +107,6 @@ public class PsiMethodReferenceUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass();
|
||||
if (qContainingClass != null && containingClass != null &&
|
||||
isReceiverType(getFirstParameterType(functionalInterfaceType, expression), qContainingClass, subst)) {
|
||||
subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst);
|
||||
LOG.assertTrue(subst != null);
|
||||
}
|
||||
|
||||
methodReturnType = subst.substitute(methodReturnType);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class JavaReadWriteAccessDetector extends ReadWriteAccessDetector {
|
||||
@Override
|
||||
public boolean isReadWriteAccessible(@NotNull final PsiElement element) {
|
||||
return element instanceof PsiVariable && !(element instanceof ImplicitVariable) || element instanceof PsiClass;
|
||||
return element instanceof PsiVariable && !(element instanceof ImplicitVariable) || element instanceof PsiClass || element instanceof PsiAnnotationMethod && !(element instanceof PsiCompiledElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,7 +49,12 @@ public class JavaReadWriteAccessDetector extends ReadWriteAccessDetector {
|
||||
@NotNull
|
||||
@Override
|
||||
public Access getExpressionAccess(@NotNull final PsiElement expression) {
|
||||
if (!(expression instanceof PsiExpression)) return Access.Read;
|
||||
if (!(expression instanceof PsiExpression)) {
|
||||
if (expression instanceof PsiNameValuePair || expression instanceof PsiIdentifier) {
|
||||
return Access.Write;
|
||||
}
|
||||
return Access.Read;
|
||||
}
|
||||
PsiExpression expr = (PsiExpression) expression;
|
||||
boolean readAccess = PsiUtil.isAccessedForReading(expr);
|
||||
boolean writeAccess = PsiUtil.isAccessedForWriting(expr);
|
||||
|
||||
+2
-1
@@ -1607,7 +1607,8 @@ public class InferenceSession {
|
||||
if (receiverSubstitutor != null) {
|
||||
if (!method.hasTypeParameters()) {
|
||||
if (signature.getParameterTypes().length == 1 || PsiUtil.isRawSubstitutor(containingClass, receiverSubstitutor)) {
|
||||
return receiverSubstitutor;
|
||||
return methodContainingClass != null ? JavaClassSupers.getInstance().getSuperClassSubstitutor(methodContainingClass, containingClass, reference.getResolveScope(), receiverSubstitutor)
|
||||
: receiverSubstitutor;
|
||||
}
|
||||
}
|
||||
mySiteSubstitutor = mySiteSubstitutor.putAll(receiverSubstitutor);
|
||||
|
||||
+7
@@ -185,6 +185,13 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (myT instanceof PsiCapturedWildcardType) {
|
||||
PsiType lowerBound = ((PsiCapturedWildcardType)myT).getLowerBound();
|
||||
if (lowerBound != PsiType.NULL) {
|
||||
constraints.add(new StrictSubtypingConstraint(lowerBound, myS));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
interface Processor<P> {
|
||||
void process(P t);
|
||||
}
|
||||
|
||||
class Test {
|
||||
void foo(Processor<? super List<String>> p) {
|
||||
p.process(Collections.emptyList());
|
||||
}
|
||||
|
||||
void bar(Processor<? extends List<String>> p) {
|
||||
p.process<error descr="'process(capture<? extends java.util.List<java.lang.String>>)' in 'Processor' cannot be applied to '(java.util.List<java.lang.Object>)'">(Collections.emptyList())</error>;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
class Test {
|
||||
interface MyBaseStream<T, S extends MyBaseStream<T, S>> {
|
||||
<R> MyStream<R> map(Function<? super T, ? extends R> mapper);
|
||||
}
|
||||
|
||||
interface MyStream<T> extends MyBaseStream<T, MyStream<T>> {}
|
||||
|
||||
{
|
||||
BiFunction<MyStream<Integer>, Function<Integer, Integer>, MyStream<Integer>> streamMapper = MyStream::map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
|
||||
import com.intellij.codeInsight.hint.ParameterInfoController;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.registry.RegistryValue;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CompletionHintsTest extends LightFixtureCompletionTestCase {
|
||||
private RegistryValue myRegistryValue = Registry.get("java.completion.argument.hints");
|
||||
private boolean myStoredRegistryValue;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myStoredRegistryValue = myRegistryValue.asBoolean();
|
||||
myRegistryValue.setValue(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
try {
|
||||
myRegistryValue.setValue(myStoredRegistryValue);
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testBasicScenario() throws Exception {
|
||||
// check hints appearance on completion
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, "class C { void m() { System.setPro<caret> } }");
|
||||
complete("setProperty");
|
||||
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
|
||||
|
||||
// check that hints don't disappear after daemon highlighting passes
|
||||
myFixture.doHighlighting();
|
||||
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
|
||||
|
||||
// test Tab/Shift+Tab navigation
|
||||
myFixture.checkResult("class C { void m() { System.setProperty(<caret>, ) } }");
|
||||
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
|
||||
myFixture.performEditorAction("NextParameter");
|
||||
myFixture.checkResult("class C { void m() { System.setProperty(, <caret>) } }");
|
||||
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
|
||||
myFixture.performEditorAction("PrevParameter");
|
||||
myFixture.checkResult("class C { void m() { System.setProperty(<caret>, ) } }");
|
||||
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
|
||||
|
||||
// test hints remain shown while entering parameter values
|
||||
myFixture.type("\"a");
|
||||
myFixture.performEditorAction("NextParameter");
|
||||
myFixture.type("\"b");
|
||||
myFixture.doHighlighting();
|
||||
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>\"a\", <hint text=\"value:\"/>\"b\") } }");
|
||||
|
||||
// test hints disappearance when caret moves out of parameter list
|
||||
myFixture.performEditorAction("EditorRight");
|
||||
myFixture.performEditorAction("EditorRight");
|
||||
ParameterInfoController.waitForDelayedActions(getEditor(), 10, TimeUnit.SECONDS);
|
||||
|
||||
myFixture.doHighlighting();
|
||||
waitTillAnimationCompletes();
|
||||
myFixture.checkResultWithInlays("class C { void m() { System.setProperty(\"a\", \"b\") } }");
|
||||
}
|
||||
|
||||
public void testSwitchingOverloads() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, "class C { void m() { Character.to<caret> } }");
|
||||
complete("toChars(int codePoint)");
|
||||
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>) } }");
|
||||
showParameterInfo();
|
||||
myFixture.performEditorAction("MethodOverloadSwitchDown");
|
||||
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
|
||||
}
|
||||
|
||||
public void testSwitchingOverloadsWithParameterFilled() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, "class C { void m() { Character.to<caret> } }");
|
||||
complete("toChars(int codePoint)");
|
||||
type("123");
|
||||
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123) } }");
|
||||
showParameterInfo();
|
||||
myFixture.performEditorAction("MethodOverloadSwitchDown");
|
||||
myFixture.checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
|
||||
myFixture.checkResult("class C { void m() { Character.toChars(123, <caret>, ) } }");
|
||||
}
|
||||
|
||||
private void showParameterInfo() {
|
||||
myFixture.performEditorAction("ParameterInfo");
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
}
|
||||
|
||||
private void complete(String partOfItemText) {
|
||||
LookupElement[] elements = myFixture.completeBasic();
|
||||
LookupElement element = Stream.of(elements).filter(e -> {
|
||||
LookupElementPresentation p = new LookupElementPresentation();
|
||||
e.renderElement(p);
|
||||
return (p.getItemText() + p.getTailText()).contains(partOfItemText);
|
||||
}).findAny().get();
|
||||
selectItem(element);
|
||||
}
|
||||
|
||||
private void waitTillAnimationCompletes() {
|
||||
long deadline = System.currentTimeMillis() + 60_000;
|
||||
while (ParameterHintsPresentationManager.getInstance().isAnimationInProgress(getEditor())) {
|
||||
if (System.currentTimeMillis() > deadline) fail("Too long waiting for animation to finish");
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -1005,6 +1005,10 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
public void testLowerBoundOfCapturedWildcardInSubtypingConstraint() throws Exception {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
public void testMembersContainedInCapturedWildcardType() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
+4
@@ -537,6 +537,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testMethodInInheritorFoundBySecondSearch() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNonExactMethodReferenceOnRawClassType() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.*;
|
||||
/**
|
||||
* @author Irina.Chernushina on 8/31/2015.
|
||||
*/
|
||||
class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
private final static Logger LOG = Logger.getInstance("#com.jetbrains.jsonSchema.JsonBySchemaAnnotator");
|
||||
private static final Key<Set<PsiElement>> ANNOTATED_PROPERTIES = Key.create("JsonSchema.Properties.Annotated");
|
||||
@NotNull private final VirtualFile mySchemaFile;
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.intellij.ide;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface HelpIdProvider {
|
||||
@Nullable String getHelpId();
|
||||
@Nullable @NonNls
|
||||
String getHelpId();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
|
||||
|
||||
@get:Property(filter = FontFilter::class)
|
||||
@get:OptionTag("FONT_SIZE")
|
||||
var fontSize by storedProperty(10)
|
||||
var fontSize by storedProperty(12)
|
||||
|
||||
@get:Property(filter = FontFilter::class)
|
||||
@get:OptionTag("FONT_SCALE")
|
||||
|
||||
@@ -29,6 +29,9 @@ public interface FontPreferences {
|
||||
int DEFAULT_FONT_SIZE = FontSize.SMALL.getSize();
|
||||
|
||||
float DEFAULT_LINE_SPACING = 1.0f;
|
||||
String MAC_OS_DEFAULT_FONT_FAMILY = "Menlo";
|
||||
String LINUX_DEFAULT_FONT_FAMILY = "DejaVu Sans Mono";
|
||||
String WINDOWS_DEFAULT_FONT_FAMILY = "Monospaced";
|
||||
|
||||
@NotNull
|
||||
List<String> getEffectiveFontFamilies();
|
||||
@@ -74,14 +77,14 @@ public interface FontPreferences {
|
||||
}
|
||||
|
||||
static String getDefaultFontName() {
|
||||
if (SystemInfo.isMacOSSnowLeopard) return "Menlo";
|
||||
if (SystemInfo.isMacOSSnowLeopard) return MAC_OS_DEFAULT_FONT_FAMILY;
|
||||
if (SystemInfo.isXWindow && !GraphicsEnvironment.isHeadless()) {
|
||||
for (Font font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) {
|
||||
if ("DejaVu Sans Mono".equals(font.getName())) {
|
||||
if (LINUX_DEFAULT_FONT_FAMILY.equals(font.getName())) {
|
||||
return font.getFontName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return "Monospaced";
|
||||
return WINDOWS_DEFAULT_FONT_FAMILY;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-7
@@ -35,7 +35,6 @@ import com.intellij.util.PlatformUtils;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -54,6 +53,7 @@ import static com.intellij.openapi.editor.markup.TextAttributes.USE_INHERITED_MA
|
||||
import static com.intellij.openapi.util.Couple.of;
|
||||
import static com.intellij.ui.ColorUtil.fromHex;
|
||||
|
||||
@SuppressWarnings("UseJBColor")
|
||||
public abstract class AbstractColorsScheme implements EditorColorsScheme, SerializableScheme {
|
||||
private static final int CURR_VERSION = 142;
|
||||
|
||||
@@ -422,10 +422,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
TextAttributes attr = myValueReader.read(TextAttributes.class, valueElement);
|
||||
myAttributesMap.put(key, attr);
|
||||
migrateErrorStripeColorFrom14(key, attr);
|
||||
if (attr != null) {
|
||||
myAttributesMap.put(key, attr);
|
||||
migrateErrorStripeColorFrom14(key, attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,10 +523,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
|
||||
}
|
||||
|
||||
private int readFontSize(Element element, boolean isDefault, Float fontScale) {
|
||||
Float size = (float)myValueReader.read(Integer.class, element);
|
||||
if (size == null) {
|
||||
Integer intSize = myValueReader.read(Integer.class, element);
|
||||
if (intSize == null) {
|
||||
return -1;
|
||||
}
|
||||
Float size = (float)intSize;
|
||||
if (!isDefault) {
|
||||
size = (fontScale != null) ? size / fontScale : DEFAULT_FONT_SIZE.getSize();
|
||||
}
|
||||
@@ -562,7 +564,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme, Serial
|
||||
parentNode.setAttribute(NAME_ATTR, getName());
|
||||
parentNode.setAttribute(VERSION_ATTR, Integer.toString(myVersion));
|
||||
|
||||
/**
|
||||
/*
|
||||
* FONT_SCALE is used to correctly identify the font size in both the JRE-managed HiDPI mode and
|
||||
* the IDE-managed HiDPI mode: {@link UIUtil#isJreHiDPIEnabled()}. Also, it helps to distinguish
|
||||
* the "hidpi-aware" scheme version from the previous one. Namely, the absence of the FONT_SCALE
|
||||
|
||||
+3
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
@@ -32,6 +33,7 @@ import java.awt.Color;
|
||||
*
|
||||
* @author Sergey.Malenkov
|
||||
*/
|
||||
@SuppressWarnings("UseJBColor")
|
||||
class ValueElementReader {
|
||||
@NonNls private static final String VALUE = "value";
|
||||
@NonNls private static final String MAC = "mac";
|
||||
@@ -60,6 +62,7 @@ class ValueElementReader {
|
||||
* @param <T> the result type
|
||||
* @return a value or {@code null} if it cannot be read
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T read(Class<T> type, Element element) {
|
||||
T value = null;
|
||||
if (element != null) {
|
||||
|
||||
+37
-19
@@ -20,11 +20,12 @@ import com.intellij.execution.actions.ConfigurationContext;
|
||||
import com.intellij.execution.actions.ConfigurationFromContext;
|
||||
import com.intellij.execution.actions.RunConfigurationProducer;
|
||||
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
|
||||
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Vladislav.Soroka
|
||||
@@ -37,7 +38,7 @@ public abstract class AbstractExternalSystemRunConfigurationProducer extends Run
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldReplace(ConfigurationFromContext self, ConfigurationFromContext other) {
|
||||
public boolean shouldReplace(@NotNull ConfigurationFromContext self, @NotNull ConfigurationFromContext other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,34 +46,33 @@ public abstract class AbstractExternalSystemRunConfigurationProducer extends Run
|
||||
protected boolean setupConfigurationFromContext(ExternalSystemRunConfiguration configuration,
|
||||
ConfigurationContext context,
|
||||
Ref<PsiElement> sourceElement) {
|
||||
Location location = context.getLocation();
|
||||
if (!(location instanceof ExternalSystemTaskLocation)) {
|
||||
Project project = getProjectFromContext(context);
|
||||
if (project == null) return false;
|
||||
|
||||
ExternalSystemTaskExecutionSettings contextTaskExecutionSettings = getTaskSettingsFromContext(context);
|
||||
if (contextTaskExecutionSettings == null) return false;
|
||||
|
||||
ExternalSystemTaskExecutionSettings taskExecutionSettings = configuration.getSettings();
|
||||
if (!contextTaskExecutionSettings.getExternalSystemId().equals(taskExecutionSettings.getExternalSystemId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExternalSystemTaskLocation taskLocation = (ExternalSystemTaskLocation)location;
|
||||
ExternalSystemTaskExecutionSettings taskExecutionSettings = configuration.getSettings();
|
||||
ExternalTaskExecutionInfo task = taskLocation.getTaskInfo();
|
||||
taskExecutionSettings.setExternalProjectPath(task.getSettings().getExternalProjectPath());
|
||||
taskExecutionSettings.setTaskNames(task.getSettings().getTaskNames());
|
||||
configuration.setName(AbstractExternalSystemTaskConfigurationType.generateName(location.getProject(), taskExecutionSettings));
|
||||
taskExecutionSettings.setExternalProjectPath(contextTaskExecutionSettings.getExternalProjectPath());
|
||||
taskExecutionSettings.setTaskNames(contextTaskExecutionSettings.getTaskNames());
|
||||
configuration.setName(AbstractExternalSystemTaskConfigurationType.generateName(project, taskExecutionSettings));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurationFromContext(ExternalSystemRunConfiguration configuration, ConfigurationContext context) {
|
||||
final Location contextLocation = context.getLocation();
|
||||
if (contextLocation == null) return false;
|
||||
Project project = getProjectFromContext(context);
|
||||
if (project == null) return false;
|
||||
|
||||
if (!(contextLocation instanceof ExternalSystemTaskLocation)) {
|
||||
return false;
|
||||
}
|
||||
ExternalSystemTaskExecutionSettings contextTaskExecutionSettings = getTaskSettingsFromContext(context);
|
||||
if (contextTaskExecutionSettings == null) return false;
|
||||
|
||||
ExternalSystemTaskLocation taskLocation = (ExternalSystemTaskLocation)contextLocation;
|
||||
ExternalSystemTaskExecutionSettings contextTaskExecutionSettings = taskLocation.getTaskInfo().getSettings();
|
||||
ExternalSystemTaskExecutionSettings taskExecutionSettings = configuration.getSettings();
|
||||
|
||||
if(!contextTaskExecutionSettings.getExternalSystemId().equals(taskExecutionSettings.getExternalSystemId())) {
|
||||
if (!contextTaskExecutionSettings.getExternalSystemId().equals(taskExecutionSettings.getExternalSystemId())) {
|
||||
return false;
|
||||
}
|
||||
if (!StringUtil.equals(contextTaskExecutionSettings.getExternalProjectPath(), taskExecutionSettings.getExternalProjectPath())) {
|
||||
@@ -81,4 +81,22 @@ public abstract class AbstractExternalSystemRunConfigurationProducer extends Run
|
||||
if (!contextTaskExecutionSettings.getTaskNames().equals(taskExecutionSettings.getTaskNames())) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ExternalSystemTaskExecutionSettings getTaskSettingsFromContext(ConfigurationContext context) {
|
||||
final Location contextLocation = context.getLocation();
|
||||
if (!(contextLocation instanceof ExternalSystemTaskLocation)) {
|
||||
return null;
|
||||
}
|
||||
return ((ExternalSystemTaskLocation)contextLocation).getTaskInfo().getSettings();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Project getProjectFromContext(ConfigurationContext context) {
|
||||
final Location contextLocation = context.getLocation();
|
||||
if (!(contextLocation instanceof ExternalSystemTaskLocation)) {
|
||||
return null;
|
||||
}
|
||||
return contextLocation.getProject();
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.openapi.externalSystem.service.project;
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
|
||||
import com.intellij.openapi.externalSystem.model.project.*;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleGrouperKt;
|
||||
@@ -103,11 +102,9 @@ public class IdeModelsProviderImpl implements IdeModelsProvider {
|
||||
}
|
||||
|
||||
private static boolean isApplicableIdeModule(@NotNull ModuleData moduleData, @NotNull Module ideModule) {
|
||||
if (ideModule.getProject().getUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT) == Boolean.TRUE) {
|
||||
for (VirtualFile root : ModuleRootManager.getInstance(ideModule).getContentRoots()) {
|
||||
if (pathsEqual(root.getPath(), moduleData.getLinkedExternalProjectPath())) {
|
||||
return true;
|
||||
}
|
||||
for (VirtualFile root : ModuleRootManager.getInstance(ideModule).getContentRoots()) {
|
||||
if (pathsEqual(root.getPath(), moduleData.getLinkedExternalProjectPath())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return isExternalSystemAwareModule(moduleData.getOwner(), ideModule) &&
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.lang.findUsages;
|
||||
|
||||
import com.intellij.lang.cacheBuilder.WordsScanner;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -54,7 +55,7 @@ public interface FindUsagesProvider {
|
||||
* @param psiElement the element for which the help topic is requested.
|
||||
* @return the help topic ID, or null if no help is available.
|
||||
*/
|
||||
@Nullable
|
||||
@Nullable @NonNls
|
||||
String getHelpId(@NotNull PsiElement psiElement);
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.ide.util.gotoByName;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -59,7 +60,7 @@ public interface ChooseByNameModel {
|
||||
@Nullable
|
||||
String getFullName(Object element);
|
||||
|
||||
@Nullable
|
||||
@Nullable @NonNls
|
||||
String getHelpId();
|
||||
|
||||
boolean willOpenEditor();
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -53,7 +53,7 @@ public class InlineElementData extends HighlightData {
|
||||
@Override
|
||||
public void addHighlToView(Editor view, EditorColorsScheme scheme, Map<TextAttributesKey, String> displayText) {
|
||||
int offset = getStartOffset();
|
||||
ParameterHintsPresentationManager.getInstance().addHint(view, offset, myText, false);
|
||||
ParameterHintsPresentationManager.getInstance().addHint(view, offset, myText, false, false);
|
||||
List<Inlay> inlays = view.getInlayModel().getInlineElementsInRange(offset, offset);
|
||||
for (Inlay inlay : inlays) {
|
||||
EditorCustomElementRenderer renderer = inlay.getRenderer();
|
||||
|
||||
+6
-2
@@ -863,8 +863,12 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
Project project = myProject;
|
||||
DaemonCodeAnalyzerImpl daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project);
|
||||
if (project == null || !project.isInitialized() || project.isDisposed() || PowerSaveMode.isEnabled() || daemonCodeAnalyzer.myDisposed) {
|
||||
DaemonCodeAnalyzerImpl daemonCodeAnalyzer;
|
||||
if (project == null ||
|
||||
!project.isInitialized() ||
|
||||
project.isDisposed() ||
|
||||
PowerSaveMode.isEnabled() ||
|
||||
(daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project)).myDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+22
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -33,6 +33,7 @@ import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ui.GraphicsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -42,6 +43,7 @@ import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class ParameterHintsPresentationManager implements Disposable {
|
||||
private static final Key<Boolean> PINNED = Key.create("parameter.hint.pinned");
|
||||
private static final Key<MyFontMetrics> HINT_FONT_METRICS = Key.create("ParameterHintFontMetrics");
|
||||
private static final Key<AnimationStep> ANIMATION_STEP = Key.create("ParameterHintAnimationStep");
|
||||
|
||||
@@ -62,17 +64,27 @@ public class ParameterHintsPresentationManager implements Disposable {
|
||||
return inlay.getRenderer() instanceof MyRenderer;
|
||||
}
|
||||
|
||||
public boolean isPinned(@NotNull Inlay inlay) {
|
||||
return Boolean.TRUE.equals(inlay.getUserData(PINNED));
|
||||
}
|
||||
|
||||
public void unpin(@NotNull Inlay inlay) {
|
||||
inlay.putUserData(PINNED, null);
|
||||
}
|
||||
|
||||
public String getHintText(@NotNull Inlay inlay) {
|
||||
EditorCustomElementRenderer renderer = inlay.getRenderer();
|
||||
return renderer instanceof MyRenderer ? ((MyRenderer)renderer).getText() : null;
|
||||
}
|
||||
|
||||
public void addHint(@NotNull Editor editor, int offset, @NotNull String hintText, boolean useAnimation) {
|
||||
public Inlay addHint(@NotNull Editor editor, int offset, @NotNull String hintText, boolean useAnimation, boolean pinned) {
|
||||
MyRenderer renderer = new MyRenderer(editor, hintText, useAnimation);
|
||||
Inlay inlay = editor.getInlayModel().addInlineElement(offset, renderer);
|
||||
if (useAnimation && inlay != null) {
|
||||
scheduleRendererUpdate(editor, inlay);
|
||||
if (inlay != null) {
|
||||
if (pinned) inlay.putUserData(PINNED, Boolean.TRUE);
|
||||
if (useAnimation) scheduleRendererUpdate(editor, inlay);
|
||||
}
|
||||
return inlay;
|
||||
}
|
||||
|
||||
public void deleteHint(@NotNull Editor editor, @NotNull Inlay hint) {
|
||||
@@ -109,6 +121,12 @@ public class ParameterHintsPresentationManager implements Disposable {
|
||||
myAlarm.addRequest(step, ANIMATION_STEP_MS, ModalityState.any());
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public boolean isAnimationInProgress(@NotNull Editor editor) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
return editor.getUserData(ANIMATION_STEP) != null;
|
||||
}
|
||||
|
||||
private static Font getFont(@NotNull Editor editor) {
|
||||
return getFontMetrics(editor).getFont();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -140,10 +140,6 @@ public class ParameterInfoComponent extends JPanel {
|
||||
return myHighlighted;
|
||||
}
|
||||
|
||||
public void setRequestFocus(boolean requestFocus) {
|
||||
myRequestFocus = requestFocus;
|
||||
}
|
||||
|
||||
public boolean isRequestFocus() {
|
||||
return myRequestFocus;
|
||||
}
|
||||
|
||||
+223
-22
@@ -16,18 +16,19 @@
|
||||
|
||||
package com.intellij.codeInsight.hint;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.ide.IdeTooltip;
|
||||
import com.intellij.injected.editor.EditorWindow;
|
||||
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
|
||||
import com.intellij.lang.parameterInfo.ParameterInfoHandlerWithTabActionSupport;
|
||||
import com.intellij.lang.parameterInfo.ParameterInfoUtils;
|
||||
import com.intellij.lang.parameterInfo.UpdateParameterInfoContext;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.event.*;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
@@ -36,19 +37,21 @@ import com.intellij.openapi.ui.popup.Balloon.Position;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.HintHint;
|
||||
import com.intellij.ui.LightweightHint;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.JBIterable;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -56,6 +59,8 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class ParameterInfoController implements Disposable {
|
||||
private final Project myProject;
|
||||
@@ -64,15 +69,16 @@ public class ParameterInfoController implements Disposable {
|
||||
private final RangeMarker myLbraceMarker;
|
||||
private final LightweightHint myHint;
|
||||
private final ParameterInfoComponent myComponent;
|
||||
private final boolean myKeepOnHintHidden;
|
||||
|
||||
private final CaretListener myEditorCaretListener;
|
||||
@NotNull private final ParameterInfoHandler<Object, Object> myHandler;
|
||||
private final ShowParameterInfoHandler.BestLocationPointProvider myProvider;
|
||||
private final MyBestLocationPointProvider myProvider;
|
||||
|
||||
private final Alarm myAlarm = new Alarm();
|
||||
private static final int DELAY = 200;
|
||||
|
||||
private boolean myDisposed = false;
|
||||
private boolean myDisposed;
|
||||
|
||||
/**
|
||||
* Keeps Vector of ParameterInfoController's in Editor
|
||||
@@ -85,7 +91,7 @@ public class ParameterInfoController implements Disposable {
|
||||
ParameterInfoController controller = allControllers.get(i);
|
||||
|
||||
if (controller.myLbraceMarker.getStartOffset() == offset) {
|
||||
if (controller.myHint.isVisible()) return controller;
|
||||
if (controller.myKeepOnHintHidden || controller.myHint.isVisible()) return controller;
|
||||
Disposer.dispose(controller);
|
||||
--i;
|
||||
}
|
||||
@@ -103,27 +109,40 @@ public class ParameterInfoController implements Disposable {
|
||||
return array;
|
||||
}
|
||||
|
||||
public static boolean isShownForEditor(@NotNull Editor editor) {
|
||||
public static boolean existsForEditor(@NotNull Editor editor) {
|
||||
return !getAllControllers(editor).isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isAlreadyShown(Editor editor, int lbraceOffset) {
|
||||
return findControllerAtOffset(editor, lbraceOffset) != null;
|
||||
ParameterInfoController controller = findControllerAtOffset(editor, lbraceOffset);
|
||||
return controller != null && controller.myHint.isVisible();
|
||||
}
|
||||
|
||||
public ParameterInfoController(@NotNull Project project,
|
||||
@NotNull Editor editor,
|
||||
int lbraceOffset,
|
||||
@NotNull LightweightHint hint,
|
||||
Object[] descriptors,
|
||||
Object highlighted,
|
||||
PsiElement parameterOwner,
|
||||
@NotNull ParameterInfoHandler handler,
|
||||
@NotNull ShowParameterInfoHandler.BestLocationPointProvider provider) {
|
||||
boolean showHint,
|
||||
boolean requestFocus) {
|
||||
myProject = project;
|
||||
myEditor = editor;
|
||||
myHandler = handler;
|
||||
myProvider = provider;
|
||||
myProvider = new MyBestLocationPointProvider(editor);
|
||||
myLbraceMarker = editor.getDocument().createRangeMarker(lbraceOffset, lbraceOffset);
|
||||
myHint = hint;
|
||||
myComponent = (ParameterInfoComponent)myHint.getComponent();
|
||||
myComponent = new ParameterInfoComponent(descriptors, editor, handler, requestFocus);
|
||||
myHint = new LightweightHint(myComponent);
|
||||
myKeepOnHintHidden = !showHint;
|
||||
|
||||
myHint.setSelectingHint(true);
|
||||
myComponent.setParameterOwner(parameterOwner);
|
||||
myComponent.setHighlightedParameter(highlighted);
|
||||
myComponent.update(); // to have correct preferred size
|
||||
if (showHint) {
|
||||
showHint(requestFocus);
|
||||
}
|
||||
|
||||
List<ParameterInfoController> allControllers = getAllControllers(myEditor);
|
||||
allControllers.add(this);
|
||||
@@ -175,12 +194,26 @@ public class ParameterInfoController implements Disposable {
|
||||
public void dispose(){
|
||||
if (myDisposed) return;
|
||||
myDisposed = true;
|
||||
|
||||
myHint.hide();
|
||||
List<ParameterInfoController> allControllers = getAllControllers(myEditor);
|
||||
allControllers.remove(this);
|
||||
myEditor.getCaretModel().removeCaretListener(myEditorCaretListener);
|
||||
}
|
||||
|
||||
public void showHint(boolean requestFocus) {
|
||||
Pair<Point, Short> pos = myProvider.getBestPointPosition(myHint, myComponent.getParameterOwner(), myLbraceMarker.getStartOffset(), true, HintManager.UNDER);
|
||||
HintHint hintHint = HintManagerImpl.createHintHint(myEditor, pos.getFirst(), myHint, pos.getSecond());
|
||||
hintHint.setExplicitClose(true);
|
||||
hintHint.setRequestFocus(requestFocus);
|
||||
|
||||
Editor editorToShow = myEditor instanceof EditorWindow ? ((EditorWindow)myEditor).getDelegate() : myEditor;
|
||||
// is case of injection we need to calculate position for EditorWindow
|
||||
// also we need to show the hint in the main editor because of intention bulb
|
||||
HintManagerImpl.getInstanceImpl().showEditorHint(myHint, editorToShow, pos.getFirst(), HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING, 0, false, hintHint);
|
||||
|
||||
updateComponent();
|
||||
}
|
||||
|
||||
private void adjustPositionForLookup(@NotNull Lookup lookup) {
|
||||
if (!myHint.isVisible() || myEditor.isDisposed()) {
|
||||
Disposer.dispose(this);
|
||||
@@ -221,8 +254,34 @@ public class ParameterInfoController implements Disposable {
|
||||
myAlarm.addRequest(request, DELAY, ModalityState.stateForComponent(myEditor.getComponent()));
|
||||
}
|
||||
|
||||
private void updateComponent(){
|
||||
if (!myHint.isVisible()){
|
||||
public void updateComponent(){
|
||||
if (myKeepOnHintHidden) {
|
||||
boolean removeHints = true;
|
||||
PsiElement owner = myComponent.getParameterOwner();
|
||||
if (owner != null && owner.isValid()) {
|
||||
int caretOffset = myEditor.getCaretModel().getOffset();
|
||||
TextRange ownerTextRange = owner.getTextRange();
|
||||
if (ownerTextRange != null) {
|
||||
if (caretOffset > ownerTextRange.getStartOffset() && caretOffset < ownerTextRange.getEndOffset()) {
|
||||
removeHints = false;
|
||||
}
|
||||
else {
|
||||
for (PsiElement element : owner.getChildren()) {
|
||||
if (element instanceof PsiErrorElement) {
|
||||
removeHints = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removeHints) {
|
||||
Disposer.dispose(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!myHint.isVisible() && !myKeepOnHintHidden && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
Disposer.dispose(this);
|
||||
return;
|
||||
}
|
||||
@@ -290,12 +349,26 @@ public class ParameterInfoController implements Disposable {
|
||||
PsiElement argsList = findArgumentList(file, offset, -1);
|
||||
if (argsList == null) return;
|
||||
|
||||
myEditor.getCaretModel().moveToOffset(offset);
|
||||
offset = adjustOffsetToInlay(offset);
|
||||
|
||||
myEditor.getCaretModel().moveToLogicalPosition(myEditor.offsetToLogicalPosition(offset).leanForward(true));
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
myEditor.getSelectionModel().removeSelection();
|
||||
myHandler.updateParameterInfo(argsList, new MyUpdateParameterInfoContext(offset, file));
|
||||
}
|
||||
|
||||
private int adjustOffsetToInlay(int offset) {
|
||||
CharSequence text = myEditor.getDocument().getImmutableCharSequence();
|
||||
String whitespaceChars = " \t";
|
||||
int whitespaceStart = CharArrayUtil.shiftBackward(text, offset, whitespaceChars) + 1;
|
||||
int whitespaceEnd = CharArrayUtil.shiftForward(text, offset, whitespaceChars);
|
||||
List<Inlay> inlays = myEditor.getInlayModel().getInlineElementsInRange(whitespaceStart, whitespaceEnd);
|
||||
for (Inlay inlay : inlays) {
|
||||
if (ParameterHintsPresentationManager.getInstance().isParameterHint(inlay)) return inlay.getOffset();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
private int getPrevOrNextParameterOffset(boolean isNext) {
|
||||
if (!(myHandler instanceof ParameterInfoHandlerWithTabActionSupport)) return -1;
|
||||
ParameterInfoHandlerWithTabActionSupport handler = (ParameterInfoHandlerWithTabActionSupport)myHandler;
|
||||
@@ -338,7 +411,93 @@ public class ParameterInfoController implements Disposable {
|
||||
return null;
|
||||
}
|
||||
|
||||
private class MyUpdateParameterInfoContext implements UpdateParameterInfoContext {
|
||||
public Object[] getObjects() {
|
||||
return myComponent.getObjects();
|
||||
}
|
||||
|
||||
public Object getHighlighted() {
|
||||
return myComponent.getHighlighted();
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public static void waitForDelayedActions(@NotNull Editor editor, long timeout, @NotNull TimeUnit unit) throws TimeoutException {
|
||||
long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
List<ParameterInfoController> controllers = getAllControllers(editor);
|
||||
boolean hasPendingRequests = false;
|
||||
for (ParameterInfoController controller : controllers) {
|
||||
if (!controller.myAlarm.isEmpty()) {
|
||||
hasPendingRequests = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPendingRequests) UIUtil.dispatchAllInvocationEvents();
|
||||
else return;
|
||||
}
|
||||
throw new TimeoutException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Point in layered pane coordinate system
|
||||
*/
|
||||
static Pair<Point, Short> chooseBestHintPosition(Project project,
|
||||
Editor editor,
|
||||
LogicalPosition pos,
|
||||
LightweightHint hint,
|
||||
boolean awtTooltip, short preferredPosition) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) return Pair.pair(new Point(), HintManager.DEFAULT);
|
||||
|
||||
HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
|
||||
Dimension hintSize = hint.getComponent().getPreferredSize();
|
||||
JComponent editorComponent = editor.getComponent();
|
||||
JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
|
||||
|
||||
Point p1;
|
||||
Point p2;
|
||||
boolean isLookupShown = LookupManager.getInstance(project).getActiveLookup() != null;
|
||||
if (isLookupShown) {
|
||||
p1 = hintManager.getHintPosition(hint, editor, HintManager.UNDER);
|
||||
p2 = hintManager.getHintPosition(hint, editor, HintManager.ABOVE);
|
||||
}
|
||||
else {
|
||||
p1 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.UNDER);
|
||||
p2 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.ABOVE);
|
||||
}
|
||||
|
||||
if (!awtTooltip) {
|
||||
p1.x = Math.min(p1.x, layeredPane.getWidth() - hintSize.width);
|
||||
p1.x = Math.max(p1.x, 0);
|
||||
p2.x = Math.min(p2.x, layeredPane.getWidth() - hintSize.width);
|
||||
p2.x = Math.max(p2.x, 0);
|
||||
}
|
||||
|
||||
boolean p1Ok = p1.y + hintSize.height < layeredPane.getHeight();
|
||||
boolean p2Ok = p2.y >= 0;
|
||||
|
||||
if (isLookupShown) {
|
||||
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
|
||||
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
|
||||
}
|
||||
else {
|
||||
if (preferredPosition != HintManager.DEFAULT) {
|
||||
if (preferredPosition == HintManager.ABOVE) {
|
||||
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
|
||||
} else if (preferredPosition == HintManager.UNDER) {
|
||||
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
|
||||
}
|
||||
}
|
||||
|
||||
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
|
||||
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
|
||||
}
|
||||
|
||||
int underSpace = layeredPane.getHeight() - p1.y;
|
||||
int aboveSpace = p2.y;
|
||||
return aboveSpace > underSpace ? new Pair<>(new Point(p2.x, 0), HintManager.UNDER) : new Pair<>(p1,
|
||||
HintManager.ABOVE);
|
||||
}
|
||||
|
||||
public class MyUpdateParameterInfoContext implements UpdateParameterInfoContext {
|
||||
private final int myOffset;
|
||||
private final PsiFile myFile;
|
||||
|
||||
@@ -415,4 +574,46 @@ public class ParameterInfoController implements Disposable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MyBestLocationPointProvider {
|
||||
private final Editor myEditor;
|
||||
private int previousOffset = -1;
|
||||
private Point previousBestPoint;
|
||||
private Short previousBestPosition;
|
||||
|
||||
public MyBestLocationPointProvider(final Editor editor) {
|
||||
myEditor = editor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Pair<Point, Short> getBestPointPosition(LightweightHint hint,
|
||||
final PsiElement list,
|
||||
int offset,
|
||||
final boolean awtTooltip,
|
||||
short preferredPosition) {
|
||||
if (list != null) {
|
||||
TextRange range = list.getTextRange();
|
||||
if (!range.contains(offset)) {
|
||||
offset = range.getStartOffset() + 1;
|
||||
}
|
||||
}
|
||||
if (previousOffset == offset) return Pair.create(previousBestPoint, previousBestPosition);
|
||||
|
||||
final boolean isMultiline = list != null && StringUtil.containsAnyChar(list.getText(), "\n\r");
|
||||
final LogicalPosition pos = myEditor.offsetToLogicalPosition(offset).leanForward(true);
|
||||
Pair<Point, Short> position;
|
||||
|
||||
if (!isMultiline) {
|
||||
position = chooseBestHintPosition(myEditor.getProject(), myEditor, pos, hint, awtTooltip, preferredPosition);
|
||||
}
|
||||
else {
|
||||
Point p = HintManagerImpl.getHintPosition(hint, myEditor, pos, HintManager.ABOVE);
|
||||
position = new Pair<>(p, HintManager.ABOVE);
|
||||
}
|
||||
previousBestPoint = position.getFirst();
|
||||
previousBestPosition = position.getSecond();
|
||||
previousOffset = offset;
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -40,7 +40,7 @@ public class PrevNextParameterHandler extends EditorActionHandler {
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledForCaret(@NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) {
|
||||
if (!ParameterInfoController.isShownForEditor(editor)) return false;
|
||||
if (!ParameterInfoController.existsForEditor(editor)) return false;
|
||||
|
||||
Project project = CommonDataKeys.PROJECT.getData(dataContext);
|
||||
if (project == null) return false;
|
||||
@@ -49,7 +49,7 @@ public class PrevNextParameterHandler extends EditorActionHandler {
|
||||
if (exprList == null) return false;
|
||||
|
||||
int lbraceOffset = exprList.getTextRange().getStartOffset();
|
||||
return ParameterInfoController.isAlreadyShown(editor, lbraceOffset) &&
|
||||
return ParameterInfoController.findControllerAtOffset(editor, lbraceOffset) != null &&
|
||||
ParameterInfoController.hasPrevOrNextParameter(editor, lbraceOffset, myIsNextParameterHandler);
|
||||
}
|
||||
|
||||
|
||||
+8
-138
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -15,29 +15,18 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.hint;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.injected.editor.EditorWindow;
|
||||
import com.intellij.lang.parameterInfo.CreateParameterInfoContext;
|
||||
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.ui.HintHint;
|
||||
import com.intellij.ui.LightweightHint;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
@@ -131,20 +120,6 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
|
||||
if (ParameterInfoController.isAlreadyShown(editor, elementStart)) return;
|
||||
|
||||
if (editor.isDisposed() || !editor.getComponent().isVisible()) return;
|
||||
final ParameterInfoComponent component = new ParameterInfoComponent(descriptors, editor,handler,requestFocus);
|
||||
component.setParameterOwner(element);
|
||||
component.setRequestFocus(requestFocus);
|
||||
if (highlighted != null) {
|
||||
component.setHighlightedParameter(highlighted);
|
||||
}
|
||||
|
||||
component.update(); // to have correct preferred size
|
||||
|
||||
final LightweightHint hint = new LightweightHint(component);
|
||||
hint.setSelectingHint(true);
|
||||
final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
|
||||
final ShowParameterInfoHandler.BestLocationPointProvider provider = new MyBestLocationPointProvider(editor);
|
||||
final Pair<Point, Short> pos = provider.getBestPointPosition(hint, element, elementStart, true, HintManager.UNDER);
|
||||
|
||||
PsiDocumentManager.getInstance(project).performLaterWhenAllCommitted(() -> {
|
||||
if (editor.isDisposed() || DumbService.isDumb(project)) return;
|
||||
@@ -152,15 +127,13 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
|
||||
final Document document = editor.getDocument();
|
||||
if (document.getTextLength() < elementStart) return;
|
||||
|
||||
HintHint hintHint = HintManagerImpl.createHintHint(editor, pos.getFirst(), hint, pos.getSecond());
|
||||
hintHint.setExplicitClose(true);
|
||||
hintHint.setRequestFocus(requestFocus);
|
||||
|
||||
Editor editorToShow = editor instanceof EditorWindow ? ((EditorWindow)editor).getDelegate() : editor;
|
||||
// is case of injection we need to calculate position for EditorWindow
|
||||
// also we need to show the hint in the main editor because of intention bulb
|
||||
hintManager.showEditorHint(hint, editorToShow, pos.getFirst(), HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING, 0, false, hintHint);
|
||||
new ParameterInfoController(project, editor, elementStart, hint, handler, provider);
|
||||
ParameterInfoController controller = ParameterInfoController.findControllerAtOffset(editor, elementStart);
|
||||
if (controller == null) {
|
||||
new ParameterInfoController(project, editor, elementStart, descriptors, highlighted, element, handler, true, requestFocus);
|
||||
}
|
||||
else {
|
||||
controller.showHint(requestFocus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -175,66 +148,6 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
|
||||
showParameterHint(list, editor, candidates, project, candidates.length > 1 ? highlighted : null, offset, handler, requestFocus);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Point in layered pane coordinate system
|
||||
*/
|
||||
static Pair<Point, Short> chooseBestHintPosition(Project project,
|
||||
Editor editor,
|
||||
int line,
|
||||
int col,
|
||||
LightweightHint hint,
|
||||
boolean awtTooltip, short preferredPosition) {
|
||||
HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
|
||||
Dimension hintSize = hint.getComponent().getPreferredSize();
|
||||
JComponent editorComponent = editor.getComponent();
|
||||
JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
|
||||
|
||||
Point p1;
|
||||
Point p2;
|
||||
boolean isLookupShown = LookupManager.getInstance(project).getActiveLookup() != null;
|
||||
if (isLookupShown) {
|
||||
p1 = hintManager.getHintPosition(hint, editor, HintManager.UNDER);
|
||||
p2 = hintManager.getHintPosition(hint, editor, HintManager.ABOVE);
|
||||
}
|
||||
else {
|
||||
LogicalPosition pos = new LogicalPosition(line, col);
|
||||
p1 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.UNDER);
|
||||
p2 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.ABOVE);
|
||||
}
|
||||
|
||||
if (!awtTooltip) {
|
||||
p1.x = Math.min(p1.x, layeredPane.getWidth() - hintSize.width);
|
||||
p1.x = Math.max(p1.x, 0);
|
||||
p2.x = Math.min(p2.x, layeredPane.getWidth() - hintSize.width);
|
||||
p2.x = Math.max(p2.x, 0);
|
||||
}
|
||||
|
||||
boolean p1Ok = p1.y + hintSize.height < layeredPane.getHeight();
|
||||
boolean p2Ok = p2.y >= 0;
|
||||
|
||||
if (isLookupShown) {
|
||||
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
|
||||
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
|
||||
}
|
||||
else {
|
||||
if (preferredPosition != HintManager.DEFAULT) {
|
||||
if (preferredPosition == HintManager.ABOVE) {
|
||||
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
|
||||
} else if (preferredPosition == HintManager.UNDER) {
|
||||
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
|
||||
}
|
||||
}
|
||||
|
||||
if (p1Ok) return new Pair<>(p1, HintManager.UNDER);
|
||||
if (p2Ok) return new Pair<>(p2, HintManager.ABOVE);
|
||||
}
|
||||
|
||||
int underSpace = layeredPane.getHeight() - p1.y;
|
||||
int aboveSpace = p2.y;
|
||||
return aboveSpace > underSpace ? new Pair<>(new Point(p2.x, 0), HintManager.UNDER) : new Pair<>(p1,
|
||||
HintManager.ABOVE);
|
||||
}
|
||||
|
||||
public void setRequestFocus(boolean requestFocus) {
|
||||
myRequestFocus = requestFocus;
|
||||
}
|
||||
@@ -242,47 +155,4 @@ public class ShowParameterInfoContext implements CreateParameterInfoContext {
|
||||
public boolean isRequestFocus() {
|
||||
return myRequestFocus;
|
||||
}
|
||||
|
||||
static class MyBestLocationPointProvider implements ShowParameterInfoHandler.BestLocationPointProvider {
|
||||
private final Editor myEditor;
|
||||
private int previousOffset = -1;
|
||||
private Point previousBestPoint;
|
||||
private Short previousBestPosition;
|
||||
|
||||
public MyBestLocationPointProvider(final Editor editor) {
|
||||
myEditor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Pair<Point, Short> getBestPointPosition(LightweightHint hint,
|
||||
final PsiElement list,
|
||||
int offset,
|
||||
final boolean awtTooltip,
|
||||
short preferredPosition) {
|
||||
if (list != null) {
|
||||
TextRange range = list.getTextRange();
|
||||
if (!range.contains(offset)) {
|
||||
offset = range.getStartOffset() + 1;
|
||||
}
|
||||
}
|
||||
if (previousOffset == offset) return Pair.create(previousBestPoint, previousBestPosition);
|
||||
|
||||
final boolean isMultiline = list != null && StringUtil.containsAnyChar(list.getText(), "\n\r");
|
||||
final LogicalPosition pos = myEditor.offsetToLogicalPosition(offset);
|
||||
Pair<Point, Short> position;
|
||||
|
||||
if (!isMultiline) {
|
||||
position = chooseBestHintPosition(myEditor.getProject(), myEditor, pos.line, pos.column, hint, awtTooltip, preferredPosition);
|
||||
}
|
||||
else {
|
||||
Point p = HintManagerImpl.getHintPosition(hint, myEditor, pos, HintManager.ABOVE);
|
||||
position = new Pair<>(p, HintManager.ABOVE);
|
||||
}
|
||||
previousBestPoint = position.getFirst();
|
||||
previousBestPosition = position.getSecond();
|
||||
previousOffset = offset;
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -142,7 +142,7 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
|
||||
final LightweightHint hint = new LightweightHint(component);
|
||||
hint.setSelectingHint(true);
|
||||
final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
|
||||
final Pair<Point, Short> pos = ShowParameterInfoContext.chooseBestHintPosition(project, editor, -1, -1, hint, true, HintManager.DEFAULT);
|
||||
final Pair<Point, Short> pos = ParameterInfoController.chooseBestHintPosition(project, editor, null, hint, true, HintManager.DEFAULT);
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
if (!editor.getComponent().isShowing()) return;
|
||||
hintManager.showEditorHint(hint, editor, pos.getFirst(),
|
||||
@@ -160,15 +160,5 @@ public class ShowParameterInfoHandler implements CodeInsightActionHandler {
|
||||
if (handlers.isEmpty()) return null;
|
||||
return handlers.toArray(new ParameterInfoHandler[handlers.size()]);
|
||||
}
|
||||
|
||||
interface BestLocationPointProvider {
|
||||
@NotNull
|
||||
Pair<Point, Short> getBestPointPosition(LightweightHint hint,
|
||||
final PsiElement list,
|
||||
int offset,
|
||||
final boolean awtTooltip,
|
||||
short preferredPosition);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -146,7 +146,7 @@ public class ParameterHintsPassFactory extends AbstractProjectComponent implemen
|
||||
String newText = myAnnotations.remove(offset);
|
||||
String oldText = presentationManager.getHintText(inlay);
|
||||
|
||||
if (delayRemoval(inlay, caretMap)) continue;
|
||||
if (delayRemoval(inlay, caretMap) || presentationManager.isPinned(inlay)) continue;
|
||||
if (!Objects.equals(newText, oldText)) {
|
||||
if (newText == null) {
|
||||
removedHints.add(oldText);
|
||||
@@ -160,7 +160,7 @@ public class ParameterHintsPassFactory extends AbstractProjectComponent implemen
|
||||
for (Map.Entry<Integer, String> e : myAnnotations.entrySet()) {
|
||||
int offset = e.getKey();
|
||||
String text = e.getValue();
|
||||
presentationManager.addHint(myEditor, offset, text, !firstTime && !removedHints.contains(text));
|
||||
presentationManager.addHint(myEditor, offset, text, !firstTime && !removedHints.contains(text), false);
|
||||
}
|
||||
keeper.restoreOriginalLocation();
|
||||
myEditor.putUserData(REPEATED_PASS, Boolean.TRUE);
|
||||
|
||||
@@ -46,13 +46,13 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
|
||||
|
||||
private long myLastChangeId;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public FileUndoProvider() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public FileUndoProvider(Project project) {
|
||||
myProject = project;
|
||||
private FileUndoProvider(Project project) {
|
||||
myProject = project;
|
||||
if (myProject == null) return;
|
||||
|
||||
LocalHistoryImpl localHistory = LocalHistoryImpl.getInstanceImpl();
|
||||
@@ -99,7 +99,7 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
|
||||
}
|
||||
|
||||
private void processEvent(VirtualFileEvent e) {
|
||||
if (shouldNotProcess(e)) return;
|
||||
if (!shouldProcess(e)) return;
|
||||
if (isUndoable(e)) {
|
||||
registerUndoableAction(e);
|
||||
}
|
||||
@@ -110,14 +110,14 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
|
||||
|
||||
@Override
|
||||
public void beforeContentsChange(@NotNull VirtualFileEvent e) {
|
||||
if (shouldNotProcess(e)) return;
|
||||
if (!shouldProcess(e)) return;
|
||||
if (isUndoable(e)) return;
|
||||
registerNonUndoableAction(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeFileDeletion(@NotNull VirtualFileEvent e) {
|
||||
if (shouldNotProcess(e)) {
|
||||
if (!shouldProcess(e)) {
|
||||
invalidateActionsFor(e);
|
||||
return;
|
||||
}
|
||||
@@ -132,6 +132,7 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
|
||||
|
||||
@Override
|
||||
public void fileDeleted(@NotNull VirtualFileEvent e) {
|
||||
if (!shouldProcess(e)) return;
|
||||
VirtualFile f = e.getFile();
|
||||
|
||||
DocumentReference ref = f.getUserData(DELETION_WAS_UNDOABLE);
|
||||
@@ -141,13 +142,11 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldNotProcess(VirtualFileEvent e) {
|
||||
return isProjectClosed() || !LocalHistory.getInstance().isUnderControl(e.getFile()) || !myIsInsideCommand
|
||||
|| FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(e.getRequestor());
|
||||
}
|
||||
|
||||
private boolean isProjectClosed() {
|
||||
return myProject.isDisposed();
|
||||
private boolean shouldProcess(VirtualFileEvent e) {
|
||||
return !myProject.isDisposed() &&
|
||||
LocalHistory.getInstance().isUnderControl(e.getFile()) &&
|
||||
myIsInsideCommand &&
|
||||
!FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(e.getRequestor());
|
||||
}
|
||||
|
||||
private static boolean isUndoable(VirtualFileEvent e) {
|
||||
@@ -167,7 +166,9 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
|
||||
}
|
||||
|
||||
private void invalidateActionsFor(VirtualFileEvent e) {
|
||||
getUndoManager().invalidateActionsFor(createDocumentReference(e));
|
||||
if (myProject == null || !myProject.isDisposed()) {
|
||||
getUndoManager().invalidateActionsFor(createDocumentReference(e));
|
||||
}
|
||||
}
|
||||
|
||||
private static DocumentReference createDocumentReference(VirtualFileEvent e) {
|
||||
@@ -185,7 +186,7 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider
|
||||
private ChangeRange myActionChangeRange;
|
||||
private ChangeRange myUndoChangeRange;
|
||||
|
||||
public MyUndoableAction(DocumentReference r) {
|
||||
MyUndoableAction(DocumentReference r) {
|
||||
super(r);
|
||||
myActionChangeRange = new ChangeRange(myGateway, myLocalHistory, myLastChangeId);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.ide.wizard;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -97,6 +98,7 @@ public abstract class AbstractWizardStepEx implements Step, Disposable {
|
||||
@Nullable
|
||||
public abstract JComponent getPreferredFocusedComponent();
|
||||
|
||||
@NonNls
|
||||
public String getHelpId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1526,7 +1526,7 @@ public abstract class DialogWrapper {
|
||||
/**
|
||||
* @return the help identifier or null if no help is available.
|
||||
*/
|
||||
@Nullable
|
||||
@Nullable @NonNls
|
||||
protected String getHelpId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -654,23 +654,19 @@ public class HintManagerImpl extends HintManager implements Disposable {
|
||||
@PositionFlags short constraint,
|
||||
boolean showByBalloon) {
|
||||
Dimension hintSize = hint.getComponent().getPreferredSize();
|
||||
int line1 = pos1.line;
|
||||
int col1 = pos1.column;
|
||||
int line2 = pos2.line;
|
||||
int col2 = pos2.column;
|
||||
|
||||
Point location;
|
||||
JComponent externalComponent = getExternalComponent(editor);
|
||||
JComponent internalComponent = editor.getContentComponent();
|
||||
if (constraint == RIGHT_UNDER) {
|
||||
Point p = editor.logicalPositionToXY(new LogicalPosition(line2, col2));
|
||||
Point p = editor.logicalPositionToXY(pos2);
|
||||
if (!showByBalloon) {
|
||||
p.y += editor.getLineHeight();
|
||||
}
|
||||
location = SwingUtilities.convertPoint(internalComponent, p, externalComponent);
|
||||
}
|
||||
else {
|
||||
Point p = editor.logicalPositionToXY(new LogicalPosition(line1, col1));
|
||||
Point p = editor.logicalPositionToXY(pos1);
|
||||
if (constraint == UNDER) {
|
||||
p.y += editor.getLineHeight();
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,10 +36,7 @@ import com.intellij.util.containers.Stack;
|
||||
import com.intellij.util.containers.WeakHashMap;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -63,6 +60,7 @@ public class LaterInvocator {
|
||||
@NotNull private final Condition<?> expired;
|
||||
@NotNull private final ActionCallback callback;
|
||||
|
||||
@Debugger.Capture
|
||||
RunnableInfo(@NotNull Runnable runnable,
|
||||
@NotNull ModalityState modalityState,
|
||||
@NotNull Condition<?> expired,
|
||||
@@ -401,6 +399,7 @@ public class LaterInvocator {
|
||||
}
|
||||
}
|
||||
|
||||
@Debugger.Insert(keyExpression = "lastInfo")
|
||||
private boolean runNextEvent() {
|
||||
final RunnableInfo lastInfo = getNextEvent(true);
|
||||
myLastInfo = lastInfo;
|
||||
|
||||
+9
-12
@@ -62,7 +62,7 @@ public class DocumentUndoProvider implements Disposable {
|
||||
@Override
|
||||
public void beforeDocumentChange(DocumentEvent e) {
|
||||
Document document = e.getDocument();
|
||||
if (shouldBeIgnored(document)) return;
|
||||
if (!shouldProcess(document)) return;
|
||||
|
||||
UndoManagerImpl undoManager = getUndoManager();
|
||||
if (undoManager.isActive() && isUndoable(document) && (undoManager.isUndoInProgress() || undoManager.isRedoInProgress()) &&
|
||||
@@ -74,7 +74,7 @@ public class DocumentUndoProvider implements Disposable {
|
||||
@Override
|
||||
public void documentChanged(final DocumentEvent e) {
|
||||
Document document = e.getDocument();
|
||||
if (shouldBeIgnored(document)) return;
|
||||
if (!shouldProcess(document)) return;
|
||||
|
||||
UndoManagerImpl undoManager = getUndoManager();
|
||||
if (undoManager.isActive() && isUndoable(document)) {
|
||||
@@ -85,11 +85,12 @@ public class DocumentUndoProvider implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldBeIgnored(Document document) {
|
||||
return UndoManagerImpl.isCopy(document) // if we don't ignore copy's events, we will receive notification
|
||||
// for the same event twice (from original document too)
|
||||
// and undo will work incorrectly
|
||||
|| !shouldRecordActions(document);
|
||||
private boolean shouldProcess(Document document) {
|
||||
if (myProject != null && myProject.isDisposed()) return false;
|
||||
return !UndoManagerImpl.isCopy(document) // if we don't ignore copy's events, we will receive notification
|
||||
// for the same event twice (from original document too)
|
||||
// and undo will work incorrectly
|
||||
&& shouldRecordActions(document);
|
||||
}
|
||||
|
||||
private boolean shouldRecordActions(final Document document) {
|
||||
@@ -116,11 +117,7 @@ public class DocumentUndoProvider implements Disposable {
|
||||
if (file != null && file.getUserData(UndoConstants.FORCE_RECORD_UNDO) == Boolean.TRUE) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (!UndoManagerImpl.isRefresh()) return true;
|
||||
}
|
||||
|
||||
return getUndoManager().isUndoOrRedoAvailable(ref);
|
||||
return !UndoManagerImpl.isRefresh() || getUndoManager().isUndoOrRedoAvailable(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +79,8 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
private int myCommandTimestamp = 1;
|
||||
|
||||
private int myCommandLevel;
|
||||
private static final int NONE = 0;
|
||||
private static final int UNDO = 1;
|
||||
private static final int REDO = 2;
|
||||
private int myCurrentOperationState = NONE;
|
||||
private enum OperationState { NONE, UNDO, REDO }
|
||||
private OperationState myCurrentOperationState = OperationState.NONE;
|
||||
|
||||
private DocumentReference myOriginatorReference;
|
||||
|
||||
@@ -129,16 +127,19 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
|
||||
@Override
|
||||
public void commandStarted(CommandEvent event) {
|
||||
if (myProject != null && myProject.isDisposed()) return;
|
||||
onCommandStarted(event.getProject(), event.getUndoConfirmationPolicy(), event.shouldRecordActionForOriginalDocument());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commandFinished(CommandEvent event) {
|
||||
if (myProject != null && myProject.isDisposed()) return;
|
||||
onCommandFinished(event.getProject(), event.getCommandName(), event.getCommandGroupId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoTransparentActionStarted() {
|
||||
if (myProject != null && myProject.isDisposed()) return;
|
||||
if (!isInsideCommand()) {
|
||||
myStarted = true;
|
||||
onCommandStarted(myProject, UndoConfirmationPolicy.DEFAULT, true);
|
||||
@@ -147,6 +148,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
|
||||
@Override
|
||||
public void undoTransparentActionFinished() {
|
||||
if (myProject != null && myProject.isDisposed()) return;
|
||||
if (myStarted) {
|
||||
myStarted = false;
|
||||
onCommandFinished(myProject, "", null);
|
||||
@@ -277,14 +279,16 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
@Override
|
||||
public void nonundoableActionPerformed(@NotNull final DocumentReference ref, final boolean isGlobal) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (myProject != null && myProject.isDisposed()) return;
|
||||
undoableActionPerformed(new NonUndoableAction(ref, isGlobal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoableActionPerformed(@NotNull UndoableAction action) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (myProject != null && myProject.isDisposed()) return;
|
||||
|
||||
if (myCurrentOperationState != NONE) return;
|
||||
if (myCurrentOperationState != OperationState.NONE) return;
|
||||
|
||||
if (myCommandLevel == 0) {
|
||||
LOG.assertTrue(action instanceof NonUndoableAction,
|
||||
@@ -355,7 +359,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
}
|
||||
|
||||
private void undoOrRedo(final FileEditor editor, final boolean isUndo) {
|
||||
myCurrentOperationState = isUndo ? UNDO : REDO;
|
||||
myCurrentOperationState = isUndo ? OperationState.UNDO : OperationState.REDO;
|
||||
|
||||
final RuntimeException[] exception = new RuntimeException[1];
|
||||
Runnable executeUndoOrRedoAction = () -> {
|
||||
@@ -370,7 +374,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
exception[0] = ex;
|
||||
}
|
||||
finally {
|
||||
myCurrentOperationState = NONE;
|
||||
myCurrentOperationState = OperationState.NONE;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -382,12 +386,12 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
|
||||
@Override
|
||||
public boolean isUndoInProgress() {
|
||||
return myCurrentOperationState == UNDO;
|
||||
return myCurrentOperationState == OperationState.UNDO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedoInProgress() {
|
||||
return myCurrentOperationState == REDO;
|
||||
return myCurrentOperationState == OperationState.REDO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -518,7 +522,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
}
|
||||
|
||||
protected void compact() {
|
||||
if (myCurrentOperationState == NONE && myCommandTimestamp % COMMAND_TO_RUN_COMPACT == 0) {
|
||||
if (myCurrentOperationState == OperationState.NONE && myCommandTimestamp % COMMAND_TO_RUN_COMPACT == 0) {
|
||||
doCompact();
|
||||
}
|
||||
}
|
||||
@@ -597,6 +601,7 @@ public class UndoManagerImpl extends UndoManager implements Disposable {
|
||||
|
||||
@TestOnly
|
||||
private void flushMergers() {
|
||||
assert myProject == null || !myProject.isDisposed();
|
||||
// Run dummy command in order to flush all mergers...
|
||||
CommandProcessor.getInstance().executeCommand(myProject, EmptyRunnable.getInstance(), CommonBundle.message("drop.undo.history.command.name"), null);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -47,7 +48,7 @@ public abstract class WebProjectGenerator<T> implements DirectoryProjectGenerato
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Nullable @NonNls
|
||||
public String getHelpId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.ui.wizard;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -48,7 +49,7 @@ public abstract class WizardStep<T extends WizardModel> {
|
||||
myIcon = icon;
|
||||
}
|
||||
|
||||
public WizardStep(String title, String explanation, Icon icon, String helpId) {
|
||||
public WizardStep(String title, String explanation, Icon icon, @NonNls String helpId) {
|
||||
myTitle = title;
|
||||
myExplanation = explanation;
|
||||
myIcon = icon;
|
||||
@@ -90,6 +91,7 @@ public abstract class WizardStep<T extends WizardModel> {
|
||||
return myIcon;
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String getHelpId() {
|
||||
return myHelpId;
|
||||
}
|
||||
|
||||
@@ -1578,4 +1578,7 @@ action.ToggleDistractionFreeMode.exit=Exit Distraction Free Mode
|
||||
action.TogglePresentationMode.exit=Exit Presentation Mode
|
||||
action.TogglePresentationMode.enter=Enter Presentation Mode
|
||||
|
||||
action.EmojiAndSymbols.description=Input special characters using macOS system palette
|
||||
action.EmojiAndSymbols.description=Input special characters using macOS system palette
|
||||
|
||||
action.MethodOverloadSwitchUp.text=Previous Method Overload
|
||||
action.MethodOverloadSwitchDown.text=Next Method Overload
|
||||
@@ -80,6 +80,9 @@
|
||||
<action id="EditorLookupUp"><keyboard-shortcut first-keystroke="control UP"/></action>
|
||||
<action id="EditorLookupDown"><keyboard-shortcut first-keystroke="control DOWN"/></action>
|
||||
|
||||
<action id="MethodOverloadSwitchUp"><keyboard-shortcut first-keystroke="control UP"/></action>
|
||||
<action id="MethodOverloadSwitchDown"><keyboard-shortcut first-keystroke="control DOWN"/></action>
|
||||
|
||||
<action id="ReformatCode">
|
||||
<keyboard-shortcut first-keystroke="control alt L"/>
|
||||
</action>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -94,7 +94,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
|
||||
{ "control 3", "GotoBookmark3", "FileChooser.GotoModule"},
|
||||
{ "control ADD", "ExpandAll", "ExpandRegion"},
|
||||
{ "control DIVIDE", "CommentByLineComment", "Images.Editor.ActualSize"},
|
||||
{ "control DOWN", "EditorScrollDown", "EditorLookupDown"},
|
||||
{ "control DOWN", "EditorScrollDown", "EditorLookupDown", "MethodOverloadSwitchDown"},
|
||||
{ "control ENTER", "EditorSplitLine", "ViewSource", "Console.Execute.Multiline"},
|
||||
{ "control EQUALS", "ExpandAll", "ExpandRegion"},
|
||||
{ "control F5", "Refresh", "Rerun"},
|
||||
@@ -106,7 +106,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
|
||||
{ "control R", "Replace", "Console.TableResult.Reload", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"},
|
||||
{ "control SLASH", "CommentByLineComment", "Images.Editor.ActualSize"},
|
||||
{ "control U", "GotoSuperMethod", "CommanderSwapPanels"},
|
||||
{ "control UP", "EditorScrollUp", "EditorLookupUp"},
|
||||
{ "control UP", "EditorScrollUp", "EditorLookupUp", "MethodOverloadSwitchUp"},
|
||||
{ "control alt A", "ChangesView.AddUnversioned", "Diagram.DeselectAll"},
|
||||
{ "control alt E", "PerforceDirect.Edit", "Console.History.Browse"},
|
||||
{ "control alt DOWN", "NextOccurence", "Console.TableResult.NextPage"},
|
||||
@@ -162,6 +162,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
|
||||
{ "meta 3", "ActivateFindToolWindow", "FileChooser.GotoModule"},
|
||||
{ "meta N", "FileChooser.NewFolder", "Generate", "NewElement"},
|
||||
{ "meta O", "GotoClass", "GotoChangedFile"},
|
||||
{ "meta UP", "ShowNavBar", "MethodOverloadSwitchUp"},
|
||||
{ "meta DOWN", "EditSource", "MethodOverloadSwitchDown"},
|
||||
{ "shift meta G", "ClassTemplateNavigation", "GoToClass", "FindPrevious"},
|
||||
{ "shift meta LEFT", "EditorLineStartWithSelection", "ResizeToolWindowLeft", },
|
||||
{ "shift meta RIGHT", "EditorLineEndWithSelection", "ResizeToolWindowRight", },
|
||||
@@ -211,8 +213,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase {
|
||||
{ "control X", "GotoFile", "SaveAll", "NextTab", "PreviousTab", "CloseContent", "CloseAllEditors", "NextSplitter",
|
||||
"GotoNextError", "NextProjectWindow", "EditorSwapSelectionBoundaries", "SplitVertically",
|
||||
"SplitHorizontally", "UnsplitAll", "Switcher", "$SelectAll"},
|
||||
{ "control UP", "EditorBackwardParagraph", "EditorLookupUp"},
|
||||
{ "control DOWN", "EditorForwardParagraph", "EditorLookupDown"},
|
||||
{ "control UP", "EditorBackwardParagraph", "EditorLookupUp", "MethodOverloadSwitchUp"},
|
||||
{ "control DOWN", "EditorForwardParagraph", "EditorLookupDown", "MethodOverloadSwitchDown"},
|
||||
{ "control alt A", "MethodUp", "ChangesView.AddUnversioned", "Diagram.DeselectAll"},
|
||||
{ "control alt E", "MethodDown", "PerforceDirect.Edit", "Console.History.Browse"},
|
||||
{ "control alt G", "GotoDeclaration", "org.jetbrains.plugins.ruby.rails.actions.generators.GeneratorsPopupAction", "Mvc.RunTarget"},
|
||||
|
||||
@@ -423,10 +423,10 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
|
||||
append(() -> ((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests()).
|
||||
append(() -> ((DocumentReferenceManagerImpl)DocumentReferenceManager.getInstance()).cleanupForNextTest()).
|
||||
append(() -> TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest()).
|
||||
append(() -> ((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest()).
|
||||
append(() -> ProjectManagerEx.getInstanceEx().closeTestProject(project)).
|
||||
append(() -> application.setDataProvider(null)).
|
||||
append(() -> ourTestCase = null).
|
||||
append(() -> ((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest()).
|
||||
append(() -> CompletionProgressIndicator.cleanupForNextTest()).
|
||||
append(() -> UIUtil.dispatchAllInvocationEvents()).
|
||||
append(() -> {
|
||||
|
||||
+2
@@ -542,6 +542,8 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
|
||||
|
||||
void testInlays();
|
||||
|
||||
void checkResultWithInlays(String text);
|
||||
|
||||
void assertPreferredCompletionItems(int selected, @NotNull String... expected);
|
||||
|
||||
/**
|
||||
|
||||
+10
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.daemon.GutterMark;
|
||||
import com.intellij.codeInsight.daemon.impl.*;
|
||||
import com.intellij.codeInsight.folding.CodeFoldingManager;
|
||||
import com.intellij.codeInsight.highlighting.actions.HighlightUsagesAction;
|
||||
import com.intellij.codeInsight.hints.InlayInfo;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.impl.IntentionListStep;
|
||||
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
|
||||
@@ -1705,6 +1706,15 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkResultWithInlays(String text) {
|
||||
Document checkDocument = new DocumentImpl(text);
|
||||
InlayHintsChecker checker = new InlayHintsChecker(this);
|
||||
List<InlayInfo> inlayInfos = checker.extractInlays(checkDocument);
|
||||
checkResult(checkDocument.getText());
|
||||
checker.verifyInlays(inlayInfos, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertPreferredCompletionItems(final int selected, @NotNull final String... expected) {
|
||||
final LookupImpl lookup = getLookup();
|
||||
|
||||
+10
-5
@@ -17,7 +17,6 @@ package com.intellij.testFramework.utils.inlays
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager
|
||||
import com.intellij.codeInsight.hints.InlayInfo
|
||||
import com.intellij.codeInsight.hints.InlayParameterHintsExtension
|
||||
import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.editor.Document
|
||||
@@ -57,10 +56,17 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
|
||||
val document = myFixture.getDocument(file)
|
||||
val originalText = document.text
|
||||
val expectedInlays: List<InlayInfo> = extractInlays(document)
|
||||
myFixture.doHighlighting();
|
||||
verifyInlays(expectedInlays, originalText)
|
||||
}
|
||||
|
||||
fun verifyInlays(expectedInlays : List<InlayInfo>, originalText: String) {
|
||||
val file = myFixture.file
|
||||
val document = myFixture.getDocument(file)
|
||||
val actual: List<Pair<Int, String>> = getActualInlays()
|
||||
|
||||
|
||||
val expected = expectedInlays.map { Pair(it.offset, it.text) }
|
||||
|
||||
|
||||
if (expectedInlays.size != actual.size || actual.zip(expected).any { it.first != it.second }) {
|
||||
val proposedText = StringBuilder(document.text)
|
||||
actual.asReversed().forEach { proposedText.insert(it.first, "<hint text=\"${it.second}\" />") }
|
||||
@@ -70,9 +76,8 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
|
||||
} ?: throw ComparisonFailure("Hints differ", originalText, proposedText.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getActualInlays(): List<Pair<Int, String>> {
|
||||
myFixture.doHighlighting()
|
||||
val editor = myFixture.editor
|
||||
val allInlays = editor.inlayModel.getInlineElementsInRange(0, editor.document.textLength)
|
||||
|
||||
|
||||
@@ -259,6 +259,7 @@ debugger.emulate.method.breakpoints.description=Emulate method breakpoints with
|
||||
debugger.intern.string.literals=false
|
||||
debugger.intern.string.literals.description=Make string literal refer to the same instance of class String
|
||||
debugger.capture.points=true
|
||||
debugger.capture.points.annotations=false
|
||||
|
||||
analyze.exceptions.on.the.fly=false
|
||||
analyze.exceptions.on.the.fly.description=Automatically analyze clipboard on frame activation,\
|
||||
@@ -369,6 +370,9 @@ show.live.templates.in.completion.description=Show live templates in completion
|
||||
java.completion.make.outer.variables.final=true
|
||||
java.completion.make.outer.variables.final.description=Make variables accessed from inner class final automatically
|
||||
|
||||
java.completion.argument.hints=false
|
||||
java.completion.argument.hints.description=When completing a method call, show hints in place of all arguments
|
||||
|
||||
java.completion.argument.live.template=false
|
||||
java.completion.argument.live.template.description=When completing a method call, start a live template with all arguments
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
public class Debugger {
|
||||
|
||||
/**
|
||||
* Advise IDEA Debugger to capture stack frames and use as a key:
|
||||
* <ul>
|
||||
* <li>{@code keyExpression} (if specified)</li>
|
||||
* <li>annotated parameter value</li>
|
||||
* <li>{@code this} value (if used on a method)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
|
||||
public @interface Capture {
|
||||
String keyExpression() default "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Advise IDEA Debugger to replace the stack frames with the captured information and use as a key:
|
||||
* <ul>
|
||||
* <li>{@code keyExpression} (if specified)</li>
|
||||
* <li>annotated parameter value</li>
|
||||
* <li>{@code this} value (if used on a method)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
|
||||
public @interface Insert {
|
||||
String keyExpression() default "";
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,12 @@
|
||||
*/
|
||||
package com.intellij.openapi.vcs.changes;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
*/
|
||||
public interface CommitExecutorWithHelp extends CommitExecutor {
|
||||
@NonNls
|
||||
String getHelpId();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes;
|
||||
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import org.jetbrains.annotations.CalledInAwt;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -69,6 +70,7 @@ public interface CommitSession {
|
||||
* @return the ID of the help topic to show for the dialog
|
||||
* @since 10.5
|
||||
*/
|
||||
@NonNls
|
||||
String getHelpId();
|
||||
|
||||
@CalledInAwt
|
||||
|
||||
@@ -110,7 +110,10 @@ public class JavaFxModuleUtil {
|
||||
}
|
||||
|
||||
private static ModificationTracker getModificationTracker(@NotNull Project project) {
|
||||
return project.getUserData(KEY);
|
||||
return () -> {
|
||||
final ModificationTracker tracker = project.getUserData(KEY);
|
||||
return tracker != null ? tracker.getModificationCount() + 1 : 0;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,24 +32,20 @@ import org.tmatesoft.svn.core.SVNException;
|
||||
public abstract class RepeatSvnActionThroughBusy {
|
||||
public static final int REPEAT = 10;
|
||||
|
||||
public static final Processor<Exception> ourBusyExceptionProcessor = new Processor<Exception>() {
|
||||
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
|
||||
@Override
|
||||
public boolean process(Exception e) {
|
||||
if (e instanceof SVNException) {
|
||||
final SVNErrorCode errorCode = ((SVNException)e).getErrorMessage().getErrorCode();
|
||||
if (SVNErrorCode.WC_LOCKED.equals(errorCode)) {
|
||||
return true;
|
||||
}
|
||||
else if (SVNErrorCode.SQLITE_ERROR.equals(errorCode)) {
|
||||
Throwable cause = ((SVNException)e).getErrorMessage().getCause();
|
||||
if (cause instanceof SqlJetException) {
|
||||
return SqlJetErrorCode.BUSY.equals(((SqlJetException)cause).getErrorCode());
|
||||
}
|
||||
public static final Processor<Exception> ourBusyExceptionProcessor = e -> {
|
||||
if (e instanceof SVNException) {
|
||||
final SVNErrorCode errorCode = ((SVNException)e).getErrorMessage().getErrorCode();
|
||||
if (SVNErrorCode.WC_LOCKED.equals(errorCode)) {
|
||||
return true;
|
||||
}
|
||||
else if (SVNErrorCode.SQLITE_ERROR.equals(errorCode)) {
|
||||
Throwable cause = ((SVNException)e).getErrorMessage().getCause();
|
||||
if (cause instanceof SqlJetException) {
|
||||
return SqlJetErrorCode.BUSY.equals(((SqlJetException)cause).getErrorCode());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
protected int myCnt = REPEAT;
|
||||
|
||||
@@ -57,14 +57,12 @@ public class RootsToWorkingCopies implements VcsListener {
|
||||
myRootMapping = new HashMap<>();
|
||||
myUnversioned = new HashSet<>();
|
||||
myVcs = vcs;
|
||||
myRechecker = new Runnable() {
|
||||
public void run() {
|
||||
final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(myVcs);
|
||||
synchronized (myLock) {
|
||||
clear();
|
||||
for (VirtualFile root : roots) {
|
||||
addRoot(root);
|
||||
}
|
||||
myRechecker = () -> {
|
||||
final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(myVcs);
|
||||
synchronized (myLock) {
|
||||
clear();
|
||||
for (VirtualFile root : roots) {
|
||||
addRoot(root);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.vcs.changes.FilePathsHelper;
|
||||
import com.intellij.util.TimeoutUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.sqljet.core.SqlJetException;
|
||||
import org.tmatesoft.sqljet.core.table.ISqlJetBusyHandler;
|
||||
import org.tmatesoft.sqljet.core.table.ISqlJetTransaction;
|
||||
import org.tmatesoft.sqljet.core.table.SqlJetDb;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 10/19/12
|
||||
* Time: 12:09 PM
|
||||
*/
|
||||
// TODO: Such locking functionality is not required anymore. Likely to be removed (together with SvnProxies).
|
||||
public abstract class SvnAbstractWriteOperationLocks {
|
||||
private final long myTimeout;
|
||||
private final static Map<String, Lock> myLockMap = new HashMap<>();
|
||||
private final static Object myLock = new Object();
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnAbstractWriteOperationLocks");
|
||||
private ISqlJetBusyHandler ourBusyHandler;
|
||||
private volatile boolean myDisposed;
|
||||
|
||||
protected SvnAbstractWriteOperationLocks(long timeout) {
|
||||
myTimeout = timeout;
|
||||
ourBusyHandler = new ISqlJetBusyHandler() {
|
||||
@Override
|
||||
public boolean call(int i) {
|
||||
if (myDisposed) return false;
|
||||
TimeoutUtil.sleep(myTimeout);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
myDisposed = true;
|
||||
}
|
||||
|
||||
// null if not 1.7+ copy
|
||||
@Nullable
|
||||
private Lock getLockObject(File file) throws SVNException {
|
||||
final boolean directory = file.isDirectory();
|
||||
final WorkingCopy wcRoot = getCopy(file, directory);
|
||||
if (! wcRoot.is17Copy()) return null;
|
||||
Lock lock;
|
||||
final String path = FilePathsHelper.convertPath(wcRoot.getFile().getPath());
|
||||
synchronized (myLock) {
|
||||
lock = myLockMap.get(path);
|
||||
if (lock == null) {
|
||||
lock = new ReentrantLock();
|
||||
myLockMap.put(path, lock);
|
||||
}
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
protected abstract WorkingCopy getCopy(File file, boolean directory) throws SVNException;
|
||||
|
||||
public void lockWrite(final File file) throws SVNException {
|
||||
final Lock lock = getLockObject(file);
|
||||
if (lock != null) {
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
public void unlockWrite(final File file) throws SVNException {
|
||||
final Lock lock = getLockObject(file);
|
||||
if (lock != null) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// would wait until read is available
|
||||
public void wrapRead(final File file, final Runnable runnable) throws SVNException {
|
||||
final WorkingCopy copy = getCopy(file, file.isDirectory());
|
||||
if (! copy.is17Copy()) {
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
|
||||
final File root = copy.getFile();
|
||||
SqlJetDb open = null;
|
||||
final boolean run[] = new boolean[1];
|
||||
run[0] = false;
|
||||
try {
|
||||
open = SqlJetDb.open(SvnUtil.getWcDb(root), false);
|
||||
open.setBusyHandler(ourBusyHandler);
|
||||
try {
|
||||
final SqlJetDb finalOpen = open;
|
||||
open.runReadTransaction(new ISqlJetTransaction() {
|
||||
@Override
|
||||
public Object run(SqlJetDb db) throws SqlJetException {
|
||||
run[0] = true;
|
||||
runnable.run();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
open.rollback();
|
||||
}
|
||||
}
|
||||
catch (SqlJetException e) {
|
||||
LOG.info(e);
|
||||
if (! run[0]) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (open != null) {
|
||||
try {
|
||||
open.close();
|
||||
}
|
||||
catch (SqlJetException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,13 +59,7 @@ public class SvnChangeProvider implements ChangeProvider {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnChangeProvider");
|
||||
public static final String PROPERTY_LAYER = "Property";
|
||||
|
||||
private static final NotNullFactory<Map<String, File>> NAME_TO_FILE_MAP_FACTORY = new NotNullFactory<Map<String, File>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<String, File> create() {
|
||||
return ContainerUtil.newHashMap();
|
||||
}
|
||||
};
|
||||
private static final NotNullFactory<Map<String, File>> NAME_TO_FILE_MAP_FACTORY = () -> ContainerUtil.newHashMap();
|
||||
|
||||
@NotNull private final SvnVcs myVcs;
|
||||
@NotNull private final VcsContextFactory myFactory;
|
||||
@@ -176,12 +170,7 @@ public class SvnChangeProvider implements ChangeProvider {
|
||||
}
|
||||
}
|
||||
|
||||
return new ISVNStatusFileProvider() {
|
||||
@Override
|
||||
public Map<String, File> getChildrenFiles(File parent) {
|
||||
return result.get(parent.getAbsolutePath());
|
||||
}
|
||||
};
|
||||
return parent -> result.get(parent.getAbsolutePath());
|
||||
}
|
||||
|
||||
private void processCopiedAndDeleted(@NotNull SvnChangeProviderContext context, @Nullable VcsDirtyScope dirtyScope) throws SVNException {
|
||||
@@ -285,12 +274,10 @@ public class SvnChangeProvider implements ChangeProvider {
|
||||
final Change change = context
|
||||
.createMovedChange(createBeforeRevision(deletedFile, true), CurrentContentRevision.create(oldPath), copiedStatus,
|
||||
deletedFile.getStatus());
|
||||
final boolean isUnder = dirtyScope == null ? true : ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return ChangeListManagerImpl.isUnder(change, dirtyScope);
|
||||
}
|
||||
});
|
||||
final boolean isUnder = dirtyScope == null
|
||||
? true
|
||||
: ApplicationManager.getApplication()
|
||||
.runReadAction((Computable<Boolean>)() -> ChangeListManagerImpl.isUnder(change, dirtyScope));
|
||||
if (isUnder) {
|
||||
context.getBuilder().removeRegisteredChangeFor(oldPath);
|
||||
context.getBuilder().processChangeInList(change, clName, SvnVcs.getKey());
|
||||
|
||||
@@ -44,12 +44,9 @@ public class SvnChangelistListener implements ChangeListListener {
|
||||
|
||||
public SvnChangelistListener(@NotNull SvnVcs vcs) {
|
||||
myVcs = vcs;
|
||||
myUnderSvnCondition = new Condition<FilePath>() {
|
||||
@Override
|
||||
public boolean value(@NotNull FilePath path) {
|
||||
final AbstractVcs vcs = ProjectLevelVcsManager.getInstance(myVcs.getProject()).getVcsFor(path);
|
||||
return vcs != null && SvnVcs.VCS_NAME.equals(vcs.getName());
|
||||
}
|
||||
myUnderSvnCondition = path -> {
|
||||
final AbstractVcs vcs1 = ProjectLevelVcsManager.getInstance(myVcs.getProject()).getVcsFor(path);
|
||||
return vcs1 != null && SvnVcs.VCS_NAME.equals(vcs1.getName());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
@@ -55,30 +54,21 @@ public class SvnCompatibilityChecker {
|
||||
myCounter = 0;
|
||||
++ myInvocationCounter;
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
application.executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
final List<VirtualFile> suspicious = new ArrayList<>();
|
||||
for (VirtualFile vf : result) {
|
||||
if (SvnUtil.seemsLikeVersionedDir(vf)) {
|
||||
suspicious.add(vf);
|
||||
}
|
||||
}
|
||||
if (! suspicious.isEmpty()) {
|
||||
final String message = (suspicious.size() == 1) ?
|
||||
"Root '" + suspicious.get(0).getPresentableName() + "' is likely to be of unsupported Subversion format" :
|
||||
"Some roots are likely to be of unsupported Subversion format";
|
||||
application.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new VcsBalloonProblemNotifier(myProject, message, MessageType.WARNING).run();
|
||||
}
|
||||
}, ModalityState.NON_MODAL, new Condition() {
|
||||
@Override
|
||||
public boolean value(Object o) {
|
||||
return (! myProject.isOpen()) || myProject.isDisposed();
|
||||
}
|
||||
});
|
||||
application.executeOnPooledThread(() -> {
|
||||
final List<VirtualFile> suspicious = new ArrayList<>();
|
||||
for (VirtualFile vf : result) {
|
||||
if (SvnUtil.seemsLikeVersionedDir(vf)) {
|
||||
suspicious.add(vf);
|
||||
}
|
||||
}
|
||||
if (!suspicious.isEmpty()) {
|
||||
final String message = (suspicious.size() == 1)
|
||||
? "Root '" + suspicious.get(0).getPresentableName() + "' is likely to be of unsupported Subversion format"
|
||||
: "Some roots are likely to be of unsupported Subversion format";
|
||||
application
|
||||
.invokeLater(() -> new VcsBalloonProblemNotifier(myProject, message, MessageType.WARNING).run(), ModalityState.NON_MODAL,
|
||||
o -> (!myProject.isOpen()) || myProject.isDisposed());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import com.intellij.ui.MultiLineTooltipUI;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.ui.components.JBRadioButton;
|
||||
import com.intellij.ui.components.labels.LinkLabel;
|
||||
import com.intellij.ui.components.labels.LinkListener;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.net.HttpProxyConfigurable;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -51,10 +50,6 @@ import org.jetbrains.idea.svn.svnkit.SvnKitManager;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.io.File;
|
||||
|
||||
public class SvnConfigurable implements Configurable {
|
||||
@@ -96,79 +91,52 @@ public class SvnConfigurable implements Configurable {
|
||||
public SvnConfigurable(Project project) {
|
||||
myProject = project;
|
||||
|
||||
myWithCommandLineClient.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
enableCommandLineClientOptions();
|
||||
}
|
||||
});
|
||||
myWithCommandLineClient.addItemListener(e -> enableCommandLineClientOptions());
|
||||
enableCommandLineClientOptions();
|
||||
myUseDefaultCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
boolean enabled = !myUseDefaultCheckBox.isSelected();
|
||||
myConfigurationDirectoryText.setEnabled(enabled);
|
||||
myConfigurationDirectoryText.setEditable(enabled);
|
||||
myConfigurationDirectoryLabel.setEnabled(enabled);
|
||||
SvnConfiguration configuration = SvnConfiguration.getInstance(myProject);
|
||||
String path = configuration.getConfigurationDirectory();
|
||||
if (!enabled || path == null) {
|
||||
myConfigurationDirectoryText.setText(IdeaSubversionConfigurationDirectory.getPath());
|
||||
}
|
||||
else {
|
||||
myConfigurationDirectoryText.setText(path);
|
||||
}
|
||||
myUseDefaultCheckBox.addActionListener(e -> {
|
||||
boolean enabled = !myUseDefaultCheckBox.isSelected();
|
||||
myConfigurationDirectoryText.setEnabled(enabled);
|
||||
myConfigurationDirectoryText.setEditable(enabled);
|
||||
myConfigurationDirectoryLabel.setEnabled(enabled);
|
||||
SvnConfiguration configuration = SvnConfiguration.getInstance(myProject);
|
||||
String path = configuration.getConfigurationDirectory();
|
||||
if (!enabled || path == null) {
|
||||
myConfigurationDirectoryText.setText(IdeaSubversionConfigurationDirectory.getPath());
|
||||
}
|
||||
else {
|
||||
myConfigurationDirectoryText.setText(path);
|
||||
}
|
||||
});
|
||||
myCommandLineClient.addBrowseFolderListener("Subversion", "Select path to Subversion executable (1.7+)", project,
|
||||
FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
|
||||
|
||||
myClearAuthButton.addActionListener(new ActionListener(){
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
SvnAuthenticationNotifier.clearAuthenticationCache(myProject, myComponent, myConfigurationDirectoryText.getText());
|
||||
}
|
||||
});
|
||||
myClearAuthButton.addActionListener(
|
||||
e -> SvnAuthenticationNotifier.clearAuthenticationCache(myProject, myComponent, myConfigurationDirectoryText.getText()));
|
||||
|
||||
|
||||
|
||||
myConfigurationDirectoryText.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@NonNls String path = myConfigurationDirectoryText.getText().trim();
|
||||
selectConfigurationDirectory(path, new Consumer<String>() {
|
||||
@Override
|
||||
public void consume(String s) {
|
||||
myConfigurationDirectoryText.setText(s);
|
||||
}
|
||||
}, myProject, myComponent);
|
||||
}
|
||||
myConfigurationDirectoryText.addActionListener(e -> {
|
||||
@NonNls String path = myConfigurationDirectoryText.getText().trim();
|
||||
selectConfigurationDirectory(path, s -> myConfigurationDirectoryText.setText(s), myProject, myComponent);
|
||||
});
|
||||
|
||||
myConfigurationDirectoryLabel.setLabelFor(myConfigurationDirectoryText);
|
||||
|
||||
myUseCommonProxy.setText(SvnBundle.message("use.idea.proxy.as.default", ApplicationNamesInfo.getInstance().getProductName()));
|
||||
myNavigateToCommonProxyLink.setListener(new LinkListener<Object>() {
|
||||
@Override
|
||||
public void linkSelected(LinkLabel aSource, Object aLinkData) {
|
||||
Settings settings = Settings.KEY.getData(DataManager.getInstance().getDataContext(myComponent));
|
||||
myNavigateToCommonProxyLink.setListener((aSource, aLinkData) -> {
|
||||
Settings settings = Settings.KEY.getData(DataManager.getInstance().getDataContext(myComponent));
|
||||
|
||||
if (settings != null) {
|
||||
settings.select(settings.find(HttpProxyConfigurable.class));
|
||||
}
|
||||
if (settings != null) {
|
||||
settings.select(settings.find(HttpProxyConfigurable.class));
|
||||
}
|
||||
}, null);
|
||||
myEditProxiesButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final SvnConfigureProxiesDialog dialog = new SvnConfigureProxiesDialog(myProject);
|
||||
dialog.show();
|
||||
myHttpTimeout.setValue(Long.valueOf(SvnConfiguration.getInstance(myProject).getHttpTimeout() / 1000));
|
||||
}
|
||||
myEditProxiesButton.addActionListener(e -> {
|
||||
final SvnConfigureProxiesDialog dialog = new SvnConfigureProxiesDialog(myProject);
|
||||
dialog.show();
|
||||
myHttpTimeout.setValue(Long.valueOf(SvnConfiguration.getInstance(myProject).getHttpTimeout() / 1000));
|
||||
});
|
||||
|
||||
myMaximumNumberOfRevisionsCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected());
|
||||
}
|
||||
});
|
||||
myMaximumNumberOfRevisionsCheckBox
|
||||
.addActionListener(e -> myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected()));
|
||||
myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected());
|
||||
|
||||
final ButtonGroup bg = new ButtonGroup();
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
@@ -374,12 +373,7 @@ public class SvnConfiguration implements PersistentStateComponent<SvnConfigurati
|
||||
if (myAuthManager == null) {
|
||||
// reloaded when configuration directory changes
|
||||
myAuthManager = new SvnAuthenticationManager(svnVcs, new File(getConfigurationDirectory()));
|
||||
Disposer.register(svnVcs.getProject(), new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
myAuthManager = null;
|
||||
}
|
||||
});
|
||||
Disposer.register(svnVcs.getProject(), () -> myAuthManager = null);
|
||||
getInteractiveManager(svnVcs);
|
||||
// to init
|
||||
myAuthManager.setAuthenticationProvider(new SvnAuthenticationProvider(svnVcs, myInteractiveProvider, myAuthManager));
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.RequestsMerger;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
|
||||
public class SvnCopiesRefreshManager {
|
||||
@@ -28,24 +27,12 @@ public class SvnCopiesRefreshManager {
|
||||
public SvnCopiesRefreshManager(final SvnFileUrlMappingImpl mapping) {
|
||||
mySemaphore = new Semaphore();
|
||||
// svn mappings refresh inside also uses asynchronous pass -> we need to pass callback that will ping our "single-threaded" executor here
|
||||
myMappingCallback = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mySemaphore.up();
|
||||
}
|
||||
};
|
||||
myRequestsMerger = new RequestsMerger(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mySemaphore.down();
|
||||
mapping.realRefresh(myMappingCallback);
|
||||
mySemaphore.waitFor();
|
||||
}
|
||||
}, new Consumer<Runnable>() {
|
||||
public void consume(final Runnable runnable) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(runnable);
|
||||
}
|
||||
});
|
||||
myMappingCallback = () -> mySemaphore.up();
|
||||
myRequestsMerger = new RequestsMerger(() -> {
|
||||
mySemaphore.down();
|
||||
mapping.realRefresh(myMappingCallback);
|
||||
mySemaphore.waitFor();
|
||||
}, runnable -> ApplicationManager.getApplication().executeOnPooledThread(runnable));
|
||||
}
|
||||
|
||||
public void asynchRequest() {
|
||||
|
||||
@@ -40,7 +40,6 @@ import org.jetbrains.idea.svn.info.InfoConsumer;
|
||||
import org.jetbrains.idea.svn.properties.PropertyValue;
|
||||
import org.jetbrains.idea.svn.status.Status;
|
||||
import org.jetbrains.idea.svn.status.StatusType;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc2.SvnTarget;
|
||||
|
||||
@@ -118,18 +117,15 @@ public class SvnDiffProvider extends DiffProviderEx implements DiffProvider, Dif
|
||||
@NotNull
|
||||
private static InfoConsumer createInfoHandler(@NotNull final Map<VirtualFile, VcsRevisionNumber> revisionMap,
|
||||
@NotNull final Map<String, VirtualFile> fileMap) {
|
||||
return new InfoConsumer() {
|
||||
@Override
|
||||
public void consume(Info info) throws SVNException {
|
||||
if (info != null) {
|
||||
VirtualFile file = fileMap.get(info.getFile().getAbsolutePath());
|
||||
return info -> {
|
||||
if (info != null) {
|
||||
VirtualFile file = fileMap.get(info.getFile().getAbsolutePath());
|
||||
|
||||
if (file != null) {
|
||||
revisionMap.put(file, getRevision(info));
|
||||
}
|
||||
else {
|
||||
LOG.info("Could not find virtual file for path " + info.getFile().getAbsolutePath());
|
||||
}
|
||||
if (file != null) {
|
||||
revisionMap.put(file, getRevision(info));
|
||||
}
|
||||
else {
|
||||
LOG.info("Could not find virtual file for path " + info.getFile().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -40,7 +40,6 @@ import com.intellij.openapi.vfs.LocalFileOperationsHandler;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.ThrowableConsumer;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
@@ -359,22 +358,19 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
private static void copyUnversionedMembersOfDirectory(final File src, final File dst) throws SvnBindException {
|
||||
if (src.isDirectory()) {
|
||||
final SvnBindException[] exc = new SvnBindException[1];
|
||||
FileUtil.processFilesRecursively(src, new Processor<File>() {
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
String relativePath = FileUtil.getRelativePath(src, file);
|
||||
File newFile = new File(dst, relativePath);
|
||||
if (!newFile.exists()) {
|
||||
try {
|
||||
FileUtil.copyFileOrDir(src, dst);
|
||||
}
|
||||
catch (IOException e) {
|
||||
exc[0] = new SvnBindException(e);
|
||||
return false;
|
||||
}
|
||||
FileUtil.processFilesRecursively(src, file -> {
|
||||
String relativePath = FileUtil.getRelativePath(src, file);
|
||||
File newFile = new File(dst, relativePath);
|
||||
if (!newFile.exists()) {
|
||||
try {
|
||||
FileUtil.copyFileOrDir(src, dst);
|
||||
}
|
||||
catch (IOException e) {
|
||||
exc[0] = new SvnBindException(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (exc[0] != null) {
|
||||
throw exc[0];
|
||||
@@ -709,15 +705,13 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
// if refresh asynchronously, local changes would also be notified that they are dirty asynchronously,
|
||||
// and commit could be executed while not all changes are visible
|
||||
filterOutInvalid(myFilesToRefresh);
|
||||
RefreshQueue.getInstance().refresh(true, true, new Runnable() {
|
||||
public void run() {
|
||||
if (project.isDisposed()) return;
|
||||
filterOutInvalid(toRefreshFiles);
|
||||
filterOutInvalid(toRefreshDirs);
|
||||
RefreshQueue.getInstance().refresh(true, true, () -> {
|
||||
if (project.isDisposed()) return;
|
||||
filterOutInvalid(toRefreshFiles);
|
||||
filterOutInvalid(toRefreshDirs);
|
||||
|
||||
final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
|
||||
vcsDirtyScopeManager.filesDirty(toRefreshFiles, toRefreshDirs);
|
||||
}
|
||||
final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
|
||||
vcsDirtyScopeManager.filesDirty(toRefreshFiles, toRefreshDirs);
|
||||
}, myFilesToRefresh);
|
||||
myFilesToRefresh.clear();
|
||||
}
|
||||
@@ -748,18 +742,15 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
// Current method could be invoked under write action (for instance, during project import). So we explicitly use
|
||||
// Application.invokeLater() in such cases to prevent deadlocks (while accessing vcs root mappings) and also not to show dialog under
|
||||
// write action.
|
||||
runNotUnderWriteAction(project, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
|
||||
final Collection<VirtualFile> filesToProcess = promptAboutAddition(vcs, addedVFiles, value, vcsHelper);
|
||||
if (filesToProcess != null && !filesToProcess.isEmpty()) {
|
||||
final List<VcsException> exceptions = new ArrayList<>();
|
||||
runInBackground(project, "Adding files to Subversion",
|
||||
createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions));
|
||||
if (!exceptions.isEmpty()) {
|
||||
vcsHelper.showErrors(exceptions, SvnBundle.message("add.files.errors.title"));
|
||||
}
|
||||
runNotUnderWriteAction(project, () -> {
|
||||
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
|
||||
final Collection<VirtualFile> filesToProcess = promptAboutAddition(vcs, addedVFiles, value, vcsHelper);
|
||||
if (filesToProcess != null && !filesToProcess.isEmpty()) {
|
||||
final List<VcsException> exceptions = new ArrayList<>();
|
||||
runInBackground(project, "Adding files to Subversion",
|
||||
createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions));
|
||||
if (!exceptions.isEmpty()) {
|
||||
vcsHelper.showErrors(exceptions, SvnBundle.message("add.files.errors.title"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -789,44 +780,41 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
final Map<VirtualFile, File> copyFromMap,
|
||||
final Collection<VirtualFile> filesToProcess,
|
||||
final List<VcsException> exceptions) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for(VirtualFile file: filesToProcess) {
|
||||
final File ioFile = new File(file.getPath());
|
||||
try {
|
||||
final File copyFrom = copyFromMap.get(file);
|
||||
if (copyFrom != null) {
|
||||
try {
|
||||
new ActionWithTempFile(ioFile) {
|
||||
protected void executeInternal() throws VcsException {
|
||||
// not recursive
|
||||
new RepeatSvnActionThroughBusy() {
|
||||
@Override
|
||||
protected void executeImpl() throws VcsException {
|
||||
vcs.getFactory(copyFrom).createCopyMoveClient().copy(copyFrom, ioFile, true, false);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
new RepeatSvnActionThroughBusy() {
|
||||
@Override
|
||||
protected void executeImpl() throws VcsException {
|
||||
vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null);
|
||||
return () -> {
|
||||
for (VirtualFile file : filesToProcess) {
|
||||
final File ioFile = new File(file.getPath());
|
||||
try {
|
||||
final File copyFrom = copyFromMap.get(file);
|
||||
if (copyFrom != null) {
|
||||
try {
|
||||
new ActionWithTempFile(ioFile) {
|
||||
protected void executeInternal() throws VcsException {
|
||||
// not recursive
|
||||
new RepeatSvnActionThroughBusy() {
|
||||
@Override
|
||||
protected void executeImpl() throws VcsException {
|
||||
vcs.getFactory(copyFrom).createCopyMoveClient().copy(copyFrom, ioFile, true, false);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
|
||||
catch (VcsException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exceptions.add(e);
|
||||
else {
|
||||
new RepeatSvnActionThroughBusy() {
|
||||
@Override
|
||||
protected void executeImpl() throws VcsException {
|
||||
vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -907,12 +895,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
if (!filesToProcess.isEmpty()) {
|
||||
runInBackground(project, "Deleting files from Subversion", createDeleteRunnable(project, vcs, filesToProcess, exceptions));
|
||||
}
|
||||
final List<FilePath> deletedFilesFiles = ObjectsConvertor.convert(deletedFiles, new Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath>() {
|
||||
@Override
|
||||
public FilePath convert(Pair<FilePath, WorkingCopyFormat> o) {
|
||||
return o.getFirst();
|
||||
}
|
||||
});
|
||||
final List<FilePath> deletedFilesFiles = ObjectsConvertor.convert(deletedFiles, o -> o.getFirst());
|
||||
for (FilePath file : deletedFilesFiles) {
|
||||
final FilePath parent = file.getParentPath();
|
||||
if (parent != null) {
|
||||
@@ -936,25 +919,23 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
final SvnVcs vcs,
|
||||
final Collection<FilePath> filesToProcess,
|
||||
final List<VcsException> exceptions) {
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
for(FilePath file: filesToProcess) {
|
||||
VirtualFile vFile = file.getVirtualFile(); // for deleted directories
|
||||
final File ioFile = new File(file.getPath());
|
||||
try {
|
||||
createDeleteAction(vcs, ioFile, true).execute();
|
||||
if (vFile != null && vFile.isValid() && vFile.isDirectory()) {
|
||||
vFile.refresh(true, true);
|
||||
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(vFile);
|
||||
}
|
||||
else {
|
||||
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
|
||||
}
|
||||
return () -> {
|
||||
for (FilePath file : filesToProcess) {
|
||||
VirtualFile vFile = file.getVirtualFile(); // for deleted directories
|
||||
final File ioFile = new File(file.getPath());
|
||||
try {
|
||||
createDeleteAction(vcs, ioFile, true).execute();
|
||||
if (vFile != null && vFile.isValid() && vFile.isDirectory()) {
|
||||
vFile.refresh(true, true);
|
||||
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(vFile);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exceptions.add(e);
|
||||
else {
|
||||
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -963,13 +944,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
SvnVcs vcs,
|
||||
VcsShowConfirmationOption.Value value,
|
||||
AbstractVcsHelper vcsHelper) {
|
||||
final Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath> convertor =
|
||||
new Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath>() {
|
||||
@Override
|
||||
public FilePath convert(Pair<FilePath, WorkingCopyFormat> o) {
|
||||
return o.getFirst();
|
||||
}
|
||||
};
|
||||
final Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath> convertor = o -> o.getFirst();
|
||||
Collection<FilePath> filesToProcess;
|
||||
if (value == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) {
|
||||
filesToProcess = ObjectsConvertor.convert(deletedFiles, convertor);
|
||||
@@ -1016,14 +991,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
|
||||
private void processMovedFiles(final Project project) {
|
||||
if (myMovedFiles.isEmpty()) return;
|
||||
|
||||
final Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
for (Iterator<MovedFileInfo> iterator = myMovedFiles.iterator(); iterator.hasNext();) {
|
||||
MovedFileInfo movedFileInfo = iterator.next();
|
||||
if (movedFileInfo.myProject == project) {
|
||||
doMove(SvnVcs.getInstance(project), movedFileInfo.mySrc, movedFileInfo.myDst);
|
||||
iterator.remove();
|
||||
}
|
||||
final Runnable runnable = () -> {
|
||||
for (Iterator<MovedFileInfo> iterator = myMovedFiles.iterator(); iterator.hasNext(); ) {
|
||||
MovedFileInfo movedFileInfo = iterator.next();
|
||||
if (movedFileInfo.myProject == project) {
|
||||
doMove(SvnVcs.getInstance(project), movedFileInfo.mySrc, movedFileInfo.myDst);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -165,18 +165,16 @@ public class SvnNativeCallsTranslator {
|
||||
}
|
||||
|
||||
static {
|
||||
ourAdvices.put(-25293, new Convertor<NativeLogReader.CallInfo, String>() {
|
||||
@Override
|
||||
public String convert(NativeLogReader.CallInfo callInfo) {
|
||||
if (! SystemInfo.isMac) return null;
|
||||
final Trinity<String, String, String> trinity = MacParser.macMessages.get(callInfo.getResultCode());
|
||||
if (trinity == null) return null;
|
||||
return MessageFormat.format(ourGenericAdvice, callInfo.getFunctionName(),
|
||||
new StringBuilder().append(callInfo.getResultCode()).append(" ( ").append(trinity.getFirst())
|
||||
.append(" - ").append(trinity.getSecond()).append(")").append("\nYou are likely to have modified ")
|
||||
.append(ApplicationInfo.getInstance().getVersionName()).append(" bundle.\n")
|
||||
.append("Please try to reinstall ").append(ApplicationInfo.getInstance().getVersionName()).toString());
|
||||
}
|
||||
ourAdvices.put(-25293, callInfo -> {
|
||||
if (!SystemInfo.isMac) return null;
|
||||
final Trinity<String, String, String> trinity = MacParser.macMessages.get(callInfo.getResultCode());
|
||||
if (trinity == null) return null;
|
||||
return MessageFormat.format(ourGenericAdvice, callInfo.getFunctionName(),
|
||||
new StringBuilder().append(callInfo.getResultCode()).append(" ( ").append(trinity.getFirst())
|
||||
.append(" - ").append(trinity.getSecond()).append(")").append("\nYou are likely to have modified ")
|
||||
.append(ApplicationInfo.getInstance().getVersionName()).append(" bundle.\n")
|
||||
.append("Please try to reinstall ").append(ApplicationInfo.getInstance().getVersionName())
|
||||
.toString());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -20,17 +20,14 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -45,13 +42,17 @@ import org.jetbrains.idea.svn.status.StatusType;
|
||||
import org.tmatesoft.svn.core.SVNCancelException;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
|
||||
import org.tmatesoft.svn.core.wc.ISVNStatusFileProvider;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static com.intellij.openapi.vfs.VfsUtilCore.visitChildrenRecursively;
|
||||
import static com.intellij.openapi.vfs.VirtualFileVisitor.ONE_LEVEL_DEEP;
|
||||
import static com.intellij.openapi.vfs.VirtualFileVisitor.SKIP_ROOT;
|
||||
import static com.intellij.util.containers.ContainerUtil.ar;
|
||||
|
||||
public class SvnRecursiveStatusWalker {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnRecursiveStatusWalker");
|
||||
|
||||
@@ -129,12 +130,9 @@ public class SvnRecursiveStatusWalker {
|
||||
}
|
||||
|
||||
public boolean isIgnoredByVcs(@NotNull final VirtualFile vFile) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
if (myVcs.getProject().isDisposed()) throw new ProcessCanceledException();
|
||||
return myVcsManager.isIgnored(vFile);
|
||||
}
|
||||
return ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> {
|
||||
if (myVcs.getProject().isDisposed()) throw new ProcessCanceledException();
|
||||
return myVcsManager.isIgnored(vFile);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -198,57 +196,28 @@ public class SvnRecursiveStatusWalker {
|
||||
myReceiver.processIgnored(vFile);
|
||||
return;
|
||||
}
|
||||
final Depth newDepth = Depth.INFINITY.equals(prevDepth) ? Depth.INFINITY : Depth.EMPTY;
|
||||
|
||||
final File ioFile = new File(vFile.getPath());
|
||||
final Processor<File> processor;
|
||||
final Processor<File> directoryFilter;
|
||||
final Ref<File> lastIgnored = new Ref<>();
|
||||
final Processor<File> checkDirProcessor = new Processor<File>() {
|
||||
Depth newDepth = Depth.INFINITY.equals(prevDepth) ? Depth.INFINITY : Depth.EMPTY;
|
||||
VirtualFileVisitor.Option[] options = newDepth.equals(Depth.EMPTY) ? ar(SKIP_ROOT, ONE_LEVEL_DEEP) : new VirtualFileVisitor.Option[0];
|
||||
|
||||
visitChildrenRecursively(vFile, new VirtualFileVisitor(options) {
|
||||
@NotNull
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
FilePath path = VcsUtil.getFilePath(file, true);
|
||||
VirtualFile vf = VfsUtil.findFileByIoFile(file, true);
|
||||
if (vf != null && isIgnoredIdeaLevel(vf)) {
|
||||
lastIgnored.set(file);
|
||||
myReceiver.processIgnored(vf);
|
||||
public Result visitFileEx(@NotNull VirtualFile file) {
|
||||
if (isIgnoredIdeaLevel(file)) {
|
||||
myReceiver.processIgnored(file);
|
||||
return SKIP_CHILDREN;
|
||||
}
|
||||
else if (file.isDirectory() && new File(file, SVNFileUtil.getAdminDirectoryName()).exists()) {
|
||||
myQueue.add(createItem(path, newDepth, true));
|
||||
else if (file.isDirectory() && file.findChild(SvnUtil.SVN_ADMIN_DIR_NAME) != null) {
|
||||
myQueue.add(createItem(VcsUtil.getFilePath(file), newDepth, true));
|
||||
return SKIP_CHILDREN;
|
||||
}
|
||||
else if (vf != null) {
|
||||
myReceiver.processUnversioned(vf);
|
||||
else {
|
||||
myReceiver.processUnversioned(file);
|
||||
return CONTINUE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (Depth.EMPTY.equals(newDepth)) {
|
||||
// just process immediate children - so only root directory itself should satisfy filter
|
||||
directoryFilter = new Processor<File>() {
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
return FileUtil.filesEqual(ioFile, file);
|
||||
}
|
||||
};
|
||||
processor = new Processor<File>() {
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
// TODO: check if we should still call checkDirProcessor() here - or we really could not check ignore settings but just call
|
||||
// TODO: myReceiver.processUnversioned() for all immediate children
|
||||
// here we deal only with immediate children - so ignored on IDEA level for children is not important
|
||||
return FileUtil.filesEqual(ioFile, file) || checkDirProcessor.process(file);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
directoryFilter = new Processor<File>() {
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
return ! Comparing.equal(lastIgnored, file) && (myQueue.isEmpty() || ! FileUtil.filesEqual(myQueue.getLast().getPath().getIOFile(), file));
|
||||
}
|
||||
};
|
||||
processor = checkDirProcessor;
|
||||
}
|
||||
FileUtil.processFilesRecursively(ioFile, processor, directoryFilter);
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -16,17 +16,13 @@
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.status.Status;
|
||||
@@ -94,11 +90,7 @@ public class SvnRootsDetector {
|
||||
}
|
||||
|
||||
private void addNestedRoots(final boolean clearState, final Runnable callback) {
|
||||
final List<VirtualFile> basicVfRoots = ObjectsConvertor.convert(myResult.myTopRoots, new Convertor<RootUrlInfo, VirtualFile>() {
|
||||
public VirtualFile convert(final RootUrlInfo real) {
|
||||
return real.getVirtualFile();
|
||||
}
|
||||
});
|
||||
final List<VirtualFile> basicVfRoots = ObjectsConvertor.convert(myResult.myTopRoots, real -> real.getVirtualFile());
|
||||
|
||||
final ChangeListManager clManager = ChangeListManager.getInstance(myVcs.getProject());
|
||||
|
||||
@@ -106,38 +98,34 @@ public class SvnRootsDetector {
|
||||
// clear what was reported before (could be for currently-not-existing roots)
|
||||
myNestedCopiesHolder.getAndClear();
|
||||
}
|
||||
clManager.invokeAfterUpdate(new Runnable() {
|
||||
public void run() {
|
||||
final List<RootUrlInfo> nestedRoots = new ArrayList<>();
|
||||
clManager.invokeAfterUpdate(() -> {
|
||||
final List<RootUrlInfo> nestedRoots = new ArrayList<>();
|
||||
|
||||
for (NestedCopyInfo info : myNestedCopiesHolder.getAndClear()) {
|
||||
if (NestedCopyType.external.equals(info.getType()) || NestedCopyType.switched.equals(info.getType())) {
|
||||
RootUrlInfo topRoot = findTopRoot(VfsUtilCore.virtualToIoFile(info.getFile()));
|
||||
for (NestedCopyInfo info : myNestedCopiesHolder.getAndClear()) {
|
||||
if (NestedCopyType.external.equals(info.getType()) || NestedCopyType.switched.equals(info.getType())) {
|
||||
RootUrlInfo topRoot = findTopRoot(VfsUtilCore.virtualToIoFile(info.getFile()));
|
||||
|
||||
if (topRoot != null) {
|
||||
// TODO: Seems that type is not set in ForNestedRootChecker as we could not determine it for sure. Probably, for the case
|
||||
// TODO: (or some other cases) when vcs root from settings belongs is in externals of some other working copy upper
|
||||
// TODO: the tree (I did not check this). Leave this setter for now.
|
||||
topRoot.setType(info.getType());
|
||||
continue;
|
||||
}
|
||||
if (!refreshPointInfo(info)) {
|
||||
continue;
|
||||
}
|
||||
if (topRoot != null) {
|
||||
// TODO: Seems that type is not set in ForNestedRootChecker as we could not determine it for sure. Probably, for the case
|
||||
// TODO: (or some other cases) when vcs root from settings belongs is in externals of some other working copy upper
|
||||
// TODO: the tree (I did not check this). Leave this setter for now.
|
||||
topRoot.setType(info.getType());
|
||||
continue;
|
||||
}
|
||||
if (!refreshPointInfo(info)) {
|
||||
continue;
|
||||
}
|
||||
registerRootUrlFromNestedPoint(info, nestedRoots);
|
||||
}
|
||||
|
||||
myResult.myTopRoots.addAll(nestedRoots);
|
||||
myMapping.applyDetectionResult(myResult);
|
||||
|
||||
callback.run();
|
||||
registerRootUrlFromNestedPoint(info, nestedRoots);
|
||||
}
|
||||
}, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, null, new Consumer<VcsDirtyScopeManager>() {
|
||||
public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) {
|
||||
if (clearState) {
|
||||
vcsDirtyScopeManager.filesDirty(null, basicVfRoots);
|
||||
}
|
||||
|
||||
myResult.myTopRoots.addAll(nestedRoots);
|
||||
myMapping.applyDetectionResult(myResult);
|
||||
|
||||
callback.run();
|
||||
}, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, null, vcsDirtyScopeManager -> {
|
||||
if (clearState) {
|
||||
vcsDirtyScopeManager.filesDirty(null, basicVfRoots);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
@@ -185,22 +173,12 @@ public class SvnRootsDetector {
|
||||
|
||||
@Nullable
|
||||
private RootUrlInfo findTopRoot(@NotNull final File file) {
|
||||
return ContainerUtil.find(myResult.myTopRoots, new Condition<RootUrlInfo>() {
|
||||
@Override
|
||||
public boolean value(RootUrlInfo topRoot) {
|
||||
return FileUtil.filesEqual(topRoot.getIoFile(), file);
|
||||
}
|
||||
});
|
||||
return ContainerUtil.find(myResult.myTopRoots, topRoot -> FileUtil.filesEqual(topRoot.getIoFile(), file));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private RootUrlInfo findAncestorTopRoot(@NotNull final VirtualFile file) {
|
||||
return ContainerUtil.find(myResult.myTopRoots, new Condition<RootUrlInfo>() {
|
||||
@Override
|
||||
public boolean value(RootUrlInfo topRoot) {
|
||||
return VfsUtilCore.isAncestor(topRoot.getVirtualFile(), file, true);
|
||||
}
|
||||
});
|
||||
return ContainerUtil.find(myResult.myTopRoots, topRoot -> VfsUtilCore.isAncestor(topRoot.getVirtualFile(), file, true));
|
||||
}
|
||||
|
||||
private static class RepositoryRoots {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.svn;
|
||||
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 10/23/12
|
||||
* Time: 2:31 PM
|
||||
*/
|
||||
// TODO: Used only in SvnLockingTest which is not required anymore. Likely to be removed.
|
||||
public class SvnTestWriteOperationLocks extends SvnAbstractWriteOperationLocks {
|
||||
private final WorkingCopy myWorkingCopy;
|
||||
|
||||
public SvnTestWriteOperationLocks(WorkingCopy copy) {
|
||||
super(10);
|
||||
myWorkingCopy = copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WorkingCopy getCopy(File file, boolean directory) throws SVNException {
|
||||
return myWorkingCopy;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,6 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.wm.impl.status.StatusBarUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
@@ -55,7 +54,6 @@ import org.jetbrains.idea.svn.api.ProgressEvent;
|
||||
import org.jetbrains.idea.svn.api.ProgressTracker;
|
||||
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager;
|
||||
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
|
||||
import org.jetbrains.idea.svn.browse.DirectoryEntry;
|
||||
import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer;
|
||||
import org.jetbrains.idea.svn.commandLine.SvnBindException;
|
||||
import org.jetbrains.idea.svn.dialogs.LockDialog;
|
||||
@@ -67,7 +65,6 @@ import org.tmatesoft.sqljet.core.internal.table.ISqlJetBtreeSchemaTable;
|
||||
import org.tmatesoft.sqljet.core.internal.table.SqlJetBtreeSchemaTable;
|
||||
import org.tmatesoft.sqljet.core.table.ISqlJetOptions;
|
||||
import org.tmatesoft.sqljet.core.table.SqlJetDb;
|
||||
import org.tmatesoft.sqljet.core.table.engine.ISqlJetEngineSynchronized;
|
||||
import org.tmatesoft.sqljet.core.table.engine.SqlJetEngine;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNErrorMessage;
|
||||
@@ -224,27 +221,25 @@ public class SvnUtil {
|
||||
}
|
||||
};
|
||||
|
||||
Runnable command = new Runnable() {
|
||||
public void run() {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
Runnable command = () -> {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
|
||||
try {
|
||||
try {
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.locking.files"));
|
||||
}
|
||||
for (File ioFile : ioFiles) {
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.locking.files"));
|
||||
progress.checkCanceled();
|
||||
}
|
||||
for (File ioFile : ioFiles) {
|
||||
if (progress != null) {
|
||||
progress.checkCanceled();
|
||||
}
|
||||
if (progress != null) {
|
||||
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
|
||||
}
|
||||
activeVcs.getFactory(ioFile).createLockClient().lock(ioFile, force, lockMessage, eventHandler);
|
||||
if (progress != null) {
|
||||
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
|
||||
}
|
||||
activeVcs.getFactory(ioFile).createLockClient().lock(ioFile, force, lockMessage, eventHandler);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exception[0] = e;
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exception[0] = e;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -289,27 +284,25 @@ public class SvnUtil {
|
||||
}
|
||||
};
|
||||
|
||||
Runnable command = new Runnable() {
|
||||
public void run() {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
Runnable command = () -> {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
|
||||
try {
|
||||
try {
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.unlocking.files"));
|
||||
}
|
||||
for (File ioFile : ioFiles) {
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.unlocking.files"));
|
||||
progress.checkCanceled();
|
||||
}
|
||||
for (File ioFile : ioFiles) {
|
||||
if (progress != null) {
|
||||
progress.checkCanceled();
|
||||
}
|
||||
if (progress != null) {
|
||||
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
|
||||
}
|
||||
activeVcs.getFactory(ioFile).createLockClient().unlock(ioFile, force, eventHandler);
|
||||
if (progress != null) {
|
||||
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
|
||||
}
|
||||
activeVcs.getFactory(ioFile).createLockClient().unlock(ioFile, force, eventHandler);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exception[0] = e;
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exception[0] = e;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -332,26 +325,17 @@ public class SvnUtil {
|
||||
|
||||
@NotNull
|
||||
public static MultiMap<Pair<SVNURL, WorkingCopyFormat>, Change> splitChangesIntoWc(@NotNull SvnVcs vcs, @NotNull List<Change> changes) {
|
||||
return splitIntoRepositoriesMap(vcs, changes, new Convertor<Change, FilePath>() {
|
||||
@Override
|
||||
public FilePath convert(@NotNull Change change) {
|
||||
return ChangesUtil.getFilePath(change);
|
||||
}
|
||||
});
|
||||
return splitIntoRepositoriesMap(vcs, changes, change -> ChangesUtil.getFilePath(change));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> MultiMap<Pair<SVNURL, WorkingCopyFormat>, T> splitIntoRepositoriesMap(@NotNull final SvnVcs vcs,
|
||||
@NotNull Collection<T> items,
|
||||
@NotNull final Convertor<T, FilePath> converter) {
|
||||
return ContainerUtil.groupBy(items, new NotNullFunction<T, Pair<SVNURL, WorkingCopyFormat>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<SVNURL, WorkingCopyFormat> fun(@NotNull T item) {
|
||||
RootUrlInfo path = vcs.getSvnFileUrlMapping().getWcRootForFilePath(converter.convert(item).getIOFile());
|
||||
return ContainerUtil.groupBy(items, item -> {
|
||||
RootUrlInfo path = vcs.getSvnFileUrlMapping().getWcRootForFilePath(converter.convert(item).getIOFile());
|
||||
|
||||
return path == null ? UNKNOWN_REPOSITORY_AND_FORMAT : Pair.create(path.getRepositoryUrlUrl(), path.getFormat());
|
||||
}
|
||||
return path == null ? UNKNOWN_REPOSITORY_AND_FORMAT : Pair.create(path.getRepositoryUrlUrl(), path.getFormat());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -487,12 +471,8 @@ public class SvnUtil {
|
||||
|
||||
public static VirtualFile getVirtualFile(final String filePath) {
|
||||
@NonNls final String path = VfsUtilCore.pathToUrl(filePath.replace(File.separatorChar, '/'));
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
|
||||
@Nullable
|
||||
public VirtualFile compute() {
|
||||
return VirtualFileManager.getInstance().findFileByUrl(path);
|
||||
}
|
||||
});
|
||||
return ApplicationManager.getApplication()
|
||||
.runReadAction((Computable<VirtualFile>)() -> VirtualFileManager.getInstance().findFileByUrl(path));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -597,13 +577,9 @@ public class SvnUtil {
|
||||
public static boolean remoteFolderIsEmpty(@NotNull SvnVcs vcs, @NotNull String url) throws VcsException {
|
||||
SvnTarget target = SvnTarget.fromURL(createUrl(url));
|
||||
Ref<Boolean> result = new Ref<>(true);
|
||||
DirectoryEntryConsumer handler = new DirectoryEntryConsumer() {
|
||||
|
||||
@Override
|
||||
public void consume(final DirectoryEntry entry) throws SVNException {
|
||||
if (entry != null) {
|
||||
result.set(false);
|
||||
}
|
||||
DirectoryEntryConsumer handler = entry -> {
|
||||
if (entry != null) {
|
||||
result.set(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -990,15 +966,13 @@ public class SvnUtil {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
result = (String)runSynchronized(new ISqlJetEngineSynchronized() {
|
||||
public Object runSynchronized(SqlJetEngine engine) throws SqlJetException {
|
||||
btree.enter();
|
||||
try {
|
||||
return readDbSchema();
|
||||
}
|
||||
finally {
|
||||
btree.leave();
|
||||
}
|
||||
result = (String)runSynchronized(engine -> {
|
||||
btree.enter();
|
||||
try {
|
||||
return readDbSchema();
|
||||
}
|
||||
finally {
|
||||
btree.leave();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -185,12 +185,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
|
||||
myChangeListListener = new SvnChangelistListener(this);
|
||||
|
||||
myVcsListener = new VcsListener() {
|
||||
@Override
|
||||
public void directoryMappingChanged() {
|
||||
invokeRefreshSvnRoots();
|
||||
}
|
||||
};
|
||||
myVcsListener = () -> invokeRefreshSvnRoots();
|
||||
}
|
||||
|
||||
myFrameStateListener = project.isDefault() ? null : new MyFrameStateListener(ChangeListManager.getInstance(project),
|
||||
@@ -205,12 +200,9 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
if (myProject.isDefault()) return;
|
||||
myCopiesRefreshManager = new SvnCopiesRefreshManager((SvnFileUrlMappingImpl)getSvnFileUrlMapping());
|
||||
if (!myConfiguration.isCleanupRun()) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cleanup17copies();
|
||||
myConfiguration.setCleanupRun(true);
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
cleanup17copies();
|
||||
myConfiguration.setCleanupRun(true);
|
||||
}, ModalityState.NON_MODAL, myProject.getDisposed());
|
||||
}
|
||||
else {
|
||||
@@ -261,26 +253,23 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
|
||||
private void upgradeIfNeeded(final MessageBus bus) {
|
||||
final MessageBusConnection connection = bus.connect();
|
||||
connection.subscribe(ChangeListManagerImpl.LISTS_LOADED, new LocalChangeListsLoadedListener() {
|
||||
@Override
|
||||
public void processLoadedLists(final List<LocalChangeList> lists) {
|
||||
if (lists.isEmpty()) return;
|
||||
try {
|
||||
ChangeListManager.getInstance(myProject).setReadOnly(LocalChangeList.DEFAULT_NAME, true);
|
||||
connection.subscribe(ChangeListManagerImpl.LISTS_LOADED, lists -> {
|
||||
if (lists.isEmpty()) return;
|
||||
try {
|
||||
ChangeListManager.getInstance(myProject).setReadOnly(LocalChangeList.DEFAULT_NAME, true);
|
||||
|
||||
if (!myConfiguration.changeListsSynchronized()) {
|
||||
processChangeLists(lists);
|
||||
}
|
||||
if (!myConfiguration.changeListsSynchronized()) {
|
||||
processChangeLists(lists);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
//
|
||||
}
|
||||
finally {
|
||||
myConfiguration.upgrade();
|
||||
}
|
||||
|
||||
connection.disconnect();
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
//
|
||||
}
|
||||
finally {
|
||||
myConfiguration.upgrade();
|
||||
}
|
||||
|
||||
connection.disconnect();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -301,12 +290,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
finally {
|
||||
final Application appManager = ApplicationManager.getApplication();
|
||||
if (appManager.isDispatchThread()) {
|
||||
appManager.executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
plVcsManager.stopBackgroundVcsOperation();
|
||||
}
|
||||
});
|
||||
appManager.executeOnPooledThread(() -> plVcsManager.stopBackgroundVcsOperation());
|
||||
}
|
||||
else {
|
||||
plVcsManager.stopBackgroundVcsOperation();
|
||||
@@ -356,24 +340,21 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
}
|
||||
|
||||
// do one time after project loaded
|
||||
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postStartup();
|
||||
StartupManager.getInstance(myProject).runWhenProjectIsInitialized((DumbAwareRunnable)() -> {
|
||||
postStartup();
|
||||
|
||||
// for IDEA, it takes 2 minutes - and anyway this can be done in background, no sense...
|
||||
// once it could be mistaken about copies for 2 minutes on start...
|
||||
// for IDEA, it takes 2 minutes - and anyway this can be done in background, no sense...
|
||||
// once it could be mistaken about copies for 2 minutes on start...
|
||||
|
||||
/*if (! myMapping.getAllWcInfos().isEmpty()) {
|
||||
invokeRefreshSvnRoots();
|
||||
return;
|
||||
}
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
public void run() {
|
||||
myCopiesRefreshManager.getCopiesRefresh().ensureInit();
|
||||
}
|
||||
}, SvnBundle.message("refreshing.working.copies.roots.progress.text"), true, myProject);*/
|
||||
/*if (! myMapping.getAllWcInfos().isEmpty()) {
|
||||
invokeRefreshSvnRoots();
|
||||
return;
|
||||
}
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
public void run() {
|
||||
myCopiesRefreshManager.getCopiesRefresh().ensureInit();
|
||||
}
|
||||
}, SvnBundle.message("refreshing.working.copies.roots.progress.text"), true, myProject);*/
|
||||
});
|
||||
|
||||
myProject.getMessageBus().connect().subscribe(ProjectLevelVcsManager.VCS_CONFIGURATION_CHANGED, myRootsToWorkingCopies);
|
||||
@@ -818,12 +799,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
infos.add(new MyPair<>(vf, url.toString(), s));
|
||||
}
|
||||
final List<MyPair<S>> filtered = new UniqueRootsFilter().filter(infos);
|
||||
final List<S> converted = ObjectsConvertor.convert(filtered, new Convertor<MyPair<S>, S>() {
|
||||
@Override
|
||||
public S convert(final MyPair<S> o) {
|
||||
return o.getSrc();
|
||||
}
|
||||
});
|
||||
final List<S> converted = ObjectsConvertor.convert(filtered, o -> o.getSrc());
|
||||
if (!notMatched.isEmpty()) {
|
||||
// potential bug is here: order is not kept. but seems it only occurs for cases where result is sorted after filtering so ok
|
||||
converted.addAll(notMatched);
|
||||
@@ -917,10 +893,10 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
|
||||
|
||||
/**
|
||||
* Detects appropriate client factory based on project root directory working copy format.
|
||||
*
|
||||
* <p>
|
||||
* Try to avoid usages of this method (for now) as it could not correctly for all cases
|
||||
* detect svn 1.8 working copy format to guarantee command line client.
|
||||
*
|
||||
* <p>
|
||||
* For instance, when working copies of several formats are presented in project
|
||||
* (though it seems to be rather unlikely case).
|
||||
*
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.svn;
|
||||
|
||||
import com.intellij.openapi.vcs.changes.ChangesUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNErrorMessage;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 10/23/12
|
||||
* Time: 2:29 PM
|
||||
*/
|
||||
// TODO: Such locking functionality is not required anymore. Likely to be removed.
|
||||
public class SvnWriteOperationLocks extends SvnAbstractWriteOperationLocks {
|
||||
private final RootsToWorkingCopies myRootsToWorkingCopies;
|
||||
|
||||
public SvnWriteOperationLocks(RootsToWorkingCopies rootsToWorkingCopies) {
|
||||
super(1000);
|
||||
myRootsToWorkingCopies = rootsToWorkingCopies;
|
||||
}
|
||||
|
||||
protected WorkingCopy getCopy(File file, boolean directory) throws SVNException {
|
||||
final VirtualFile parentOrSelf = ChangesUtil.findValidParentAccurately(VcsUtil.getFilePath(file, directory));
|
||||
final WorkingCopy wcRoot = myRootsToWorkingCopies.getWcRoot(parentOrSelf);
|
||||
if (wcRoot == null) {
|
||||
throw new SVNException(SVNErrorMessage.create(directory ? SVNErrorCode.WC_NOT_WORKING_COPY : SVNErrorCode.WC_NOT_FILE));
|
||||
}
|
||||
// todo check about externals!
|
||||
return wcRoot;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -24,7 +23,6 @@ import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -46,20 +44,11 @@ public class UniqueRootsFilter {
|
||||
}
|
||||
|
||||
private static <T extends RootUrlPair> void sort(List<T> list) {
|
||||
Collections.sort(list, new Comparator<RootUrlPair>() {
|
||||
public int compare(final RootUrlPair o1, final RootUrlPair o2) {
|
||||
return o1.getVirtualFile().getPath().compareTo(o2.getVirtualFile().getPath());
|
||||
}
|
||||
});
|
||||
Collections.sort(list, (o1, o2) -> o1.getVirtualFile().getPath().compareTo(o2.getVirtualFile().getPath()));
|
||||
}
|
||||
|
||||
private static <T extends RootUrlPair> boolean alreadyRegistered(@NotNull final T child, @NotNull List<T> registered) {
|
||||
return ContainerUtil.exists(registered, new Condition<T>() {
|
||||
@Override
|
||||
public boolean value(T parent) {
|
||||
return isSamePath(child, parent) || isSameSupposedUrl(child, parent);
|
||||
}
|
||||
});
|
||||
return ContainerUtil.exists(registered, parent -> isSamePath(child, parent) || isSameSupposedUrl(child, parent));
|
||||
}
|
||||
|
||||
private static <T extends RootUrlPair> boolean isSamePath(@NotNull T child, @NotNull T parent) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.AbstractVcsHelper;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.TransactionRunnable;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -59,24 +58,22 @@ public abstract class BasicAction extends AnAction implements DumbAware {
|
||||
AbstractVcsHelper helper = AbstractVcsHelper.getInstance(project);
|
||||
|
||||
try {
|
||||
List<VcsException> exceptions = helper.runTransactionRunnable(vcs, new TransactionRunnable() {
|
||||
public void run(List<VcsException> exceptions) {
|
||||
VirtualFile badFile = null;
|
||||
try {
|
||||
if (isBatchAction()) {
|
||||
batchExecute(vcs, files, e.getDataContext());
|
||||
}
|
||||
else {
|
||||
for (VirtualFile file : files) {
|
||||
badFile = file;
|
||||
execute(vcs, file, e.getDataContext());
|
||||
}
|
||||
List<VcsException> exceptions = helper.runTransactionRunnable(vcs, exceptionList -> {
|
||||
VirtualFile badFile = null;
|
||||
try {
|
||||
if (isBatchAction()) {
|
||||
batchExecute(vcs, files, e.getDataContext());
|
||||
}
|
||||
else {
|
||||
for (VirtualFile file : files) {
|
||||
badFile = file;
|
||||
execute(vcs, file, e.getDataContext());
|
||||
}
|
||||
}
|
||||
catch (VcsException ex) {
|
||||
ex.setVirtualFile(badFile);
|
||||
exceptions.add(ex);
|
||||
}
|
||||
}
|
||||
catch (VcsException ex) {
|
||||
ex.setVirtualFile(badFile);
|
||||
exceptionList.add(ex);
|
||||
}
|
||||
}, null);
|
||||
|
||||
|
||||
+1
-5
@@ -32,11 +32,7 @@ public class ExclusiveBackgroundVcsAction {
|
||||
} finally {
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (application.isDispatchThread()) {
|
||||
application.executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
plVcsManager.stopBackgroundVcsOperation();
|
||||
}
|
||||
});
|
||||
application.executeOnPooledThread(() -> plVcsManager.stopBackgroundVcsOperation());
|
||||
} else {
|
||||
plVcsManager.stopBackgroundVcsOperation();
|
||||
}
|
||||
|
||||
@@ -35,9 +35,7 @@ import org.jetbrains.idea.svn.api.Depth;
|
||||
import org.jetbrains.idea.svn.commandLine.SvnBindException;
|
||||
import org.jetbrains.idea.svn.conflict.ConflictClient;
|
||||
import org.jetbrains.idea.svn.dialogs.SelectFilesDialog;
|
||||
import org.jetbrains.idea.svn.status.Status;
|
||||
import org.jetbrains.idea.svn.status.StatusClient;
|
||||
import org.jetbrains.idea.svn.status.StatusConsumer;
|
||||
import org.jetbrains.idea.svn.status.StatusType;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
|
||||
@@ -127,13 +125,10 @@ public class MarkResolvedAction extends BasicAction {
|
||||
File path = VfsUtilCore.virtualToIoFile(file);
|
||||
StatusClient client = vcs.getFactory(path).createStatusClient();
|
||||
|
||||
client.doStatus(path, SVNRevision.UNDEFINED, Depth.INFINITY, false, false, false, false, new StatusConsumer() {
|
||||
@Override
|
||||
public void consume(@NotNull Status status) {
|
||||
if (status.getContentsStatus() == StatusType.STATUS_CONFLICTED ||
|
||||
status.getPropertiesStatus() == StatusType.STATUS_CONFLICTED) {
|
||||
result.add(status.getFile().getAbsolutePath());
|
||||
}
|
||||
client.doStatus(path, SVNRevision.UNDEFINED, Depth.INFINITY, false, false, false, false, status -> {
|
||||
if (status.getContentsStatus() == StatusType.STATUS_CONFLICTED ||
|
||||
status.getPropertiesStatus() == StatusType.STATUS_CONFLICTED) {
|
||||
result.add(status.getFile().getAbsolutePath());
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ShareWholeProject extends AnAction implements DumbAware {
|
||||
|
||||
final Presentation presentation = e.getPresentation();
|
||||
presentation.setEnabled(checker.isEnabled());
|
||||
|
||||
|
||||
presentation.setVisible(checker.isVisible());
|
||||
if (checker.isEnabled()) {
|
||||
presentation.setText(SvnBundle.message("action.share.whole.project.text"));
|
||||
@@ -73,19 +73,20 @@ public class ShareWholeProject extends AnAction implements DumbAware {
|
||||
myHadNoMappings = MyCheckResult.notMapped.equals(result);
|
||||
if (MyCheckResult.notMapped.equals(result)) {
|
||||
// no change list manager working
|
||||
if(SvnUtil.seemsLikeVersionedDir(baseDir)) return;
|
||||
} else if (SvnStatusUtil.isUnderControl(myProject, baseDir)) {
|
||||
if (SvnUtil.seemsLikeVersionedDir(baseDir)) return;
|
||||
}
|
||||
else if (SvnStatusUtil.isUnderControl(myProject, baseDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((! myHadNoMappings) && (! SvnVcs.getInstance(myProject).getSvnFileUrlMapping().isEmpty())) {
|
||||
if ((!myHadNoMappings) && (!SvnVcs.getInstance(myProject).getSvnFileUrlMapping().isEmpty())) {
|
||||
// there are some versioned dirs under project dir
|
||||
return;
|
||||
}
|
||||
|
||||
// visible: already checked above
|
||||
myVisible = true;
|
||||
myEnabled = (! vcsManager.isBackgroundVcsOperationRunning());
|
||||
myEnabled = (!vcsManager.isBackgroundVcsOperationRunning());
|
||||
}
|
||||
|
||||
private static enum MyCheckResult {
|
||||
@@ -137,7 +138,7 @@ public class ShareWholeProject extends AnAction implements DumbAware {
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final MyChecker checker = new MyChecker();
|
||||
checker.execute(e);
|
||||
if (! checker.isEnabled()) return;
|
||||
if (!checker.isEnabled()) return;
|
||||
|
||||
final Project project = checker.getProject();
|
||||
final VirtualFile baseDir = project.getBaseDir();
|
||||
@@ -146,26 +147,21 @@ public class ShareWholeProject extends AnAction implements DumbAware {
|
||||
boolean excThrown = false;
|
||||
try {
|
||||
success = ShareProjectAction.share(project, baseDir);
|
||||
} catch (VcsException exc) {
|
||||
}
|
||||
catch (VcsException exc) {
|
||||
AbstractVcsHelper.getInstance(project).showError(exc, "Failed to Share Project");
|
||||
excThrown = true;
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
// if success = false -> either action was cancelled or exception was thrown, so also check for exception
|
||||
if (success || excThrown) {
|
||||
baseDir.refresh(true, true, new Runnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(project.getBaseDir());
|
||||
if (checker.isHadNoMappings() && SvnUtil.seemsLikeVersionedDir(baseDir)) {
|
||||
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
|
||||
vcsManager.setDirectoryMappings(Arrays.asList(new VcsDirectoryMapping("", SvnVcs.VCS_NAME)));
|
||||
}
|
||||
}
|
||||
}, ModalityState.NON_MODAL, project.getDisposed());
|
||||
baseDir.refresh(true, true, () -> ApplicationManager.getApplication().invokeLater(() -> {
|
||||
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(project.getBaseDir());
|
||||
if (checker.isHadNoMappings() && SvnUtil.seemsLikeVersionedDir(baseDir)) {
|
||||
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
|
||||
vcsManager.setDirectoryMappings(Arrays.asList(new VcsDirectoryMapping("", SvnVcs.VCS_NAME)));
|
||||
}
|
||||
});
|
||||
}, ModalityState.NON_MODAL, project.getDisposed()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-6
@@ -67,12 +67,7 @@ public class SvnExcludingIgnoredOperation {
|
||||
}
|
||||
|
||||
private boolean isIgnoredByVcs(final VirtualFile file) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return myVcsManager.isIgnored(file);
|
||||
}
|
||||
});
|
||||
return ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> myVcsManager.isIgnored(file));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,53 +58,53 @@ public class SvnMergeProvider implements MergeProvider {
|
||||
@NotNull
|
||||
public MergeData loadRevisions(@NotNull final VirtualFile file) throws VcsException {
|
||||
final MergeData data = new MergeData();
|
||||
VcsRunnable runnable = new VcsRunnable() {
|
||||
public void run() throws VcsException {
|
||||
File oldFile = null;
|
||||
File newFile = null;
|
||||
File workingFile = null;
|
||||
boolean mergeCase = false;
|
||||
SvnVcs vcs = SvnVcs.getInstance(myProject);
|
||||
Info info = vcs.getInfo(file);
|
||||
VcsRunnable runnable = () -> {
|
||||
File oldFile = null;
|
||||
File newFile = null;
|
||||
File workingFile = null;
|
||||
boolean mergeCase = false;
|
||||
SvnVcs vcs = SvnVcs.getInstance(myProject);
|
||||
Info info = vcs.getInfo(file);
|
||||
|
||||
if (info != null) {
|
||||
oldFile = info.getConflictOldFile();
|
||||
newFile = info.getConflictNewFile();
|
||||
workingFile = info.getConflictWrkFile();
|
||||
mergeCase = workingFile == null || workingFile.getName().contains("working");
|
||||
// for debug
|
||||
if (workingFile == null) {
|
||||
LOG.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile);
|
||||
}
|
||||
if (mergeCase) {
|
||||
// this is merge case
|
||||
oldFile = info.getConflictNewFile();
|
||||
newFile = info.getConflictOldFile();
|
||||
workingFile = info.getConflictWrkFile();
|
||||
}
|
||||
data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision());
|
||||
} else {
|
||||
throw new VcsException("Could not get info for " + file.getPath());
|
||||
}
|
||||
if (oldFile == null || newFile == null || workingFile == null) {
|
||||
ByteArrayOutputStream bos = getBaseRevisionContents(vcs, file);
|
||||
data.ORIGINAL = bos.toByteArray();
|
||||
data.LAST = bos.toByteArray();
|
||||
data.CURRENT = readFile(new File(file.getPath()));
|
||||
}
|
||||
else {
|
||||
data.ORIGINAL = readFile(oldFile);
|
||||
data.LAST = readFile(newFile);
|
||||
data.CURRENT = readFile(workingFile);
|
||||
if (info != null) {
|
||||
oldFile = info.getConflictOldFile();
|
||||
newFile = info.getConflictNewFile();
|
||||
workingFile = info.getConflictWrkFile();
|
||||
mergeCase = workingFile == null || workingFile.getName().contains("working");
|
||||
// for debug
|
||||
if (workingFile == null) {
|
||||
LOG
|
||||
.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile);
|
||||
}
|
||||
if (mergeCase) {
|
||||
final ByteArrayOutputStream contents = getBaseRevisionContents(vcs, file);
|
||||
if (! Arrays.equals(contents.toByteArray(), data.ORIGINAL)) {
|
||||
// swap base and server: another order of merge arguments
|
||||
byte[] original = data.ORIGINAL;
|
||||
data.ORIGINAL = data.LAST;
|
||||
data.LAST = original;
|
||||
}
|
||||
// this is merge case
|
||||
oldFile = info.getConflictNewFile();
|
||||
newFile = info.getConflictOldFile();
|
||||
workingFile = info.getConflictWrkFile();
|
||||
}
|
||||
data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision());
|
||||
}
|
||||
else {
|
||||
throw new VcsException("Could not get info for " + file.getPath());
|
||||
}
|
||||
if (oldFile == null || newFile == null || workingFile == null) {
|
||||
ByteArrayOutputStream bos = getBaseRevisionContents(vcs, file);
|
||||
data.ORIGINAL = bos.toByteArray();
|
||||
data.LAST = bos.toByteArray();
|
||||
data.CURRENT = readFile(new File(file.getPath()));
|
||||
}
|
||||
else {
|
||||
data.ORIGINAL = readFile(oldFile);
|
||||
data.LAST = readFile(newFile);
|
||||
data.CURRENT = readFile(workingFile);
|
||||
}
|
||||
if (mergeCase) {
|
||||
final ByteArrayOutputStream contents = getBaseRevisionContents(vcs, file);
|
||||
if (!Arrays.equals(contents.toByteArray(), data.ORIGINAL)) {
|
||||
// swap base and server: another order of merge arguments
|
||||
byte[] original = data.ORIGINAL;
|
||||
data.ORIGINAL = data.LAST;
|
||||
data.LAST = original;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -176,11 +176,7 @@ public abstract class BaseSvnFileAnnotation extends FileAnnotation {
|
||||
|
||||
public List<VcsFileRevision> getRevisions() {
|
||||
final List<VcsFileRevision> result = new ArrayList<>(myRevisionMap.values());
|
||||
Collections.sort(result, new Comparator<VcsFileRevision>() {
|
||||
public int compare(final VcsFileRevision o1, final VcsFileRevision o2) {
|
||||
return o2.getRevisionNumber().compareTo(o1.getRevisionNumber());
|
||||
}
|
||||
});
|
||||
Collections.sort(result, (o1, o2) -> o2.getRevisionNumber().compareTo(o1.getRevisionNumber()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,10 @@ import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.*;
|
||||
import org.jetbrains.idea.svn.checkin.CommitInfo;
|
||||
import org.jetbrains.idea.svn.diff.DiffOptions;
|
||||
import org.jetbrains.idea.svn.history.*;
|
||||
import org.jetbrains.idea.svn.history.HistoryClient;
|
||||
import org.jetbrains.idea.svn.history.SvnChangeList;
|
||||
import org.jetbrains.idea.svn.history.SvnFileRevision;
|
||||
import org.jetbrains.idea.svn.info.Info;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNErrorMessage;
|
||||
@@ -70,8 +71,9 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
throw new VcsException("Can not get current revision for file " + file.getPath());
|
||||
}
|
||||
final SVNRevision svnRevision = ((SvnRevisionNumber)lastChangedRevision.getRevisionNumber()).getRevision();
|
||||
if (! svnRevision.isValid()) {
|
||||
throw new VcsException("Can not get last changed revision for file: " + file.getPath() + "\nPlease run svn info for this file and file an issue.");
|
||||
if (!svnRevision.isValid()) {
|
||||
throw new VcsException(
|
||||
"Can not get last changed revision for file: " + file.getPath() + "\nPlease run svn info for this file and file an issue.");
|
||||
}
|
||||
return annotate(file, new SvnFileRevision(myVcs, currentRevision, currentRevision, null, null, null, null, null),
|
||||
lastChangedRevision.getRevisionNumber(), true);
|
||||
@@ -89,78 +91,80 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
final FileAnnotation[] annotation = new FileAnnotation[1];
|
||||
final VcsException[] exception = new VcsException[1];
|
||||
|
||||
Runnable command = new Runnable() {
|
||||
public void run() {
|
||||
final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
final File ioFile = new File(file.getPath()).getAbsoluteFile();
|
||||
Info info = null;
|
||||
try {
|
||||
Runnable command = () -> {
|
||||
final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
final File ioFile = new File(file.getPath()).getAbsoluteFile();
|
||||
Info info = null;
|
||||
try {
|
||||
|
||||
final String contents;
|
||||
if (loadExternally) {
|
||||
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(ioFile), SVNRevision.BASE, SVNRevision.UNDEFINED);
|
||||
contents = LoadTextUtil.getTextByBinaryPresentation(data, file, false, false).toString();
|
||||
} else {
|
||||
final byte[] bytes = VcsHistoryUtil.loadRevisionContent(revision);
|
||||
contents = LoadTextUtil.getTextByBinaryPresentation(bytes, file, false, false).toString();
|
||||
}
|
||||
|
||||
final SvnFileAnnotation result = new SvnFileAnnotation(myVcs, file, contents, lastChangedRevision);
|
||||
|
||||
info = myVcs.getInfo(ioFile);
|
||||
if (info == null) {
|
||||
exception[0] = new VcsException(new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "File ''{0}'' is not under version control", ioFile)));
|
||||
return;
|
||||
}
|
||||
final String url = info.getURL() == null ? null : info.getURL().toString();
|
||||
|
||||
SVNRevision endRevision = ((SvnFileRevision) revision).getRevision();
|
||||
if (SVNRevision.WORKING.equals(endRevision)) {
|
||||
endRevision = info.getRevision();
|
||||
}
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.computing.annotation", file.getName()));
|
||||
}
|
||||
|
||||
// ignore mime type=true : IDEA-19562
|
||||
final AnnotationConsumer annotateHandler = createAnnotationHandler(progress, result);
|
||||
|
||||
boolean calculateMergeinfo =
|
||||
myVcs.getSvnConfiguration().isShowMergeSourcesInAnnotate() && SvnUtil.checkRepositoryVersion15(myVcs, url);
|
||||
final MySteppedLogGetter logGetter = new MySteppedLogGetter(
|
||||
myVcs, ioFile, progress,
|
||||
myVcs.getFactory(ioFile).createHistoryClient(), endRevision, result,
|
||||
url, calculateMergeinfo, file.getCharset());
|
||||
|
||||
logGetter.go();
|
||||
final LinkedList<SVNRevision> rp = logGetter.getRevisionPoints();
|
||||
|
||||
// TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair
|
||||
AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient();
|
||||
for (int i = 0; i < rp.size() - 1; i++) {
|
||||
annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), calculateMergeinfo, getLogClientOptions(myVcs),
|
||||
annotateHandler);
|
||||
}
|
||||
|
||||
if (rp.get(1).getNumber() > 0) {
|
||||
result.setFirstRevision(rp.get(1));
|
||||
}
|
||||
annotation[0] = result;
|
||||
final String contents;
|
||||
if (loadExternally) {
|
||||
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(ioFile), SVNRevision.BASE, SVNRevision.UNDEFINED);
|
||||
contents = LoadTextUtil.getTextByBinaryPresentation(data, file, false, false).toString();
|
||||
}
|
||||
catch (IOException e) {
|
||||
exception[0] = new VcsException(e);
|
||||
} catch (VcsException e) {
|
||||
if (e.getCause() instanceof SVNException) {
|
||||
handleSvnException(ioFile, info, (SVNException)e.getCause(), file, revision, annotation, exception);
|
||||
}
|
||||
else {
|
||||
exception[0] = e;
|
||||
}
|
||||
else {
|
||||
final byte[] bytes = VcsHistoryUtil.loadRevisionContent(revision);
|
||||
contents = LoadTextUtil.getTextByBinaryPresentation(bytes, file, false, false).toString();
|
||||
}
|
||||
|
||||
final SvnFileAnnotation result = new SvnFileAnnotation(myVcs, file, contents, lastChangedRevision);
|
||||
|
||||
info = myVcs.getInfo(ioFile);
|
||||
if (info == null) {
|
||||
exception[0] = new VcsException(
|
||||
new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "File ''{0}'' is not under version control", ioFile)));
|
||||
return;
|
||||
}
|
||||
final String url = info.getURL() == null ? null : info.getURL().toString();
|
||||
|
||||
SVNRevision endRevision = ((SvnFileRevision)revision).getRevision();
|
||||
if (SVNRevision.WORKING.equals(endRevision)) {
|
||||
endRevision = info.getRevision();
|
||||
}
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.computing.annotation", file.getName()));
|
||||
}
|
||||
|
||||
// ignore mime type=true : IDEA-19562
|
||||
final AnnotationConsumer annotateHandler = createAnnotationHandler(progress, result);
|
||||
|
||||
boolean calculateMergeinfo =
|
||||
myVcs.getSvnConfiguration().isShowMergeSourcesInAnnotate() && SvnUtil.checkRepositoryVersion15(myVcs, url);
|
||||
final MySteppedLogGetter logGetter = new MySteppedLogGetter(
|
||||
myVcs, ioFile, progress,
|
||||
myVcs.getFactory(ioFile).createHistoryClient(), endRevision, result,
|
||||
url, calculateMergeinfo, file.getCharset());
|
||||
|
||||
logGetter.go();
|
||||
final LinkedList<SVNRevision> rp = logGetter.getRevisionPoints();
|
||||
|
||||
// TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair
|
||||
AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient();
|
||||
for (int i = 0; i < rp.size() - 1; i++) {
|
||||
annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), calculateMergeinfo, getLogClientOptions(myVcs),
|
||||
annotateHandler);
|
||||
}
|
||||
|
||||
if (rp.get(1).getNumber() > 0) {
|
||||
result.setFirstRevision(rp.get(1));
|
||||
}
|
||||
annotation[0] = result;
|
||||
}
|
||||
catch (IOException e) {
|
||||
exception[0] = new VcsException(e);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
if (e.getCause() instanceof SVNException) {
|
||||
handleSvnException(ioFile, info, (SVNException)e.getCause(), file, revision, annotation, exception);
|
||||
}
|
||||
else {
|
||||
exception[0] = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(command, SvnBundle.message("action.text.annotate"), false, myVcs.getProject());
|
||||
ProgressManager.getInstance()
|
||||
.runProcessWithProgressSynchronously(command, SvnBundle.message("action.text.annotate"), false, myVcs.getProject());
|
||||
}
|
||||
else {
|
||||
command.run();
|
||||
@@ -179,10 +183,10 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
FileAnnotation[] annotation, VcsException[] exception) {
|
||||
// TODO: Check how this scenario could be reproduced by user and what changes needs to be done for command line client
|
||||
if (SVNErrorCode.FS_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) {
|
||||
final CommittedChangesProvider<SvnChangeList,ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
|
||||
final CommittedChangesProvider<SvnChangeList, ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
|
||||
try {
|
||||
final Pair<SvnChangeList, FilePath> pair = provider.getOneList(file, revision.getRevisionNumber());
|
||||
if (pair != null && info != null && pair.getSecond() != null && ! Comparing.equal(pair.getSecond().getIOFile(), ioFile)) {
|
||||
if (pair != null && info != null && pair.getSecond() != null && !Comparing.equal(pair.getSecond().getIOFile(), ioFile)) {
|
||||
annotation[0] = annotateNonExisting(pair, revision, info, file.getCharset(), file);
|
||||
return;
|
||||
}
|
||||
@@ -205,19 +209,21 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
final List<String> parts2 = StringUtil.split(can2.getPath(), File.separator, true);
|
||||
int cnt = 0;
|
||||
while (parts1.size() > cnt && parts2.size() > cnt) {
|
||||
if (! parts1.get(cnt).equals(parts2.get(cnt))) {
|
||||
if (!parts1.get(cnt).equals(parts2.get(cnt))) {
|
||||
if (cnt > 0) {
|
||||
return new File(StringUtil.join(parts1.subList(0, cnt), File.separator));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
++ cnt;
|
||||
++cnt;
|
||||
}
|
||||
//shorter one
|
||||
if (parts1.size() > parts2.size()) {
|
||||
return file2;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return file1;
|
||||
}
|
||||
}
|
||||
@@ -225,28 +231,34 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
private SvnRemoteFileAnnotation annotateNonExisting(Pair<SvnChangeList, FilePath> pair,
|
||||
VcsFileRevision revision,
|
||||
Info info,
|
||||
Charset charset, final VirtualFile current) throws VcsException, SVNException, IOException {
|
||||
Charset charset, final VirtualFile current)
|
||||
throws VcsException, SVNException, IOException {
|
||||
final File wasFile = pair.getSecond().getIOFile();
|
||||
final File root = getCommonAncestor(wasFile, info.getFile());
|
||||
|
||||
if (root == null) throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
|
||||
if (root == null) {
|
||||
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
|
||||
}
|
||||
|
||||
final String relativePath = FileUtil.getRelativePath(root.getPath(), wasFile.getPath(), File.separatorChar);
|
||||
if (relativePath == null) throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
|
||||
if (relativePath == null) {
|
||||
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
|
||||
}
|
||||
|
||||
Info wcRootInfo = myVcs.getInfo(root);
|
||||
if (wcRootInfo == null || wcRootInfo.getURL() == null) {
|
||||
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
|
||||
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
|
||||
}
|
||||
SVNURL wasUrl = wcRootInfo.getURL();
|
||||
final String[] strings = relativePath.replace('\\','/').split("/");
|
||||
final String[] strings = relativePath.replace('\\', '/').split("/");
|
||||
for (String string : strings) {
|
||||
wasUrl = wasUrl.appendPath(string, true);
|
||||
}
|
||||
|
||||
final SVNRevision svnRevision = ((SvnRevisionNumber)revision.getRevisionNumber()).getRevision();
|
||||
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromURL(wasUrl), svnRevision, svnRevision);
|
||||
final String contents = LoadTextUtil.getTextByBinaryPresentation(data, charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString();
|
||||
final String contents =
|
||||
LoadTextUtil.getTextByBinaryPresentation(data, charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString();
|
||||
final SvnRemoteFileAnnotation result = new SvnRemoteFileAnnotation(myVcs, contents, revision.getRevisionNumber(), current);
|
||||
final AnnotationConsumer annotateHandler = createAnnotationHandler(ProgressManager.getInstance().getProgressIndicator(), result);
|
||||
|
||||
@@ -262,23 +274,19 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
@NotNull
|
||||
private static AnnotationConsumer createAnnotationHandler(@Nullable final ProgressIndicator progress,
|
||||
@NotNull final BaseSvnFileAnnotation result) {
|
||||
return new AnnotationConsumer() {
|
||||
|
||||
@Override
|
||||
public void consume(int lineNumber, @NotNull CommitInfo info, @Nullable CommitInfo mergeInfo) throws SVNException {
|
||||
if (progress != null) {
|
||||
progress.checkCanceled();
|
||||
}
|
||||
|
||||
result.setLineInfo(lineNumber, info, mergeInfo != null && info.getRevision() > mergeInfo.getRevision() ? mergeInfo : null);
|
||||
return (lineNumber, info, mergeInfo) -> {
|
||||
if (progress != null) {
|
||||
progress.checkCanceled();
|
||||
}
|
||||
|
||||
result.setLineInfo(lineNumber, info, mergeInfo != null && info.getRevision() > mergeInfo.getRevision() ? mergeInfo : null);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public VcsAnnotation createCacheable(FileAnnotation fileAnnotation) {
|
||||
if (! (fileAnnotation instanceof SvnFileAnnotation)) return null;
|
||||
final SvnFileAnnotation svnFileAnnotation = (SvnFileAnnotation) fileAnnotation;
|
||||
if (!(fileAnnotation instanceof SvnFileAnnotation)) return null;
|
||||
final SvnFileAnnotation svnFileAnnotation = (SvnFileAnnotation)fileAnnotation;
|
||||
final AnnotationSourceSwitcher annotationSourceSwitcher = svnFileAnnotation.getAnnotationSourceSwitcher();
|
||||
if (annotationSourceSwitcher != null) {
|
||||
annotationSourceSwitcher.switchTo(AnnotationSource.LOCAL);
|
||||
@@ -288,7 +296,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
final VcsUsualLineAnnotationData lineAnnotationData = new VcsUsualLineAnnotationData(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
final VcsRevisionNumber revisionNumber = svnFileAnnotation.getLineRevisionNumber(i);
|
||||
lineAnnotationData.put(i, revisionNumber);
|
||||
lineAnnotationData.put(i, revisionNumber);
|
||||
}
|
||||
|
||||
final VcsAnnotation vcsAnnotation = new VcsAnnotation(VcsUtil.getFilePath(svnFileAnnotation.getFile()), lineAnnotationData,
|
||||
@@ -304,10 +312,10 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
final VcsRevisionNumber number = svnFileAnnotation.getLineRevisionNumber(i);
|
||||
if (number == null) continue;
|
||||
merged.put(i, number);
|
||||
addMap.put(number, svnFileAnnotation.getRevision(((SvnRevisionNumber) number).getRevision().getNumber()));
|
||||
addMap.put(number, svnFileAnnotation.getRevision(((SvnRevisionNumber)number).getRevision().getNumber()));
|
||||
}
|
||||
}
|
||||
if (! merged.isEmpty()) {
|
||||
if (!merged.isEmpty()) {
|
||||
vcsAnnotation.addAnnotation(MERGED_KEY, merged);
|
||||
vcsAnnotation.addCachedOtherRevisions(addMap);
|
||||
}
|
||||
@@ -326,7 +334,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
new SvnFileAnnotation(myVcs, vcsAnnotation.getFilePath().getVirtualFile(), annotatedContent, revisionNumber);
|
||||
final VcsLineAnnotationData basicAnnotation = vcsAnnotation.getBasicAnnotation();
|
||||
final VcsLineAnnotationData data = vcsAnnotation.getAdditionalAnnotations().get(MERGED_KEY);
|
||||
final Map<VcsRevisionNumber,VcsFileRevision> historyAsMap = session.getHistoryAsMap();
|
||||
final Map<VcsRevisionNumber, VcsFileRevision> historyAsMap = session.getHistoryAsMap();
|
||||
final Map<VcsRevisionNumber, VcsFileRevision> cachedOtherRevisions = vcsAnnotation.getCachedOtherRevisions();
|
||||
|
||||
for (int i = 0; i < basicAnnotation.getNumLines(); i++) {
|
||||
@@ -337,17 +345,18 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
|
||||
if (mergedData == null) {
|
||||
annotation.setLineInfo(i, fileRevision.getCommitInfo(), null);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
final SvnFileRevision mergedRevision = (SvnFileRevision)cachedOtherRevisions.get(mergedData);
|
||||
if (mergedRevision == null) return null;
|
||||
annotation.setLineInfo(i, fileRevision.getCommitInfo(), mergedRevision.getCommitInfo());
|
||||
}
|
||||
}
|
||||
if (vcsAnnotation.getFirstRevision() != null) {
|
||||
annotation.setFirstRevision(((SvnRevisionNumber) vcsAnnotation.getFirstRevision()).getRevision());
|
||||
annotation.setFirstRevision(((SvnRevisionNumber)vcsAnnotation.getFirstRevision()).getRevision());
|
||||
}
|
||||
for (VcsFileRevision revision : session.getRevisionList()) {
|
||||
annotation.setRevision(((SvnRevisionNumber) revision.getRevisionNumber()).getRevision().getNumber(), (SvnFileRevision)revision);
|
||||
annotation.setRevision(((SvnRevisionNumber)revision.getRevisionNumber()).getRevision().getNumber(), (SvnFileRevision)revision);
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
@@ -387,16 +396,18 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
boolean longHistory = true;
|
||||
if (maxAnnotateRevisions == -1) {
|
||||
longHistory = false;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (myEndRevision.getNumber() < maxAnnotateRevisions) {
|
||||
longHistory = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! longHistory) {
|
||||
if (!longHistory) {
|
||||
doLog(myCalculateMergeinfo, null, 0);
|
||||
putDefaultBounds();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
doLog(false, null, 0);
|
||||
final List<VcsFileRevision> fileRevisionList = myResult.getRevisions();
|
||||
if (fileRevisionList.size() < maxAnnotateRevisions) {
|
||||
@@ -407,7 +418,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
return;
|
||||
}
|
||||
|
||||
myRevisionPoints.add(((SvnRevisionNumber) fileRevisionList.get(0).getRevisionNumber()).getRevision());
|
||||
myRevisionPoints.add(((SvnRevisionNumber)fileRevisionList.get(0).getRevisionNumber()).getRevision());
|
||||
final SVNRevision truncateTo =
|
||||
((SvnRevisionNumber)fileRevisionList.get(maxAnnotateRevisions - 1).getRevisionNumber()).getRevision();
|
||||
myRevisionPoints.add(truncateTo);
|
||||
@@ -427,19 +438,17 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
|
||||
private void doLog(final boolean includeMerged, final SVNRevision truncateTo, final int max) throws VcsException {
|
||||
myClient.doLog(SvnTarget.fromFile(myIoFile), myEndRevision, truncateTo == null ? SVNRevision.create(1L) : truncateTo,
|
||||
false, false, includeMerged, max, null,
|
||||
new LogEntryConsumer() {
|
||||
@Override
|
||||
public void consume(LogEntry logEntry) {
|
||||
if (SVNRevision.UNDEFINED.getNumber() == logEntry.getRevision()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (myProgress != null) {
|
||||
myProgress.checkCanceled();
|
||||
myProgress.setText2(SvnBundle.message("progress.text2.revision.processed", logEntry.getRevision()));
|
||||
}
|
||||
myResult.setRevision(logEntry.getRevision(), new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, myUrl, ""));
|
||||
logEntry -> {
|
||||
if (SVNRevision.UNDEFINED.getNumber() == logEntry.getRevision()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (myProgress != null) {
|
||||
myProgress.checkCanceled();
|
||||
myProgress.setText2(SvnBundle.message("progress.text2.revision.processed", logEntry.getRevision()));
|
||||
}
|
||||
myResult
|
||||
.setRevision(logEntry.getRevision(), new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, myUrl, ""));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -105,13 +105,8 @@ public class AuthenticationService {
|
||||
if (repositoryUrl != null) {
|
||||
final String realm = repositoryUrl.toDecodedString();
|
||||
|
||||
authentication = requestCredentials(realm, type, new Getter<SVNAuthentication>() {
|
||||
@Override
|
||||
public SVNAuthentication get() {
|
||||
return myConfiguration.getInteractiveManager(myVcs).getInnerProvider()
|
||||
.requestClientAuthentication(type, repositoryUrl, realm, null, null, true);
|
||||
}
|
||||
});
|
||||
authentication = requestCredentials(realm, type, () -> myConfiguration.getInteractiveManager(myVcs).getInnerProvider()
|
||||
.requestClientAuthentication(type, repositoryUrl, realm, null, null, true));
|
||||
}
|
||||
|
||||
if (authentication == null) {
|
||||
@@ -154,30 +149,25 @@ public class AuthenticationService {
|
||||
public String requestSshCredentials(@NotNull final String realm,
|
||||
@NotNull final SimpleCredentialsDialog.Mode mode,
|
||||
@NotNull final String key) {
|
||||
return requestCredentials(realm, StringUtil.toLowerCase(mode.toString()), new Getter<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
final Ref<String> answer = new Ref<>();
|
||||
return requestCredentials(realm, StringUtil.toLowerCase(mode.toString()), () -> {
|
||||
final Ref<String> answer = new Ref<>();
|
||||
|
||||
Runnable command = new Runnable() {
|
||||
public void run() {
|
||||
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myVcs.getProject());
|
||||
Runnable command = () -> {
|
||||
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myVcs.getProject());
|
||||
|
||||
dialog.setup(mode, realm, key, true);
|
||||
dialog.setTitle(SvnBundle.message("dialog.title.authentication.required"));
|
||||
dialog.setSaveEnabled(false);
|
||||
if (dialog.showAndGet()) {
|
||||
answer.set(dialog.getPassword());
|
||||
}
|
||||
}
|
||||
};
|
||||
dialog.setup(mode, realm, key, true);
|
||||
dialog.setTitle(SvnBundle.message("dialog.title.authentication.required"));
|
||||
dialog.setSaveEnabled(false);
|
||||
if (dialog.showAndGet()) {
|
||||
answer.set(dialog.getPassword());
|
||||
}
|
||||
};
|
||||
|
||||
// Use ModalityState.any() as currently ssh credentials in terminal mode are requested in the thread that reads output and not in
|
||||
// the thread that started progress
|
||||
WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, ModalityState.any());
|
||||
// Use ModalityState.any() as currently ssh credentials in terminal mode are requested in the thread that reads output and not in
|
||||
// the thread that started progress
|
||||
WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, ModalityState.any());
|
||||
|
||||
return answer.get();
|
||||
}
|
||||
return answer.get();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.jetbrains.idea.svn.auth;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -63,7 +62,8 @@ import static com.intellij.util.WaitForProgressToShow.runOrInvokeLaterAboveProgr
|
||||
/**
|
||||
* @author alex
|
||||
*/
|
||||
public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager implements SvnAuthenticationListener, ISVNAuthenticationManagerExt {
|
||||
public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager
|
||||
implements SvnAuthenticationListener, ISVNAuthenticationManagerExt {
|
||||
private static final Logger LOG = Logger.getInstance(SvnAuthenticationManager.class);
|
||||
// while Mac storage not working for IDEA, we use this key to check whether to prompt abt plaintext or just store
|
||||
public static final String SVN_SSH = "svn+ssh";
|
||||
@@ -104,26 +104,22 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
myPersistentAuthenticationProviderProxy.setProject(myProject);
|
||||
}
|
||||
myInteraction = new MySvnAuthenticationInteraction(myProject);
|
||||
Disposer.register(myProject, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
myVcs = null;
|
||||
myProject = null;
|
||||
if (myPersistentAuthenticationProviderProxy != null) {
|
||||
myPersistentAuthenticationProviderProxy.myProject = null;
|
||||
((MyKeyringMasterKeyProvider) myPersistentAuthenticationProviderProxy.myISVNGnomeKeyringPasswordProvider).myProject = null;
|
||||
myPersistentAuthenticationProviderProxy = null;
|
||||
}
|
||||
if (myInteraction instanceof MySvnAuthenticationInteraction) {
|
||||
((MySvnAuthenticationInteraction) myInteraction).myProject = null;
|
||||
}
|
||||
if (myConfig != null) {
|
||||
myConfig.clear();
|
||||
myConfig = null;
|
||||
}
|
||||
myInteraction = null;
|
||||
|
||||
Disposer.register(myProject, () -> {
|
||||
myVcs = null;
|
||||
myProject = null;
|
||||
if (myPersistentAuthenticationProviderProxy != null) {
|
||||
myPersistentAuthenticationProviderProxy.myProject = null;
|
||||
((MyKeyringMasterKeyProvider)myPersistentAuthenticationProviderProxy.myISVNGnomeKeyringPasswordProvider).myProject = null;
|
||||
myPersistentAuthenticationProviderProxy = null;
|
||||
}
|
||||
if (myInteraction instanceof MySvnAuthenticationInteraction) {
|
||||
((MySvnAuthenticationInteraction)myInteraction).myProject = null;
|
||||
}
|
||||
if (myConfig != null) {
|
||||
myConfig.clear();
|
||||
myConfig = null;
|
||||
}
|
||||
myInteraction = null;
|
||||
});
|
||||
// This is not the same instance as DefaultSVNAuthenticationManager.myProviders[1], but currently
|
||||
// DefaultSVNAuthenticationManager.CacheAuthenticationProvider uses only its outer class state - so we utilize necessary logic with
|
||||
@@ -189,7 +185,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
SVNAuthentication previousAuth, boolean authMayBeStored) {
|
||||
final SVNAuthentication authentication =
|
||||
myDelegate.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored);
|
||||
if (myProject != null && ! myProject.isDisposed()) {
|
||||
if (myProject != null && !myProject.isDisposed()) {
|
||||
myProject.getMessageBus().syncPublisher(AUTHENTICATION_PROVIDER_LISTENER)
|
||||
.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored, authentication);
|
||||
}
|
||||
@@ -202,7 +198,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
Object certificate,
|
||||
boolean resultMayBeStored) {
|
||||
final int result = myDelegate.acceptServerAuthentication(url, realm, certificate, resultMayBeStored);
|
||||
if (myProject != null && ! myProject.isDisposed()) {
|
||||
if (myProject != null && !myProject.isDisposed()) {
|
||||
myProject.getMessageBus().syncPublisher(AUTHENTICATION_PROVIDER_LISTENER)
|
||||
.acceptServerAuthentication(url, realm, certificate, resultMayBeStored, result);
|
||||
}
|
||||
@@ -212,14 +208,19 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
public interface ISVNAuthenticationProviderListener {
|
||||
void requestClientAuthentication(String kind, SVNURL url, String realm, SVNErrorMessage errorMessage,
|
||||
SVNAuthentication previousAuth, boolean authMayBeStored, SVNAuthentication authentication);
|
||||
void acceptServerAuthentication(SVNURL url, String realm, Object certificate, boolean resultMayBeStored, @MagicConstant int acceptResult);
|
||||
SVNAuthentication previousAuth, boolean authMayBeStored, SVNAuthentication authentication);
|
||||
|
||||
void acceptServerAuthentication(SVNURL url,
|
||||
String realm,
|
||||
Object certificate,
|
||||
boolean resultMayBeStored,
|
||||
@MagicConstant int acceptResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationProvider(ISVNAuthenticationProvider provider) {
|
||||
ISVNAuthenticationProvider useProvider = provider;
|
||||
if (! (provider instanceof AuthenticationProviderProxy)) {
|
||||
if (!(provider instanceof AuthenticationProviderProxy)) {
|
||||
useProvider = new AuthenticationProviderProxy(provider);
|
||||
}
|
||||
myProvider = useProvider;
|
||||
@@ -234,13 +235,13 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
/**
|
||||
* Gets authentication provider without looking into thread local storage for providers.
|
||||
*
|
||||
* <p>
|
||||
* TODO:
|
||||
* Thread local storage is used "for some interaction with SVNKit" and is not always cleared correctly. So some threads contain
|
||||
* "passive provider" in thread local storage - and getProvider() returns this "passive provider". This occurs, for instance when
|
||||
* RemoteRevisionsCache is refreshed in background - after its execution, corresponding thread has "passive provider" in thread local
|
||||
* storage.
|
||||
*
|
||||
* <p>
|
||||
* As a result authentication fails in such cases (at least for command line implementation). To fix this, command line implementation is
|
||||
* updated not to check thread local storage at all.
|
||||
*
|
||||
@@ -305,7 +306,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
@Override
|
||||
public void requested(ProviderType type, SVNURL url, String realm, String kind, boolean canceled) {
|
||||
if (ProviderType.interactive.equals(type) && (! canceled)) {
|
||||
if (ProviderType.interactive.equals(type) && (!canceled)) {
|
||||
ourJustEntered.set(true);
|
||||
}
|
||||
myListener.getMulticaster().requested(type, url, realm, kind, canceled);
|
||||
@@ -347,7 +348,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
}
|
||||
};
|
||||
ensureListenerCreated();
|
||||
myDelegate = new DefaultSVNPersistentAuthenticationProvider(authDir, userName, delegatingOptions, getDefaultOptions(), getHostOptionsProvider()) {
|
||||
myDelegate = new DefaultSVNPersistentAuthenticationProvider(authDir, userName, delegatingOptions, getDefaultOptions(),
|
||||
getHostOptionsProvider()) {
|
||||
@Override
|
||||
protected IPasswordStorage[] createPasswordStorages(DefaultSVNOptions options) {
|
||||
final IPasswordStorage[] passwordStorages = super.createPasswordStorages(options);
|
||||
@@ -366,17 +368,18 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public SVNAuthentication requestClientAuthentication(final String kind, final SVNURL url, final String realm, final SVNErrorMessage errorMessage,
|
||||
final SVNAuthentication previousAuth, final boolean authMayBeStored) {
|
||||
public SVNAuthentication requestClientAuthentication(final String kind,
|
||||
final SVNURL url,
|
||||
final String realm,
|
||||
final SVNErrorMessage errorMessage,
|
||||
final SVNAuthentication previousAuth,
|
||||
final boolean authMayBeStored) {
|
||||
try {
|
||||
return wrapNativeCall(new ThrowableComputable<SVNAuthentication, SVNException>() {
|
||||
@Override
|
||||
public SVNAuthentication compute() throws SVNException {
|
||||
final SVNAuthentication svnAuthentication =
|
||||
myDelegate.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored);
|
||||
myListener.getMulticaster().requested(ProviderType.persistent, url, realm, kind, svnAuthentication == null);
|
||||
return svnAuthentication;
|
||||
}
|
||||
return wrapNativeCall(() -> {
|
||||
final SVNAuthentication svnAuthentication =
|
||||
myDelegate.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored);
|
||||
myListener.getMulticaster().requested(ProviderType.persistent, url, realm, kind, svnAuthentication == null);
|
||||
return svnAuthentication;
|
||||
});
|
||||
}
|
||||
catch (SVNException e) {
|
||||
@@ -391,41 +394,39 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
private void actualSavePermissions(String realm, SVNAuthentication auth) {
|
||||
final String actualKind = auth.getKind();
|
||||
File dir = new File(myAuthDir, actualKind);
|
||||
String fileName = SVNFileUtil.computeChecksum(realm);
|
||||
File authFile = new File(dir, fileName);
|
||||
File dir = new File(myAuthDir, actualKind);
|
||||
String fileName = SVNFileUtil.computeChecksum(realm);
|
||||
File authFile = new File(dir, fileName);
|
||||
|
||||
try {
|
||||
((ISVNPersistentAuthenticationProvider) myDelegate).saveAuthentication(auth, actualKind, realm);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
if (myProject != null) {
|
||||
ApplicationManager.getApplication().invokeLater(new VcsBalloonProblemNotifier(myProject,
|
||||
"<b>Problem when storing Subversion credentials:</b> " + e.getMessage(), MessageType.ERROR));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// do not make password file readonly
|
||||
setWriteable(authFile);
|
||||
}
|
||||
try {
|
||||
((ISVNPersistentAuthenticationProvider)myDelegate).saveAuthentication(auth, actualKind, realm);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
if (myProject != null) {
|
||||
ApplicationManager.getApplication().invokeLater(new VcsBalloonProblemNotifier(myProject,
|
||||
"<b>Problem when storing Subversion credentials:</b> " +
|
||||
e.getMessage(), MessageType.ERROR));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// do not make password file readonly
|
||||
setWriteable(authFile);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAuthentication(final SVNAuthentication auth, final String kind, final String realm) throws SVNException {
|
||||
try {
|
||||
wrapNativeCall(new ThrowableComputable<Void, SVNException>() {
|
||||
@Override
|
||||
public Void compute() throws SVNException {
|
||||
final Boolean fromInteractive = ourJustEntered.get();
|
||||
ourJustEntered.set(null);
|
||||
if (! myArtificialSaving && ! Boolean.TRUE.equals(fromInteractive)) {
|
||||
// not what user entered
|
||||
return null;
|
||||
}
|
||||
myListener.getMulticaster().saveAttemptStarted(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
|
||||
((ISVNPersistentAuthenticationProvider) myDelegate).saveAuthentication(auth, kind, realm);
|
||||
myListener.getMulticaster().saveAttemptFinished(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
|
||||
wrapNativeCall(() -> {
|
||||
final Boolean fromInteractive = ourJustEntered.get();
|
||||
ourJustEntered.set(null);
|
||||
if (!myArtificialSaving && !Boolean.TRUE.equals(fromInteractive)) {
|
||||
// not what user entered
|
||||
return null;
|
||||
}
|
||||
myListener.getMulticaster().saveAttemptStarted(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
|
||||
((ISVNPersistentAuthenticationProvider)myDelegate).saveAuthentication(auth, kind, realm);
|
||||
myListener.getMulticaster().saveAttemptFinished(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (SVNException e) {
|
||||
@@ -437,12 +438,9 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
@Override
|
||||
public void saveFingerprints(final String realm, final byte[] fingerprints) {
|
||||
try {
|
||||
wrapNativeCall(new ThrowableComputable<Void, SVNException>() {
|
||||
@Override
|
||||
public Void compute() throws SVNException {
|
||||
((ISVNPersistentAuthenticationProvider) myDelegate).saveFingerprints(realm, fingerprints);
|
||||
return null;
|
||||
}
|
||||
wrapNativeCall(() -> {
|
||||
((ISVNPersistentAuthenticationProvider)myDelegate).saveFingerprints(realm, fingerprints);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (SVNException e) {
|
||||
@@ -454,12 +452,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
@Override
|
||||
public byte[] loadFingerprints(final String realm) {
|
||||
try {
|
||||
return wrapNativeCall(new ThrowableComputable<byte[], SVNException>() {
|
||||
@Override
|
||||
public byte[] compute() throws SVNException {
|
||||
return ((ISVNPersistentAuthenticationProvider) myDelegate).loadFingerprints(realm);
|
||||
}
|
||||
});
|
||||
return wrapNativeCall(() -> ((ISVNPersistentAuthenticationProvider)myDelegate).loadFingerprints(realm));
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
@@ -468,8 +461,9 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
}
|
||||
|
||||
private final static int maxAttempts = 10;
|
||||
|
||||
private void setWriteable(final File file) {
|
||||
if (! file.exists()) return;
|
||||
if (!file.exists()) return;
|
||||
if (file.getParentFile() == null) {
|
||||
return;
|
||||
}
|
||||
@@ -478,8 +472,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
try {
|
||||
final File tempFile = FileUtil.createTempFile(parent, "123", "1", true);
|
||||
FileUtil.delete(tempFile);
|
||||
if (! file.renameTo(tempFile)) continue;
|
||||
if (! file.createNewFile()) continue;
|
||||
if (!file.renameTo(tempFile)) continue;
|
||||
if (!file.createNewFile()) continue;
|
||||
FileUtil.copy(tempFile, file);
|
||||
FileUtil.delete(tempFile);
|
||||
return;
|
||||
@@ -496,7 +490,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
myKeyAlgorithm.put(Thread.currentThread(), keyAlgorithm);
|
||||
try {
|
||||
super.verifyHostKey(hostName, port, keyAlgorithm, hostKey);
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
myKeyAlgorithm.remove(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
@@ -543,7 +538,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
final SVNAuthentication proxy = ProxySvnAuthentication.proxy(authentication, authStorageEnabled, myArtificialSaving);
|
||||
super.acknowledgeAuthentication(accepted, kind, realm, errorMessage, proxy);
|
||||
successSaving = true;
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
mySavePermissions.remove();
|
||||
if (myArtificialSaving) {
|
||||
myArtificialSaving = false;
|
||||
@@ -569,7 +565,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
}
|
||||
|
||||
public void acknowledgeForSSL(boolean accepted, SVNAuthentication proxy) {
|
||||
if (accepted && proxy instanceof SVNSSLAuthentication && (((SVNSSLAuthentication) proxy).getCertificateFile() != null)) {
|
||||
if (accepted && proxy instanceof SVNSSLAuthentication && (((SVNSSLAuthentication)proxy).getCertificateFile() != null)) {
|
||||
final SVNSSLAuthentication svnsslAuthentication = (SVNSSLAuthentication)proxy;
|
||||
final SVNURL url = svnsslAuthentication.getURL();
|
||||
|
||||
@@ -603,7 +599,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
// ! use common proxy if it is set
|
||||
try {
|
||||
final List<Proxy> proxies = HttpConfigurable.getInstance().getOnlyBySettingsSelector().select(new URI(url.toString()));
|
||||
if (proxies != null && ! proxies.isEmpty()) {
|
||||
if (proxies != null && !proxies.isEmpty()) {
|
||||
for (Proxy proxy : proxies) {
|
||||
if (HttpConfigurable.isRealProxy(proxy) && Proxy.Type.HTTP.equals(proxy.type())) {
|
||||
final SocketAddress address = proxy.address();
|
||||
@@ -624,15 +620,15 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
String proxyExceptions = getServersPropertyIdea(host, "http-proxy-exceptions");
|
||||
String proxyExceptionsSeparator = ",";
|
||||
if (proxyExceptions == null) {
|
||||
proxyExceptions = System.getProperty("http.nonProxyHosts");
|
||||
proxyExceptionsSeparator = "|";
|
||||
proxyExceptions = System.getProperty("http.nonProxyHosts");
|
||||
proxyExceptionsSeparator = "|";
|
||||
}
|
||||
if (proxyExceptions != null) {
|
||||
for(StringTokenizer exceptions = new StringTokenizer(proxyExceptions, proxyExceptionsSeparator); exceptions.hasMoreTokens();) {
|
||||
String exception = exceptions.nextToken().trim();
|
||||
if (DefaultSVNOptions.matches(exception, host)) {
|
||||
return null;
|
||||
}
|
||||
for (StringTokenizer exceptions = new StringTokenizer(proxyExceptions, proxyExceptionsSeparator); exceptions.hasMoreTokens(); ) {
|
||||
String exception = exceptions.nextToken().trim();
|
||||
if (DefaultSVNOptions.matches(exception, host)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
String proxyPort = getServersPropertyIdea(host, HTTP_PROXY_PORT);
|
||||
@@ -687,41 +683,42 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
}
|
||||
|
||||
private static class MySimpleProxyManager implements ISVNProxyManager {
|
||||
protected String myProxyHost;
|
||||
private final String myProxyPort;
|
||||
protected String myProxyUser;
|
||||
protected String myProxyPassword;
|
||||
protected String myProxyHost;
|
||||
private final String myProxyPort;
|
||||
protected String myProxyUser;
|
||||
protected String myProxyPassword;
|
||||
|
||||
public MySimpleProxyManager(String host, String port, String user, String password) {
|
||||
myProxyHost = host;
|
||||
myProxyPort = port == null ? "3128" : port;
|
||||
myProxyUser = user;
|
||||
myProxyPassword = password;
|
||||
}
|
||||
public MySimpleProxyManager(String host, String port, String user, String password) {
|
||||
myProxyHost = host;
|
||||
myProxyPort = port == null ? "3128" : port;
|
||||
myProxyUser = user;
|
||||
myProxyPassword = password;
|
||||
}
|
||||
|
||||
public String getProxyHost() {
|
||||
return myProxyHost;
|
||||
}
|
||||
public String getProxyHost() {
|
||||
return myProxyHost;
|
||||
}
|
||||
|
||||
public int getProxyPort() {
|
||||
try {
|
||||
return Integer.parseInt(myProxyPort);
|
||||
} catch (NumberFormatException nfe) {
|
||||
//
|
||||
}
|
||||
return 3128;
|
||||
public int getProxyPort() {
|
||||
try {
|
||||
return Integer.parseInt(myProxyPort);
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
//
|
||||
}
|
||||
return 3128;
|
||||
}
|
||||
|
||||
public String getProxyUserName() {
|
||||
return myProxyUser;
|
||||
}
|
||||
public String getProxyUserName() {
|
||||
return myProxyUser;
|
||||
}
|
||||
|
||||
public String getProxyPassword() {
|
||||
return myProxyPassword;
|
||||
}
|
||||
public String getProxyPassword() {
|
||||
return myProxyPassword;
|
||||
}
|
||||
|
||||
public void acknowledgeProxyContext(boolean accepted, SVNErrorMessage errorMessage) {
|
||||
}
|
||||
public void acknowledgeProxyContext(boolean accepted, SVNErrorMessage errorMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
// 30 seconds
|
||||
@@ -786,7 +783,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
}
|
||||
}
|
||||
Map globalProps = serversFile.getProperties("global");
|
||||
return (String) globalProps.get(name);
|
||||
return (String)globalProps.get(name);
|
||||
}
|
||||
|
||||
public static boolean checkHostGroup(final String url, final String patterns, final String exceptions) {
|
||||
@@ -799,15 +796,15 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
}
|
||||
|
||||
final String host = svnurl.getHost();
|
||||
return matches(patterns, host) && (! matches(exceptions, host));
|
||||
return matches(patterns, host) && (!matches(exceptions, host));
|
||||
}
|
||||
|
||||
private static boolean matches(final String pattern, final String host) {
|
||||
final StringTokenizer tokenizer = new StringTokenizer(pattern, ",");
|
||||
while(tokenizer.hasMoreTokens()) {
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String token = tokenizer.nextToken();
|
||||
if (DefaultSVNOptions.matches(token, host)) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -815,7 +812,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
@Nullable
|
||||
public static String getGroupForHost(final String host, final IdeaSVNConfigFile serversFile) {
|
||||
final Map<String,ProxyGroup> groups = serversFile.getAllGroups();
|
||||
final Map<String, ProxyGroup> groups = serversFile.getAllGroups();
|
||||
for (Map.Entry<String, ProxyGroup> entry : groups.entrySet()) {
|
||||
if (matchesGroupPattern(host, entry.getValue().getPatterns())) return entry.getKey();
|
||||
}
|
||||
@@ -825,19 +822,19 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
// taken from default manager as is
|
||||
private static String getGroupName(Map groups, String host) {
|
||||
for (Object o : groups.keySet()) {
|
||||
final String name = (String) o;
|
||||
final String pattern = (String) groups.get(name);
|
||||
final String name = (String)o;
|
||||
final String pattern = (String)groups.get(name);
|
||||
if (matchesGroupPattern(host, pattern)) return name;
|
||||
}
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean matchesGroupPattern(String host, String pattern) {
|
||||
for(StringTokenizer tokens = new StringTokenizer(pattern, ","); tokens.hasMoreTokens();) {
|
||||
String token = tokens.nextToken();
|
||||
if (DefaultSVNOptions.matches(token, host)) {
|
||||
return true;
|
||||
}
|
||||
for (StringTokenizer tokens = new StringTokenizer(pattern, ","); tokens.hasMoreTokens(); ) {
|
||||
String token = tokens.nextToken();
|
||||
if (DefaultSVNOptions.matches(token, host)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -871,24 +868,28 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
@Override
|
||||
public void warnOnAuthStorageDisabled(SVNURL url) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store credentials: forbidden by \"store-auth-creds=no\"", MessageType.ERROR);
|
||||
VcsBalloonProblemNotifier
|
||||
.showOverChangesView(myProject, "Cannot store credentials: forbidden by \"store-auth-creds=no\"", MessageType.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warnOnPasswordStorageDisabled(SVNURL url) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store password: forbidden by \"store-passwords=no\"", MessageType.ERROR);
|
||||
VcsBalloonProblemNotifier
|
||||
.showOverChangesView(myProject, "Cannot store password: forbidden by \"store-passwords=no\"", MessageType.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warnOnSSLPassphraseStorageDisabled(SVNURL url) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store passphrase: forbidden by \"store-ssl-client-cert-pp=no\"", MessageType.ERROR);
|
||||
VcsBalloonProblemNotifier
|
||||
.showOverChangesView(myProject, "Cannot store passphrase: forbidden by \"store-ssl-client-cert-pp=no\"", MessageType.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean promptForPlaintextPasswordSaving(SVNURL url, String realm) {
|
||||
final int answer = Messages.showYesNoDialog(myProject, String.format("Your password for authentication realm:\n" +
|
||||
"%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?", realm),
|
||||
"Store the password in plaintext?", Messages.getQuestionIcon());
|
||||
"%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?",
|
||||
realm),
|
||||
"Store the password in plaintext?", Messages.getQuestionIcon());
|
||||
return answer == Messages.YES;
|
||||
}
|
||||
|
||||
@@ -900,9 +901,11 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
@Override
|
||||
public boolean promptForSSLPlaintextPassphraseSaving(SVNURL url, String realm, File certificateFile, String certificateName) {
|
||||
final int answer = Messages.showYesNoDialog(myProject,
|
||||
String.format("Your passphrase for " + certificateName + ":\n%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?",
|
||||
certificateFile.getPath()),
|
||||
"Store the passphrase in plaintext?", Messages.getQuestionIcon());
|
||||
String.format("Your passphrase for " +
|
||||
certificateName +
|
||||
":\n%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?",
|
||||
certificateFile.getPath()),
|
||||
"Store the passphrase in plaintext?", Messages.getQuestionIcon());
|
||||
return answer == Messages.YES;
|
||||
}
|
||||
|
||||
@@ -967,13 +970,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
final boolean superValue = super.isStorePlainTextPasswords(realm, auth);
|
||||
final boolean value = mySavePermissions.allowed() || superValue;
|
||||
if ((! value) && (! mySavePermissions.have())) {
|
||||
promptAndSaveWhenWeLackEncryption(realm, auth, new Getter<Boolean>() {
|
||||
@Override
|
||||
public Boolean get() {
|
||||
return myInteraction.promptForPlaintextPasswordSaving(myUrl, realm);
|
||||
}
|
||||
});
|
||||
if ((!value) && (!mySavePermissions.have())) {
|
||||
promptAndSaveWhenWeLackEncryption(realm, auth, () -> myInteraction.promptForPlaintextPasswordSaving(myUrl, realm));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -983,25 +981,24 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
if (USERNAME.equals(auth.getKind())) return true;
|
||||
|
||||
final boolean value = mySavePermissions.allowed() || super.isStorePlainTextPassphrases(realm, auth);
|
||||
if ((! value) && (! mySavePermissions.have())) {
|
||||
promptAndSaveWhenWeLackEncryption(realm, auth, new Getter<Boolean>() {
|
||||
@Override
|
||||
public Boolean get() {
|
||||
File file = null;
|
||||
String certificateName = null;
|
||||
if (auth instanceof SVNSSLAuthentication) {
|
||||
file = ((SVNSSLAuthentication) auth).getCertificateFile();
|
||||
certificateName = "client certificate";
|
||||
} else if (auth instanceof SVNSSHAuthentication) {
|
||||
file = ((SVNSSHAuthentication) auth).getPrivateKeyFile();
|
||||
certificateName = "private key file";
|
||||
} else {
|
||||
assert false;
|
||||
}
|
||||
return myInteraction.promptForSSLPlaintextPassphraseSaving(myUrl, realm,
|
||||
file, certificateName);
|
||||
}
|
||||
});
|
||||
if ((!value) && (!mySavePermissions.have())) {
|
||||
promptAndSaveWhenWeLackEncryption(realm, auth, () -> {
|
||||
File file = null;
|
||||
String certificateName = null;
|
||||
if (auth instanceof SVNSSLAuthentication) {
|
||||
file = ((SVNSSLAuthentication)auth).getCertificateFile();
|
||||
certificateName = "client certificate";
|
||||
}
|
||||
else if (auth instanceof SVNSSHAuthentication) {
|
||||
file = ((SVNSSHAuthentication)auth).getPrivateKeyFile();
|
||||
certificateName = "private key file";
|
||||
}
|
||||
else {
|
||||
assert false;
|
||||
}
|
||||
return myInteraction.promptForSSLPlaintextPassphraseSaving(myUrl, realm,
|
||||
file, certificateName);
|
||||
});
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -1011,10 +1008,11 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
final boolean value;
|
||||
if (hasAuthStorageEnabledOption()) {
|
||||
value = super.isAuthStorageEnabled();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
value = isTurned(getConfigFile().getPropertyValue("auth", "store-auth-creds"));
|
||||
}
|
||||
if (! value) {
|
||||
if (!value) {
|
||||
myInteraction.warnOnAuthStorageDisabled(myUrl);
|
||||
}
|
||||
return value;
|
||||
@@ -1026,11 +1024,12 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
final boolean value;
|
||||
if (storePasswords != null) {
|
||||
value = isTurned(storePasswords);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
final String configValue = getConfigFile().getPropertyValue("auth", "store-passwords");
|
||||
value = isTurned(configValue);
|
||||
}
|
||||
if (! value) {
|
||||
if (!value) {
|
||||
myInteraction.warnOnPasswordStorageDisabled(myUrl);
|
||||
}
|
||||
return value;
|
||||
@@ -1039,7 +1038,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
@Override
|
||||
public boolean isStoreSSLClientCertificatePassphrases() {
|
||||
final boolean value = super.isStoreSSLClientCertificatePassphrases();
|
||||
if (! value) {
|
||||
if (!value) {
|
||||
myInteraction.warnOnSSLPassphraseStorageDisabled(myUrl);
|
||||
}
|
||||
return value;
|
||||
@@ -1062,16 +1061,13 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
|
||||
private void promptAndSaveWhenWeLackEncryption(final String realm, final SVNAuthentication auth, final Getter<Boolean> prompt) {
|
||||
final Boolean[] saveOnce = new Boolean[1];
|
||||
final Runnable actualSave = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mySavePermissions.put(Boolean.TRUE.equals(saveOnce[0]));
|
||||
try {
|
||||
myPersistentAuthenticationProviderProxy.actualSavePermissions(realm, auth);
|
||||
}
|
||||
finally {
|
||||
mySavePermissions.remove();
|
||||
}
|
||||
final Runnable actualSave = () -> {
|
||||
mySavePermissions.put(Boolean.TRUE.equals(saveOnce[0]));
|
||||
try {
|
||||
myPersistentAuthenticationProviderProxy.actualSavePermissions(realm, auth);
|
||||
}
|
||||
finally {
|
||||
mySavePermissions.remove();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1080,7 +1076,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
saveOnce[0] = Boolean.TRUE.equals(prompt.get());
|
||||
ApplicationManager.getApplication().executeOnPooledThread(actualSave);
|
||||
}, getCurrent(), myProject);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
saveOnce[0] = Boolean.TRUE.equals(prompt.get());
|
||||
actualSave.run();
|
||||
}
|
||||
@@ -1152,7 +1149,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
LOG.info(sb.toString());
|
||||
}
|
||||
return t;
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
NativeLogReader.clear();
|
||||
NativeLogReader.endTracking();
|
||||
}
|
||||
@@ -1170,12 +1168,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
|
||||
final String message = keyringName != null ? SvnBundle.message("gnome.keyring.prompt.named", keyringName)
|
||||
: SvnBundle.message("gnome.keyring.prompt.nameless");
|
||||
final Ref<String> result = Ref.create();
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
result.set(Messages.showPasswordDialog(myProject, message, SvnBundle.message("subversion.name"), Messages.getQuestionIcon()));
|
||||
}
|
||||
});
|
||||
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> result
|
||||
.set(Messages.showPasswordDialog(myProject, message, SvnBundle.message("subversion.name"), Messages.getQuestionIcon())));
|
||||
return !result.isNull() ? result.get().toCharArray() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.ex.WindowManagerEx;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.net.HttpConfigurable;
|
||||
import com.intellij.util.proxy.CommonProxy;
|
||||
@@ -62,7 +61,6 @@ import org.tmatesoft.svn.core.wc2.SvnTarget;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
@@ -112,22 +110,19 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
|
||||
|
||||
final Ref<Boolean> resultRef = new Ref<>();
|
||||
|
||||
final Runnable checker = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final boolean result =
|
||||
interactiveValidation(obj.myProject, obj.getUrl(), obj.getRealm(), obj.getKind());
|
||||
log("ask result for: " + obj.getUrl() + " is: " + result);
|
||||
resultRef.set(result);
|
||||
if (result) {
|
||||
onStateChangedToSuccess(obj);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myVerificationInProgress = false;
|
||||
final Runnable checker = () -> {
|
||||
try {
|
||||
final boolean result =
|
||||
interactiveValidation(obj.myProject, obj.getUrl(), obj.getRealm(), obj.getKind());
|
||||
log("ask result for: " + obj.getUrl() + " is: " + result);
|
||||
resultRef.set(result);
|
||||
if (result) {
|
||||
onStateChangedToSuccess(obj);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myVerificationInProgress = false;
|
||||
}
|
||||
};
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
// also do not show auth if thread does not have progress indicator
|
||||
@@ -173,12 +168,9 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
|
||||
}
|
||||
}
|
||||
log("on state changed ");
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (SVNURL key : outdatedRequests) {
|
||||
removeLazyNotificationByKey(key);
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
for (SVNURL key : outdatedRequests) {
|
||||
removeLazyNotificationByKey(key);
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
@@ -428,35 +420,23 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
|
||||
private static void showAuthenticationFailedWithHotFixes(final Project project,
|
||||
final SvnConfiguration configuration,
|
||||
final SVNException e) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(project, "Authentication failed: " + e.getMessage(), MessageType.ERROR,
|
||||
new NamedRunnable(
|
||||
SvnBundle.message("confirmation.title.clear.authentication.cache")) {
|
||||
@Override
|
||||
public void run() {
|
||||
clearAuthenticationCache(project, null, configuration
|
||||
.getConfigurationDirectory());
|
||||
}
|
||||
},
|
||||
new NamedRunnable(SvnBundle.message("action.title.select.configuration.directory")) {
|
||||
@Override
|
||||
public void run() {
|
||||
SvnConfigurable
|
||||
.selectConfigurationDirectory(configuration.getConfigurationDirectory(),
|
||||
new Consumer<String>() {
|
||||
@Override
|
||||
public void consume(String s) {
|
||||
configuration
|
||||
.setConfigurationDirParameters(false, s);
|
||||
}
|
||||
}, project, null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}, ModalityState.NON_MODAL, project.getDisposed());
|
||||
ApplicationManager.getApplication().invokeLater(() -> VcsBalloonProblemNotifier
|
||||
.showOverChangesView(project, "Authentication failed: " + e.getMessage(), MessageType.ERROR, new NamedRunnable(
|
||||
SvnBundle.message("confirmation.title.clear.authentication.cache")) {
|
||||
@Override
|
||||
public void run() {
|
||||
clearAuthenticationCache(project, null, configuration
|
||||
.getConfigurationDirectory());
|
||||
}
|
||||
}, new NamedRunnable(
|
||||
SvnBundle.message("action.title.select.configuration.directory")) {
|
||||
@Override
|
||||
public void run() {
|
||||
SvnConfigurable.selectConfigurationDirectory(configuration.getConfigurationDirectory(),
|
||||
s -> configuration.setConfigurationDirParameters(false, s), project, null);
|
||||
}
|
||||
}
|
||||
), ModalityState.NON_MODAL, project.getDisposed());
|
||||
}
|
||||
|
||||
public static void clearAuthenticationCache(@NotNull final Project project, final Component component, final String configDirPath) {
|
||||
@@ -481,27 +461,19 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
|
||||
public static void clearAuthenticationDirectory(@NotNull SvnConfiguration configuration) {
|
||||
final File authDir = new File(configuration.getConfigurationDirectory(), "auth");
|
||||
if (authDir.exists()) {
|
||||
final Runnable process = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final ProgressIndicator ind = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (ind != null) {
|
||||
ind.setIndeterminate(true);
|
||||
ind.setText("Clearing stored credentials in " + authDir.getAbsolutePath());
|
||||
}
|
||||
final File[] files = authDir.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(@NotNull File dir, @NotNull String name) {
|
||||
return ourAuthKinds.contains(name);
|
||||
}
|
||||
});
|
||||
final Runnable process = () -> {
|
||||
final ProgressIndicator ind = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (ind != null) {
|
||||
ind.setIndeterminate(true);
|
||||
ind.setText("Clearing stored credentials in " + authDir.getAbsolutePath());
|
||||
}
|
||||
final File[] files = authDir.listFiles((dir, name) -> ourAuthKinds.contains(name));
|
||||
|
||||
for (File dir : files) {
|
||||
if (ind != null) {
|
||||
ind.setText("Deleting " + dir.getAbsolutePath());
|
||||
}
|
||||
FileUtil.delete(dir);
|
||||
for (File dir : files) {
|
||||
if (ind != null) {
|
||||
ind.setText("Deleting " + dir.getAbsolutePath());
|
||||
}
|
||||
FileUtil.delete(dir);
|
||||
}
|
||||
};
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
|
||||
+53
-66
@@ -85,14 +85,12 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
|
||||
final String userName =
|
||||
previousAuth != null && previousAuth.getUserName() != null ? previousAuth.getUserName() : myManager.getDefaultUsername(kind, url);
|
||||
if (ISVNAuthenticationManager.PASSWORD.equals(kind)) {// || ISVNAuthenticationManager.USERNAME.equals(kind)) {
|
||||
command = new Runnable() {
|
||||
public void run() {
|
||||
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myProject);
|
||||
dialog.setup(realm, userName, authCredsOn);
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
result[0] = new SVNPasswordAuthentication(dialog.getUserName(), dialog.getPassword(), dialog.isSaveAllowed(), url, false);
|
||||
}
|
||||
command = () -> {
|
||||
SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(myProject);
|
||||
dialog.setup(realm, userName, authCredsOn);
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
result[0] = new SVNPasswordAuthentication(dialog.getUserName(), dialog.getPassword(), dialog.isSaveAllowed(), url, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -100,14 +98,12 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return new SVNUserNameAuthentication(userName, false);
|
||||
}
|
||||
command = new Runnable() {
|
||||
public void run() {
|
||||
UserNameCredentialsDialog dialog = new UserNameCredentialsDialog(myProject);
|
||||
dialog.setup(realm, userName, authCredsOn);
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
result[0] = new SVNUserNameAuthentication(dialog.getUserName(), dialog.isSaveAllowed(), url, false);
|
||||
}
|
||||
command = () -> {
|
||||
UserNameCredentialsDialog dialog = new UserNameCredentialsDialog(myProject);
|
||||
dialog.setup(realm, userName, authCredsOn);
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
result[0] = new SVNUserNameAuthentication(dialog.getUserName(), dialog.isSaveAllowed(), url, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -117,47 +113,43 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
|
||||
final Connector agentConnector = createSshAgentConnector();
|
||||
final boolean isAgentAvailable = agentConnector != null && agentConnector.isAvailable();
|
||||
|
||||
command = new Runnable() {
|
||||
public void run() {
|
||||
SSHCredentialsDialog dialog = new SSHCredentialsDialog(myProject, realm, userName, authCredsOn, url.getPort(), isAgentAvailable);
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
int port = dialog.getPortNumber();
|
||||
if (dialog.isSshAgentSelected()) {
|
||||
if (agentConnector != null) {
|
||||
result[0] =
|
||||
new SVNSSHAuthentication(dialog.getUserName(), new TrileadAgentProxy(agentConnector), port, url, false);
|
||||
}
|
||||
}
|
||||
else if (dialog.getKeyFile() != null && dialog.getKeyFile().trim().length() > 0) {
|
||||
String passphrase = dialog.getPassphrase();
|
||||
if (passphrase != null && passphrase.length() == 0) {
|
||||
passphrase = null;
|
||||
}
|
||||
command = () -> {
|
||||
SSHCredentialsDialog dialog = new SSHCredentialsDialog(myProject, realm, userName, authCredsOn, url.getPort(), isAgentAvailable);
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
int port = dialog.getPortNumber();
|
||||
if (dialog.isSshAgentSelected()) {
|
||||
if (agentConnector != null) {
|
||||
result[0] =
|
||||
new SVNSSHAuthentication(dialog.getUserName(), new File(dialog.getKeyFile()), passphrase, port, dialog.isSaveAllowed(), url,
|
||||
false);
|
||||
new SVNSSHAuthentication(dialog.getUserName(), new TrileadAgentProxy(agentConnector), port, url, false);
|
||||
}
|
||||
else {
|
||||
result[0] = new SVNSSHAuthentication(dialog.getUserName(), dialog.getPassword(), port, dialog.isSaveAllowed(), url, false);
|
||||
}
|
||||
else if (dialog.getKeyFile() != null && dialog.getKeyFile().trim().length() > 0) {
|
||||
String passphrase = dialog.getPassphrase();
|
||||
if (passphrase != null && passphrase.length() == 0) {
|
||||
passphrase = null;
|
||||
}
|
||||
result[0] =
|
||||
new SVNSSHAuthentication(dialog.getUserName(), new File(dialog.getKeyFile()), passphrase, port, dialog.isSaveAllowed(), url,
|
||||
false);
|
||||
}
|
||||
else {
|
||||
result[0] = new SVNSSHAuthentication(dialog.getUserName(), dialog.getPassword(), port, dialog.isSaveAllowed(), url, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if (ISVNAuthenticationManager.SSL.equals(kind)) {
|
||||
command = new Runnable() {
|
||||
public void run() {
|
||||
final ISVNHostOptions options = myManager.getHostOptionsProvider().getHostOptions(url);
|
||||
final String file = options.getSSLClientCertFile();
|
||||
final SSLCredentialsDialog dialog = new SSLCredentialsDialog(myProject, realm, authCredsOn);
|
||||
if (!StringUtil.isEmptyOrSpaces(file)) {
|
||||
dialog.setFile(file);
|
||||
}
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
result[0] = new SVNSSLAuthentication(new File(dialog.getCertificatePath()), String.valueOf(dialog.getCertificatePassword()),
|
||||
dialog.getSaveAuth(), url, false);
|
||||
}
|
||||
command = () -> {
|
||||
final ISVNHostOptions options = myManager.getHostOptionsProvider().getHostOptions(url);
|
||||
final String file = options.getSSLClientCertFile();
|
||||
final SSLCredentialsDialog dialog = new SSLCredentialsDialog(myProject, realm, authCredsOn);
|
||||
if (!StringUtil.isEmptyOrSpaces(file)) {
|
||||
dialog.setFile(file);
|
||||
}
|
||||
setTitle(dialog, errorMessage);
|
||||
if (dialog.showAndGet()) {
|
||||
result[0] = new SVNSSLAuthentication(new File(dialog.getCertificatePath()), String.valueOf(dialog.getCertificatePassword()),
|
||||
dialog.getSaveAuth(), url, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -197,25 +189,20 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP
|
||||
final int[] result = new int[1];
|
||||
Runnable command;
|
||||
if (certificate instanceof X509Certificate || certificate instanceof String) {
|
||||
command = new Runnable() {
|
||||
public void run() {
|
||||
ServerSSLDialog dialog = certificate instanceof X509Certificate
|
||||
? new ServerSSLDialog(myProject, (X509Certificate)certificate, resultMayBeStored)
|
||||
: new ServerSSLDialog(myProject, (String)certificate, resultMayBeStored);
|
||||
dialog.show();
|
||||
result[0] = dialog.getResult();
|
||||
}
|
||||
command = () -> {
|
||||
ServerSSLDialog dialog = certificate instanceof X509Certificate
|
||||
? new ServerSSLDialog(myProject, (X509Certificate)certificate, resultMayBeStored)
|
||||
: new ServerSSLDialog(myProject, (String)certificate, resultMayBeStored);
|
||||
dialog.show();
|
||||
result[0] = dialog.getResult();
|
||||
};
|
||||
} else if (certificate instanceof byte[]) {
|
||||
final String sshKeyAlgorithm = myManager.getSSHKeyAlgorithm();
|
||||
command = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final ServerSSHDialog serverSSHDialog =
|
||||
new ServerSSHDialog(myProject, resultMayBeStored, url.toDecodedString(), sshKeyAlgorithm, (byte[])certificate);
|
||||
serverSSHDialog.show();
|
||||
result[0] = serverSSHDialog.getResult();
|
||||
}
|
||||
command = () -> {
|
||||
final ServerSSHDialog serverSSHDialog =
|
||||
new ServerSSHDialog(myProject, resultMayBeStored, url.toDecodedString(), sshKeyAlgorithm, (byte[])certificate);
|
||||
serverSSHDialog.show();
|
||||
result[0] = serverSSHDialog.getResult();
|
||||
};
|
||||
} else {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Subversion: unknown certificate type from " + url.toDecodedString(),
|
||||
|
||||
+10
-13
@@ -122,19 +122,16 @@ public class BranchConfigurationDialog extends DialogWrapper {
|
||||
}
|
||||
}
|
||||
})
|
||||
.setRemoveAction(new AnActionButtonRunnable() {
|
||||
@Override
|
||||
public void run(AnActionButton button) {
|
||||
int selectedIndex = myBranchLocationsList.getSelectedIndex();
|
||||
for (String url : myBranchLocationsList.getSelectedValuesList()) {
|
||||
int index = myBranchLocationsModel.getConfiguration().getBranchUrls().indexOf(url);
|
||||
myBranchLocationsModel.getConfiguration().removeBranch(url);
|
||||
myBranchLocationsModel.fireItemRemoved(index);
|
||||
}
|
||||
if (myBranchLocationsModel.getSize() > 0) {
|
||||
selectedIndex = min(selectedIndex, myBranchLocationsModel.getSize() - 1);
|
||||
myBranchLocationsList.setSelectedIndex(selectedIndex);
|
||||
}
|
||||
.setRemoveAction(button -> {
|
||||
int selectedIndex = myBranchLocationsList.getSelectedIndex();
|
||||
for (String url : myBranchLocationsList.getSelectedValuesList()) {
|
||||
int index = myBranchLocationsModel.getConfiguration().getBranchUrls().indexOf(url);
|
||||
myBranchLocationsModel.getConfiguration().removeBranch(url);
|
||||
myBranchLocationsModel.fireItemRemoved(index);
|
||||
}
|
||||
if (myBranchLocationsModel.getSize() > 0) {
|
||||
selectedIndex = min(selectedIndex, myBranchLocationsModel.getSize() - 1);
|
||||
myBranchLocationsList.setSelectedIndex(selectedIndex);
|
||||
}
|
||||
})
|
||||
.disableUpDownActions()
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.svn.SvnVcs;
|
||||
import org.jetbrains.idea.svn.api.Depth;
|
||||
import org.jetbrains.idea.svn.browse.BrowseClient;
|
||||
import org.jetbrains.idea.svn.browse.DirectoryEntry;
|
||||
import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
@@ -93,13 +92,9 @@ public class BranchesLoader implements Runnable {
|
||||
|
||||
@NotNull
|
||||
private static DirectoryEntryConsumer createConsumer(@NotNull final List<SvnBranchItem> result) {
|
||||
return new DirectoryEntryConsumer() {
|
||||
|
||||
@Override
|
||||
public void consume(final DirectoryEntry entry) throws SVNException {
|
||||
if (entry.getDate() != null) {
|
||||
result.add(new SvnBranchItem(entry.getUrl().toDecodedString(), entry.getDate(), entry.getRevision()));
|
||||
}
|
||||
return entry -> {
|
||||
if (entry.getDate() != null) {
|
||||
result.add(new SvnBranchItem(entry.getUrl().toDecodedString(), entry.getDate(), entry.getRevision()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+23
-50
@@ -45,11 +45,8 @@ import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
|
||||
@@ -109,12 +106,10 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
|
||||
updateControls();
|
||||
}
|
||||
});
|
||||
myRepositoryField.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
SVNURL url = SelectLocationDialog.selectLocation(project, mySrcURL);
|
||||
if (url != null) {
|
||||
myRepositoryField.setText(url.toString());
|
||||
}
|
||||
myRepositoryField.addActionListener(e -> {
|
||||
SVNURL url = SelectLocationDialog.selectLocation(project, mySrcURL);
|
||||
if (url != null) {
|
||||
myRepositoryField.setText(url.toString());
|
||||
}
|
||||
});
|
||||
myRepositoryField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@@ -122,16 +117,14 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
|
||||
updateToURL();
|
||||
}
|
||||
});
|
||||
myToURLText.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
String url = myToURLText.getText();
|
||||
String dstName = SVNPathUtil.tail(mySrcURL);
|
||||
dstName = SVNEncodingUtil.uriDecode(dstName);
|
||||
url = SelectLocationDialog.selectCopyDestination(myProject, SVNPathUtil.removeTail(url),
|
||||
SvnBundle.message("label.copy.select.location.dialog.copy.as"), dstName, false);
|
||||
if (url != null) {
|
||||
myToURLText.setText(url);
|
||||
}
|
||||
myToURLText.addActionListener(e -> {
|
||||
String url = myToURLText.getText();
|
||||
String dstName = SVNPathUtil.tail(mySrcURL);
|
||||
dstName = SVNEncodingUtil.uriDecode(dstName);
|
||||
url = SelectLocationDialog.selectCopyDestination(myProject, SVNPathUtil.removeTail(url),
|
||||
SvnBundle.message("label.copy.select.location.dialog.copy.as"), dstName, false);
|
||||
if (url != null) {
|
||||
myToURLText.setText(url);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -149,25 +142,13 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
|
||||
|
||||
myRevisionPanel.setRoot(mySrcVirtualFile);
|
||||
myRevisionPanel.setProject(myProject);
|
||||
myRevisionPanel.setUrlProvider(new SvnRevisionPanel.UrlProvider() {
|
||||
public String getUrl() {
|
||||
return mySrcURL;
|
||||
}
|
||||
});
|
||||
myRevisionPanel.setUrlProvider(() -> mySrcURL);
|
||||
updateBranchTagBases();
|
||||
|
||||
myRevisionPanel.addChangeListener(new ChangeListener() {
|
||||
public void stateChanged(final ChangeEvent e) {
|
||||
getOKAction().setEnabled(isOKActionEnabled());
|
||||
}
|
||||
});
|
||||
myRevisionPanel.addChangeListener(e -> getOKAction().setEnabled(isOKActionEnabled()));
|
||||
|
||||
init();
|
||||
ActionListener listener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
updateControls();
|
||||
}
|
||||
};
|
||||
ActionListener listener = e -> updateControls();
|
||||
myWorkingCopyRadioButton.addActionListener(listener);
|
||||
myRepositoryRadioButton.addActionListener(listener);
|
||||
myBranchOrTagRadioButton.addActionListener(listener);
|
||||
@@ -179,23 +160,15 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
|
||||
}
|
||||
});
|
||||
updateToURL();
|
||||
myProjectButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myRepositoryField.setText(myWcRootUrl);
|
||||
}
|
||||
myProjectButton.addActionListener(e -> myRepositoryField.setText(myWcRootUrl));
|
||||
myBranchTagBaseComboBox.addActionListener(e -> {
|
||||
BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile);
|
||||
updateBranchTagBases();
|
||||
updateControls();
|
||||
});
|
||||
myBranchTagBaseComboBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile);
|
||||
updateBranchTagBases();
|
||||
updateControls();
|
||||
}
|
||||
});
|
||||
myBranchTagBaseComboBox.getComboBox().addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
updateToURL();
|
||||
updateControls();
|
||||
}
|
||||
myBranchTagBaseComboBox.getComboBox().addActionListener(e -> {
|
||||
updateToURL();
|
||||
updateControls();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+9
-14
@@ -27,7 +27,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.SvnUtil;
|
||||
import org.jetbrains.idea.svn.SvnVcs;
|
||||
import org.jetbrains.idea.svn.api.Depth;
|
||||
import org.jetbrains.idea.svn.browse.DirectoryEntry;
|
||||
import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
@@ -130,20 +129,16 @@ public class DefaultBranchConfigInitializer implements Runnable {
|
||||
|
||||
@NotNull
|
||||
private static DirectoryEntryConsumer createHandler(@NotNull final SvnBranchConfigurationNew result, @NotNull final SVNURL rootPath) {
|
||||
return new DirectoryEntryConsumer() {
|
||||
return entry -> {
|
||||
if (entry.isDirectory()) {
|
||||
SVNURL childUrl = rootPath.appendPath(entry.getName(), false);
|
||||
|
||||
@Override
|
||||
public void consume(final DirectoryEntry entry) throws SVNException {
|
||||
if (entry.isDirectory()) {
|
||||
SVNURL childUrl = rootPath.appendPath(entry.getName(), false);
|
||||
|
||||
if (StringUtil.endsWithIgnoreCase(entry.getName(), DEFAULT_TRUNK_NAME)) {
|
||||
result.setTrunkUrl(childUrl.toString());
|
||||
}
|
||||
else {
|
||||
result.addBranches(childUrl.toString(),
|
||||
new InfoStorage<>(new ArrayList<>(0), InfoReliability.defaultValues));
|
||||
}
|
||||
if (StringUtil.endsWithIgnoreCase(entry.getName(), DEFAULT_TRUNK_NAME)) {
|
||||
result.setTrunkUrl(childUrl.toString());
|
||||
}
|
||||
else {
|
||||
result.addBranches(childUrl.toString(),
|
||||
new InfoStorage<>(new ArrayList<>(0), InfoReliability.defaultValues));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,10 +17,10 @@ package org.jetbrains.idea.svn.branchConfig;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.vcs.ProgressManagerQueue;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.CalledInBackground;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.vcs.ProgressManagerQueue;
|
||||
import org.jetbrains.annotations.CalledInBackground;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.SvnVcs;
|
||||
@@ -62,12 +62,7 @@ public class NewRootBunch {
|
||||
}
|
||||
|
||||
if (reload && override) {
|
||||
myBranchesLoader.run(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reloadBranches(root, previous, config.getValue());
|
||||
}
|
||||
});
|
||||
myBranchesLoader.run(() -> reloadBranches(root, previous, config.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,16 +99,11 @@ public class NewRootBunch {
|
||||
public void reloadBranchesAsync(@NotNull final VirtualFile root,
|
||||
@NotNull final String branchLocation,
|
||||
@NotNull final InfoReliability reliability) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reloadBranches(root, branchLocation, reliability, true);
|
||||
}
|
||||
});
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> reloadBranches(root, branchLocation, reliability, true));
|
||||
}
|
||||
|
||||
public void reloadBranches(@NotNull VirtualFile root, @Nullable SvnBranchConfigurationNew prev, @NotNull SvnBranchConfigurationNew next) {
|
||||
final Set<String> oldUrls = (prev == null) ? Collections.<String>emptySet() : new HashSet<>(prev.getBranchUrls());
|
||||
final Set<String> oldUrls = (prev == null) ? Collections.emptySet() : new HashSet<>(prev.getBranchUrls());
|
||||
final SvnVcs vcs = SvnVcs.getInstance(myProject);
|
||||
if (!vcs.isVcsBackgroundOperationsAllowed(root)) return;
|
||||
|
||||
|
||||
@@ -168,25 +168,13 @@ public class SelectBranchPopup {
|
||||
@Override
|
||||
public PopupStep onChosen(final String selectedValue, final boolean finalChoice) {
|
||||
if (CONFIGURE_MESSAGE.equals(selectedValue)) {
|
||||
return doFinalStep(new Runnable() {
|
||||
public void run() {
|
||||
BranchConfigurationDialog.configureBranches(myProject, myVcsRoot);
|
||||
}
|
||||
});
|
||||
return doFinalStep(() -> BranchConfigurationDialog.configureBranches(myProject, myVcsRoot));
|
||||
}
|
||||
else if (myTrunkString.equals(selectedValue)) {
|
||||
return doFinalStep(new Runnable() {
|
||||
public void run() {
|
||||
myCallback.branchSelected(myProject, myConfiguration, myConfiguration.getTrunkUrl(), -1);
|
||||
}
|
||||
});
|
||||
return doFinalStep(() -> myCallback.branchSelected(myProject, myConfiguration, myConfiguration.getTrunkUrl(), -1));
|
||||
}
|
||||
else if (!myTopLevel || selectedValue.equals(myConfiguration.getTrunkUrl())) {
|
||||
return doFinalStep(new Runnable() {
|
||||
public void run() {
|
||||
myCallback.branchSelected(myProject, myConfiguration, selectedValue, -1);
|
||||
}
|
||||
});
|
||||
return doFinalStep(() -> myCallback.branchSelected(myProject, myConfiguration, selectedValue, -1));
|
||||
}
|
||||
else {
|
||||
showBranchPopup(selectedValue);
|
||||
@@ -238,35 +226,18 @@ public class SelectBranchPopup {
|
||||
.setTitle(SVNPathUtil.tail(selectedValue))
|
||||
.setResizable(true)
|
||||
//.setDimensionServiceKey("Svn.CompareWithBranchPopup")
|
||||
.setItemChoosenCallback(new Runnable() {
|
||||
public void run() {
|
||||
if (REFRESH_MESSAGE.equals(branchList.getSelectedValue())) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadBranches(selectedValue, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showBranchPopup(selectedValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
SvnBranchItem item = (SvnBranchItem)branchList.getSelectedValue();
|
||||
if (item != null) {
|
||||
myCallback.branchSelected(myProject, myConfiguration, item.getUrl(), item.getRevision());
|
||||
}
|
||||
.setItemChoosenCallback(() -> {
|
||||
if (REFRESH_MESSAGE.equals(branchList.getSelectedValue())) {
|
||||
SwingUtilities.invokeLater(() -> loadBranches(selectedValue, () -> showBranchPopup(selectedValue)));
|
||||
return;
|
||||
}
|
||||
})
|
||||
.setFilteringEnabled(new NullableFunction<Object, String>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public String fun(Object item) {
|
||||
return item instanceof SvnBranchItem ? getBranchName((SvnBranchItem)item) : null;
|
||||
SvnBranchItem item = (SvnBranchItem)branchList.getSelectedValue();
|
||||
if (item != null) {
|
||||
myCallback.branchSelected(myProject, myConfiguration, item.getUrl(), item.getRevision());
|
||||
}
|
||||
})
|
||||
.setFilteringEnabled(
|
||||
(NullableFunction<Object, String>)item -> item instanceof SvnBranchItem ? getBranchName((SvnBranchItem)item) : null)
|
||||
.createPopup();
|
||||
showPopupAt(popup);
|
||||
}
|
||||
|
||||
+15
-27
@@ -62,18 +62,11 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
|
||||
// TODO: for DefaultConfigLoader it would be better to run modal cancellable task - so branches structure could be detected and
|
||||
// TODO: shown in dialog. Currently when "Configure Branches" is invoked for the first time - no branches are shown.
|
||||
// TODO: If "Cancel" is pressed and "Configure Branches" invoked once again - already detected (in background) branches are shown.
|
||||
((ProjectLevelVcsManagerImpl) vcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myProject.isDisposed()) return;
|
||||
myBranchesLoader.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
((ProjectLevelVcsManagerImpl)vcsManager)
|
||||
.addInitializationRequest(VcsInitObject.BRANCHES, () -> ApplicationManager.getApplication().runReadAction(() -> {
|
||||
if (myProject.isDisposed()) return;
|
||||
myBranchesLoader.start();
|
||||
}));
|
||||
myBunch = new NewRootBunch(project, myBranchesLoader);
|
||||
}
|
||||
|
||||
@@ -189,22 +182,17 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S
|
||||
}
|
||||
|
||||
private void preloadBranches(@NotNull final Collection<Pair<VirtualFile, SvnBranchConfigurationNew>> branchPoints) {
|
||||
((ProjectLevelVcsManagerImpl) myVcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : branchPoints) {
|
||||
myBunch.reloadBranches(pair.getFirst(), null, pair.getSecond());
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
//
|
||||
}
|
||||
((ProjectLevelVcsManagerImpl)myVcsManager)
|
||||
.addInitializationRequest(VcsInitObject.BRANCHES, () -> ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
try {
|
||||
for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : branchPoints) {
|
||||
myBunch.reloadBranches(pair.getFirst(), null, pair.getSecond());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
//
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private List<SvnBranchItem> getStored(String branchUrl) {
|
||||
|
||||
+1
-7
@@ -19,7 +19,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.SvnUtil;
|
||||
@@ -64,12 +63,7 @@ public class SvnBranchConfigurationNew {
|
||||
|
||||
public List<String> getBranchUrls() {
|
||||
final ArrayList<String> result = new ArrayList<>(myBranchMap.keySet());
|
||||
final List<String> cutList = ObjectsConvertor.convert(result, new Convertor<String, String>() {
|
||||
@Override
|
||||
public String convert(String s) {
|
||||
return cutEndSlash(s);
|
||||
}
|
||||
});
|
||||
final List<String> cutList = ObjectsConvertor.convert(result, s -> cutEndSlash(s));
|
||||
Collections.sort(cutList);
|
||||
return cutList;
|
||||
}
|
||||
|
||||
@@ -121,12 +121,8 @@ public class IdeaCommitHandler implements CommitEventHandler, ProgressTracker {
|
||||
|
||||
private void trackDeletedFile(@NotNull ProgressEvent event) {
|
||||
@NonNls final String filePath = "file://" + event.getFile().getAbsolutePath().replace(File.separatorChar, '/');
|
||||
VirtualFile virtualFile = ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
|
||||
@Nullable
|
||||
public VirtualFile compute() {
|
||||
return VirtualFileManager.getInstance().findFileByUrl(filePath);
|
||||
}
|
||||
});
|
||||
VirtualFile virtualFile = ApplicationManager.getApplication()
|
||||
.runReadAction((Computable<VirtualFile>)() -> VirtualFileManager.getInstance().findFileByUrl(filePath));
|
||||
|
||||
if (virtualFile != null) {
|
||||
myDeletedFiles.add(virtualFile);
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vcs.CheckinProjectPanel;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
@@ -135,16 +134,8 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
|
||||
final Project project = mySvnVcs.getProject();
|
||||
final String message = SvnBundle.message("status.text.comitted.revision", committedRevisions);
|
||||
if (feedback == null) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new VcsBalloonProblemNotifier(project, message, MessageType.INFO).run();
|
||||
}
|
||||
}, new Condition<Object>() {
|
||||
@Override
|
||||
public boolean value(Object o) {
|
||||
return (! project.isOpen()) || project.isDisposed();
|
||||
}
|
||||
});
|
||||
ApplicationManager.getApplication().invokeLater(() -> new VcsBalloonProblemNotifier(project, message, MessageType.INFO).run(),
|
||||
o -> (!project.isOpen()) || project.isDisposed());
|
||||
} else {
|
||||
feedback.add("Subversion: " + message);
|
||||
}
|
||||
@@ -207,11 +198,9 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
|
||||
doCommit(committables, preparedComment, exception, feedback);
|
||||
}
|
||||
else if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
public void run() {
|
||||
doCommit(committables, preparedComment, exception, feedback);
|
||||
}
|
||||
}, SvnBundle.message("progress.title.commit"), false, mySvnVcs.getProject());
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||
() -> doCommit(committables, preparedComment, exception, feedback), SvnBundle.message("progress.title.commit"), false,
|
||||
mySvnVcs.getProject());
|
||||
}
|
||||
else {
|
||||
doCommit(committables, preparedComment, exception, feedback);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user