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:
@@ -326,19 +326,36 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeSourcePosition(@NotNull XNavigatable navigatable) {
|
||||
if (myValueDescriptor instanceof FieldDescriptorImpl) {
|
||||
SourcePosition position = ((FieldDescriptorImpl)myValueDescriptor).getSourcePosition(getProject(), getDebuggerContext());
|
||||
if (position != null) {
|
||||
navigatable.setSourcePosition(DebuggerUtilsEx.toXSourcePosition(position));
|
||||
public void computeSourcePosition(@NotNull final XNavigatable navigatable) {
|
||||
if (myEvaluationContext.getSuspendContext().isResumed()) return;
|
||||
myEvaluationContext.getDebugProcess().getManagerThread().schedule(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) {
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.NORMAL;
|
||||
}
|
||||
}
|
||||
if (myValueDescriptor instanceof LocalVariableDescriptorImpl) {
|
||||
SourcePosition position = ((LocalVariableDescriptorImpl)myValueDescriptor).getSourcePosition(getProject(), getDebuggerContext());
|
||||
if (position != null) {
|
||||
navigatable.setSourcePosition(DebuggerUtilsEx.toXSourcePosition(position));
|
||||
|
||||
@Override
|
||||
public void contextAction() throws Exception {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myValueDescriptor instanceof FieldDescriptorImpl) {
|
||||
SourcePosition position = ((FieldDescriptorImpl)myValueDescriptor).getSourcePosition(getProject(), getDebuggerContext());
|
||||
if (position != null) {
|
||||
navigatable.setSourcePosition(DebuggerUtilsEx.toXSourcePosition(position));
|
||||
}
|
||||
}
|
||||
if (myValueDescriptor instanceof LocalVariableDescriptorImpl) {
|
||||
SourcePosition position =
|
||||
((LocalVariableDescriptorImpl)myValueDescriptor).getSourcePosition(getProject(), getDebuggerContext());
|
||||
if (position != null) {
|
||||
navigatable.setSourcePosition(DebuggerUtilsEx.toXSourcePosition(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DebuggerContextImpl getDebuggerContext() {
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ public class JavaGenerateMemberCompletionContributor {
|
||||
for (PsiField field : parent.getFields()) {
|
||||
if (!(field instanceof PsiEnumConstant)) {
|
||||
Collections.addAll(prototypes, GetterSetterPrototypeProvider.generateGetterSetters(field, true));
|
||||
Collections.addAll(prototypes, GetterSetterPrototypeProvider.generateGetterSetters(field, true));
|
||||
Collections.addAll(prototypes, GetterSetterPrototypeProvider.generateGetterSetters(field, false));
|
||||
}
|
||||
}
|
||||
for (final PsiMethod prototype : prototypes) {
|
||||
|
||||
@@ -81,7 +81,7 @@ public class OverrideImplementTest extends LightCodeInsightTestCase {
|
||||
CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(getProject()).clone();
|
||||
try {
|
||||
CommonCodeStyleSettings javaSettings = codeStyleSettings.getCommonSettings(JavaLanguage.INSTANCE);
|
||||
codeStyleSettings.RIGHT_MARGIN = 80;
|
||||
javaSettings.RIGHT_MARGIN = 80;
|
||||
javaSettings.KEEP_LINE_BREAKS = true;
|
||||
codeStyleSettings.GENERATE_FINAL_PARAMETERS = true;
|
||||
javaSettings.METHOD_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM;
|
||||
@@ -97,7 +97,7 @@ public class OverrideImplementTest extends LightCodeInsightTestCase {
|
||||
CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(getProject()).clone();
|
||||
try {
|
||||
CommonCodeStyleSettings javaSettings = codeStyleSettings.getCommonSettings(JavaLanguage.INSTANCE);
|
||||
codeStyleSettings.RIGHT_MARGIN = 80;
|
||||
javaSettings.RIGHT_MARGIN = 80;
|
||||
javaSettings.KEEP_LINE_BREAKS = false;
|
||||
codeStyleSettings.GENERATE_FINAL_PARAMETERS = false;
|
||||
javaSettings.METHOD_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM;
|
||||
|
||||
@@ -165,6 +165,10 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
|
||||
int fingerprint = getDependenciesFingerprint();
|
||||
|
||||
for (JavaSourceRootDescriptor root : pd.getBuildRootIndex().getTargetRoots(this, null)) {
|
||||
fingerprint += FileUtil.fileHashCode(root.getRootFile());
|
||||
}
|
||||
|
||||
final LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module);
|
||||
if (level != null) {
|
||||
fingerprint += level.name().hashCode();
|
||||
|
||||
@@ -38,8 +38,4 @@ public class OutgoingResult {
|
||||
public List<? extends VcsFullCommitDetails> getCommits() {
|
||||
return myCommits;
|
||||
}
|
||||
|
||||
public boolean hasErrors() {
|
||||
return !myErrors.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
*/
|
||||
package com.intellij.dvcs.push;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Source to push from. For example, local branch for git or branch/bookmark for mercurial.
|
||||
*/
|
||||
public interface PushSource {
|
||||
@NotNull
|
||||
String getPresentation();
|
||||
}
|
||||
|
||||
@@ -198,14 +198,15 @@ public class PushController implements Disposable {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
OutgoingResult outgoing = result.get();
|
||||
if (outgoing.hasErrors()) {
|
||||
List<VcsError> errors = outgoing.getErrors();
|
||||
if (!errors.isEmpty()) {
|
||||
final CommitLoader loader = new CommitLoader() {
|
||||
@Override
|
||||
public void reloadCommits() {
|
||||
loadCommits(model, node, false);
|
||||
}
|
||||
};
|
||||
myPushLog.setChildren(node, ContainerUtil.map(outgoing.getErrors(), new Function<VcsError, DefaultMutableTreeNode>() {
|
||||
myPushLog.setChildren(node, ContainerUtil.map(errors, new Function<VcsError, DefaultMutableTreeNode>() {
|
||||
@Override
|
||||
public DefaultMutableTreeNode fun(final VcsError error) {
|
||||
VcsLinkedText errorLinkText = new VcsLinkedText(error.getText(), new VcsLinkListener() {
|
||||
@@ -347,13 +348,13 @@ public class PushController implements Disposable {
|
||||
return additionalPanels;
|
||||
}
|
||||
|
||||
private boolean hasRepoForPushSupport(@NotNull PushSupport support) {
|
||||
for (MyRepoModel model : myView2Model.values()) {
|
||||
if (support.equals(model.getSupport())) {
|
||||
return true;
|
||||
private boolean hasRepoForPushSupport(@NotNull final PushSupport support) {
|
||||
return ContainerUtil.exists(myView2Model.values(), new Condition<MyRepoModel>() {
|
||||
@Override
|
||||
public boolean value(MyRepoModel model) {
|
||||
return support.equals(model.getSupport());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private static class MyRepoModel {
|
||||
|
||||
@@ -34,13 +34,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Nadya Zabrodina
|
||||
*/
|
||||
public class BranchActionGroupPopup extends PopupFactoryImpl.ActionGroupPopup {
|
||||
public BranchActionGroupPopup(@NotNull String title, @NotNull Project project,
|
||||
@NotNull Condition<AnAction> preselectActionCondition, @NotNull ActionGroup actions) {
|
||||
super(title, actions, SimpleDataContext.getProjectContext(project), false, false, false, false, null, -1,
|
||||
super(title, actions, SimpleDataContext.getProjectContext(project), false, false, true, false, null, -1,
|
||||
preselectActionCondition, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Nadya Zabrodina
|
||||
*/
|
||||
public abstract class NewBranchAction<T extends Repository> extends DumbAwareAction {
|
||||
protected final List<T> myRepositories;
|
||||
protected Project myProject;
|
||||
@@ -43,7 +40,7 @@ public abstract class NewBranchAction<T extends Repository> extends DumbAwareAct
|
||||
public void update(AnActionEvent e) {
|
||||
if (DvcsUtil.anyRepositoryIsFresh(myRepositories)) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
e.getPresentation().setDescription("Checkout of a new branch is not possible before the first commit.");
|
||||
e.getPresentation().setDescription("Checkout of a new branch is not possible before the first commit");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+40
-7
@@ -89,11 +89,23 @@ public class PsiNamesElementSignatureProvider extends AbstractElementSignaturePr
|
||||
return candidate instanceof PsiComment ? candidate : null;
|
||||
}
|
||||
else if (CODE_BLOCK_MARKER.equals(elementMarker)) {
|
||||
int index = 0;
|
||||
if (tokenizer.hasMoreTokens()) {
|
||||
String indexStr = tokenizer.nextToken();
|
||||
try {
|
||||
index = Integer.parseInt(indexStr);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
if (processingInfoStorage != null) {
|
||||
processingInfoStorage.append("Invalid block index: ").append(indexStr).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (PsiElement child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
PsiElement firstChild = child.getFirstChild();
|
||||
PsiElement lastChild = child.getLastChild();
|
||||
if (firstChild != null && lastChild != null && "{".equals(firstChild.getText()) && "}".equals(lastChild.getText())) {
|
||||
return child;
|
||||
if (isBlockElement(child)) {
|
||||
if (--index < 0) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -212,18 +224,39 @@ public class PsiNamesElementSignatureProvider extends AbstractElementSignaturePr
|
||||
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof PsiNamedElement && !(parent instanceof PsiFile)) {
|
||||
PsiElement firstChild = element.getFirstChild();
|
||||
PsiElement lastChild = element.getLastChild();
|
||||
if (firstChild != null && "{".equals(firstChild.getText()) && lastChild != null && "}".equals(lastChild.getText())) {
|
||||
if (isBlockElement(element)) {
|
||||
int index = getBlockElementIndex(element);
|
||||
StringBuilder bufferToUse = buffer;
|
||||
if (bufferToUse == null) {
|
||||
bufferToUse = new StringBuilder();
|
||||
}
|
||||
bufferToUse.append(TYPE_MARKER).append(ELEMENT_TOKENS_SEPARATOR).append(CODE_BLOCK_MARKER);
|
||||
if (index > 0) {
|
||||
bufferToUse.append(ELEMENT_TOKENS_SEPARATOR).append(index);
|
||||
}
|
||||
return bufferToUse;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isBlockElement(@NotNull PsiElement element) {
|
||||
PsiElement firstChild = element.getFirstChild();
|
||||
PsiElement lastChild = element.getLastChild();
|
||||
return firstChild != null && "{".equals(firstChild.getText()) && lastChild != null && "}".equals(lastChild.getText());
|
||||
}
|
||||
|
||||
private static int getBlockElementIndex(@NotNull PsiElement element) {
|
||||
int i = 0;
|
||||
for (PsiElement sibling : element.getParent().getChildren()) {
|
||||
if (element.equals(sibling)) {
|
||||
return i;
|
||||
}
|
||||
if (isBlockElement(sibling)) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Malformed PSI");
|
||||
}
|
||||
}
|
||||
|
||||
+85
-20
@@ -49,6 +49,7 @@ import com.intellij.ui.navigation.History;
|
||||
import com.intellij.ui.navigation.Place;
|
||||
import com.intellij.ui.speedSearch.ElementFilter;
|
||||
import com.intellij.ui.treeStructure.SimpleNode;
|
||||
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.update.Activatable;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
@@ -87,6 +88,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
private final History myHistory = new History(this);
|
||||
|
||||
private final OptionsTree myTree;
|
||||
private final SettingsTreeView myTreeView;
|
||||
private final MySearchField mySearch;
|
||||
private final Splitter myMainSplitter;
|
||||
//[back/forward] JComponent myToolbarComponent;
|
||||
@@ -126,7 +128,12 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
mySearch = new MySearchField() {
|
||||
@Override
|
||||
protected void onTextKeyEvent(final KeyEvent e) {
|
||||
myTree.processTextEvent(e);
|
||||
if (myTreeView != null) {
|
||||
myTreeView.myTree.processKeyEvent(e);
|
||||
}
|
||||
else {
|
||||
myTree.processTextEvent(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,12 +151,12 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
}
|
||||
});
|
||||
|
||||
myTree = new OptionsTree(myProject, groups, getContext()) {
|
||||
final KeyListener listener = new KeyListener() {
|
||||
@Override
|
||||
protected void onTreeKeyEvent(final KeyEvent e) {
|
||||
public void keyTyped(KeyEvent event) {
|
||||
myFilterDocumentWasChanged = false;
|
||||
try {
|
||||
mySearch.keyEventToTextField(e);
|
||||
mySearch.keyEventToTextField(event);
|
||||
}
|
||||
finally {
|
||||
if (myFilterDocumentWasChanged && !isFilterFieldVisible()) {
|
||||
@@ -157,10 +164,33 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getContext().addColleague(myTree);
|
||||
Disposer.register(this, myTree);
|
||||
@Override
|
||||
public void keyPressed(KeyEvent event) {
|
||||
keyTyped(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent event) {
|
||||
keyTyped(event);
|
||||
}
|
||||
};
|
||||
if (Registry.is("ide.file.settings.tree.new")) {
|
||||
myTreeView = new SettingsTreeView(listener, getContext(), groups);
|
||||
myTree = null;
|
||||
}
|
||||
else {
|
||||
myTreeView = null;
|
||||
myTree = new OptionsTree(myProject, groups, getContext()) {
|
||||
@Override
|
||||
protected void onTreeKeyEvent(final KeyEvent e) {
|
||||
listener.keyTyped(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
getContext().addColleague(myTreeView != null ? myTreeView : myTree);
|
||||
Disposer.register(this, myTreeView != null ? myTreeView : myTree);
|
||||
mySearch.addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
@@ -198,7 +228,8 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
Dimension dimension = super.getMinimumSize();
|
||||
dimension.width = Math.max(myTree.getMinimumSize().width, mySearchWrapper.getPreferredSize().width);
|
||||
JComponent component = myTreeView != null ? myTreeView : myTree;
|
||||
dimension.width = Math.max(component.getMinimumSize().width, mySearchWrapper.getPreferredSize().width);
|
||||
return dimension;
|
||||
}
|
||||
};
|
||||
@@ -211,7 +242,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
*/
|
||||
|
||||
myLeftSide.add(mySearchWrapper, BorderLayout.NORTH);
|
||||
myLeftSide.add(myTree, BorderLayout.CENTER);
|
||||
myLeftSide.add(myTreeView != null ? myTreeView : myTree, BorderLayout.CENTER);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
@@ -233,9 +264,19 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
mySpotlightUpdate = new MergingUpdateQueue("OptionsSpotlight", 200, false, this, this, this);
|
||||
|
||||
if (preselectedConfigurable != null) {
|
||||
myTree.select(preselectedConfigurable);
|
||||
if (myTreeView != null) {
|
||||
myTreeView.select(preselectedConfigurable);
|
||||
}
|
||||
else {
|
||||
myTree.select(preselectedConfigurable);
|
||||
}
|
||||
} else {
|
||||
myTree.selectFirst();
|
||||
if (myTreeView != null) {
|
||||
myTreeView.selectFirst();
|
||||
}
|
||||
else {
|
||||
myTree.selectFirst();
|
||||
}
|
||||
}
|
||||
|
||||
Toolkit.getDefaultToolkit().addAWTEventListener(this,
|
||||
@@ -295,12 +336,16 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public <T extends Configurable> T findConfigurable(Class<T> configurableClass) {
|
||||
return myTree.findConfigurable(configurableClass);
|
||||
return myTreeView != null
|
||||
? myTreeView.findConfigurable(configurableClass)
|
||||
: myTree.findConfigurable(configurableClass);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SearchableConfigurable findConfigurableById(@NotNull String configurableId) {
|
||||
return myTree.findConfigurableById(configurableId);
|
||||
return myTreeView != null
|
||||
? myTreeView.findConfigurableById(configurableId)
|
||||
: myTree.findConfigurableById(configurableId);
|
||||
}
|
||||
|
||||
public ActionCallback clearSearchAndSelect(Configurable configurable) {
|
||||
@@ -318,7 +363,9 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
|
||||
public ActionCallback select(Configurable configurable, final String text) {
|
||||
myFilter.refilterFor(text, false, true);
|
||||
return myTree.select(configurable);
|
||||
return myTreeView != null
|
||||
? myTreeView.select(configurable)
|
||||
: myTree.select(configurable);
|
||||
}
|
||||
|
||||
private float readProportion(final float defaultValue, final String propertyName) {
|
||||
@@ -367,7 +414,10 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
myOwnDetails.setContent(myContentWrapper);
|
||||
myOwnDetails.setBannerMinHeight(mySearchWrapper.getHeight());
|
||||
myOwnDetails.setText(getBannerText(configurable));
|
||||
if (Registry.is("ide.file.settings.order.new")) {
|
||||
if (myTreeView != null) {
|
||||
myOwnDetails.forProject(myTreeView.findConfigurableProject(configurable));
|
||||
}
|
||||
else if (Registry.is("ide.file.settings.order.new")) {
|
||||
myOwnDetails.forProject(myTree.getConfigurableProject(configurable));
|
||||
}
|
||||
|
||||
@@ -385,7 +435,8 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
checkModified(oldConfigurable);
|
||||
checkModified(configurable);
|
||||
|
||||
if (myTree.myBuilder.getSelectedElements().size() == 0) {
|
||||
FilteringTreeBuilder builder = myTreeView != null ? myTreeView.myBuilder : myTree.myBuilder;
|
||||
if (builder.getSelectedElements().size() == 0) {
|
||||
select(configurable).notify(result);
|
||||
} else {
|
||||
result.setDone();
|
||||
@@ -507,6 +558,9 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
}
|
||||
|
||||
private String[] getBannerText(Configurable configurable) {
|
||||
if (myTreeView != null) {
|
||||
return myTreeView.getPathNames(configurable);
|
||||
}
|
||||
final List<Configurable> list = myTree.getPathToRoot(configurable);
|
||||
final String[] result = new String[list.size()];
|
||||
int add = 0;
|
||||
@@ -795,7 +849,12 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
getContext().fireErrorsChanged(errors, null);
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
myTree.select(errors.keySet().iterator().next());
|
||||
if (myTreeView != null) {
|
||||
myTreeView.select(errors.keySet().iterator().next());
|
||||
}
|
||||
else {
|
||||
myTree.select(errors.keySet().iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,7 +894,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
return myFiltered.contains(node.getConfigurable()) || isChildOfNameHit(node);
|
||||
}
|
||||
|
||||
return true;
|
||||
return SettingsTreeView.isFiltered(myFiltered, myHits, value);
|
||||
}
|
||||
|
||||
private boolean isChildOfNameHit(OptionsTree.EditorNode node) {
|
||||
@@ -929,7 +988,8 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
myLastSelected = current;
|
||||
}
|
||||
|
||||
final ActionCallback callback = fireUpdate(adjustSelection ? myTree.findNodeFor(toSelect) : null, adjustSelection, now);
|
||||
SimpleNode node = !adjustSelection ? null : myTreeView != null ? myTreeView.findNode(toSelect) : myTree.findNodeFor(toSelect);
|
||||
final ActionCallback callback = fireUpdate(node, adjustSelection, now);
|
||||
|
||||
myFilterDocumentWasChanged = true;
|
||||
|
||||
@@ -965,7 +1025,12 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
myFilter.refilterFor(filter, false, true).doWhenDone(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myTree.select(config).notifyWhenDone(result);
|
||||
if (myTreeView != null) {
|
||||
myTreeView.select(config).notifyWhenDone(result);
|
||||
}
|
||||
else {
|
||||
myTree.select(config).notifyWhenDone(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+864
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.options.newEditor;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.ui.search.ConfigurableHit;
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.options.*;
|
||||
import com.intellij.openapi.options.ex.ConfigurableWrapper;
|
||||
import com.intellij.openapi.options.ex.NodeConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.treeStructure.*;
|
||||
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
|
||||
import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ui.GraphicsUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import com.intellij.util.ui.update.Update;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeExpansionListener;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.plaf.TreeUI;
|
||||
import javax.swing.plaf.basic.BasicTreeUI;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
|
||||
/**
|
||||
* @author Sergey.Malenkov
|
||||
*/
|
||||
final class SettingsTreeView extends JComponent implements Disposable, OptionsEditorColleague {
|
||||
final SimpleTree myTree;
|
||||
final FilteringTreeBuilder myBuilder;
|
||||
|
||||
private final OptionsEditorContext myContext;
|
||||
private final MyRoot myRoot;
|
||||
private final JScrollPane myScroller;
|
||||
private JLabel mySeparator;
|
||||
private final MyRenderer myRenderer = new MyRenderer();
|
||||
private final IdentityHashMap<Configurable, MyNode> myConfigurableToNodeMap = new IdentityHashMap<Configurable, MyNode>();
|
||||
private final MergingUpdateQueue myQueue = new MergingUpdateQueue("OptionsTree", 150, false, this, this, this).setRestartTimerOnAdd(true);
|
||||
|
||||
private Configurable myQueuedConfigurable;
|
||||
|
||||
SettingsTreeView(final KeyListener listener, OptionsEditorContext context, ConfigurableGroup... groups) {
|
||||
myContext = context;
|
||||
myRoot = new MyRoot(groups);
|
||||
|
||||
myTree = new MyTree();
|
||||
myTree.getInputMap().clear();
|
||||
TreeUtil.installActions(myTree);
|
||||
|
||||
myTree.setOpaque(true);
|
||||
myTree.setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 0));
|
||||
|
||||
myTree.setRowHeight(-1);
|
||||
myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||
|
||||
myTree.setCellRenderer(myRenderer);
|
||||
myTree.setRootVisible(false);
|
||||
myTree.setShowsRootHandles(false);
|
||||
|
||||
myScroller = ScrollPaneFactory.createScrollPane(myTree);
|
||||
myScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
||||
add(myScroller);
|
||||
|
||||
myTree.addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
myBuilder.revalidateTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
myBuilder.revalidateTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
myBuilder.revalidateTree();
|
||||
}
|
||||
});
|
||||
|
||||
myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
||||
public void valueChanged(TreeSelectionEvent event) {
|
||||
MyNode node = extractNode(event.getNewLeadSelectionPath());
|
||||
select(node == null ? null : node.myConfigurable);
|
||||
}
|
||||
});
|
||||
|
||||
myTree.addKeyListener(new KeyListener() {
|
||||
public void keyTyped(KeyEvent event) {
|
||||
if (listener != null && isValid(event)) {
|
||||
listener.keyTyped(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void keyPressed(KeyEvent event) {
|
||||
if (listener != null && isValid(event)) {
|
||||
listener.keyPressed(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void keyReleased(KeyEvent event) {
|
||||
if (listener != null && isValid(event)) {
|
||||
listener.keyReleased(event);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValid(KeyEvent event) {
|
||||
return null == myTree.getInputMap().get(KeyStroke.getKeyStrokeForEvent(event));
|
||||
}
|
||||
});
|
||||
myBuilder = new MyBuilder(new SimpleTreeStructure.Impl(myRoot));
|
||||
myBuilder.setFilteringMerge(300, null);
|
||||
Disposer.register(this, myBuilder);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
String[] getPathNames(Configurable configurable) {
|
||||
ArrayDeque<String> path = new ArrayDeque<String>();
|
||||
MyNode node = myConfigurableToNodeMap.get(configurable);
|
||||
while (node != null) {
|
||||
path.push(node.myDisplayName);
|
||||
SimpleNode parent = node.getParent();
|
||||
node = parent instanceof MyNode
|
||||
? (MyNode)parent
|
||||
: null;
|
||||
}
|
||||
return ArrayUtil.toStringArray(path);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
SimpleNode findNode(Configurable toSelect) {
|
||||
return myConfigurableToNodeMap.get(toSelect);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
SearchableConfigurable findConfigurableById(@NotNull String id) {
|
||||
for (Configurable configurable : myConfigurableToNodeMap.keySet()) {
|
||||
if (configurable instanceof SearchableConfigurable) {
|
||||
SearchableConfigurable searchable = (SearchableConfigurable)configurable;
|
||||
if (id.equals(searchable.getId())) {
|
||||
return searchable;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
<T extends UnnamedConfigurable> T findConfigurable(@NotNull Class<T> type) {
|
||||
for (UnnamedConfigurable configurable : myConfigurableToNodeMap.keySet()) {
|
||||
if (configurable instanceof ConfigurableWrapper) {
|
||||
ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
|
||||
configurable = wrapper.getConfigurable();
|
||||
}
|
||||
if (type.isInstance(configurable)) {
|
||||
return type.cast(configurable);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Project findConfigurableProject(@Nullable Configurable configurable) {
|
||||
if (configurable instanceof ConfigurableWrapper) {
|
||||
ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
|
||||
return wrapper.getExtensionPoint().getProject();
|
||||
}
|
||||
return findConfigurableProject(myConfigurableToNodeMap.get(configurable));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Project findConfigurableProject(@Nullable MyNode node) {
|
||||
if (node != null) {
|
||||
Configurable configurable = node.myConfigurable;
|
||||
if (configurable instanceof ConfigurableWrapper) {
|
||||
ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
|
||||
return wrapper.getExtensionPoint().getProject();
|
||||
}
|
||||
SimpleNode parent = node.getParent();
|
||||
if (parent instanceof MyNode) {
|
||||
return findConfigurableProject((MyNode)parent);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ConfigurableGroup findConfigurableGroupAt(int x, int y) {
|
||||
TreePath path = myTree.getClosestPathForLocation(x - myTree.getX(), y - myTree.getY());
|
||||
while (path != null) {
|
||||
MyNode node = extractNode(path);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
if (node.myComposite instanceof ConfigurableGroup) {
|
||||
return (ConfigurableGroup)node.myComposite;
|
||||
}
|
||||
path = path.getParentPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MyNode extractNode(@Nullable Object object) {
|
||||
if (object instanceof TreePath) {
|
||||
TreePath path = (TreePath)object;
|
||||
object = path.getLastPathComponent();
|
||||
}
|
||||
if (object instanceof DefaultMutableTreeNode) {
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode)object;
|
||||
object = node.getUserObject();
|
||||
}
|
||||
if (object instanceof FilteringTreeStructure.FilteringNode) {
|
||||
FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)object;
|
||||
object = node.getDelegate();
|
||||
}
|
||||
return object instanceof MyNode
|
||||
? (MyNode)object
|
||||
: null;
|
||||
}
|
||||
|
||||
static boolean isFiltered(Set<Configurable> configurables, ConfigurableHit hits, SimpleNode value) {
|
||||
if (value instanceof MyNode && !configurables.contains(((MyNode)value).myConfigurable)) {
|
||||
if (hits != null) {
|
||||
configurables = hits.getNameFullHits();
|
||||
while (value != null) {
|
||||
if (value instanceof MyNode) {
|
||||
if (configurables.contains(((MyNode)value).myConfigurable)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
value = value.getParent();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout() {
|
||||
myScroller.setBounds(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
|
||||
if (mySeparator == null) {
|
||||
mySeparator = new JLabel();
|
||||
mySeparator.setFont(UIUtil.getLabelFont());
|
||||
mySeparator.setFont(getFont().deriveFont(Font.BOLD));
|
||||
}
|
||||
ConfigurableGroup group = findConfigurableGroupAt(0, 5 + mySeparator.getFont().getSize());
|
||||
if (group != null && group == findConfigurableGroupAt(0, -5)) {
|
||||
int offset = UIUtil.isUnderNativeMacLookAndFeel() ? 1 : 3;
|
||||
mySeparator.setBorder(BorderFactory.createEmptyBorder(offset, 18, offset, 3));
|
||||
mySeparator.setText(group.getDisplayName());
|
||||
|
||||
Rectangle bounds = myScroller.getViewport().getBounds();
|
||||
int height = mySeparator.getPreferredSize().height;
|
||||
if (bounds.height > height) {
|
||||
bounds.height = height;
|
||||
}
|
||||
g.setColor(myTree.getBackground());
|
||||
if (g instanceof Graphics2D) {
|
||||
int h = bounds.height / 4;
|
||||
int y = bounds.y + bounds.height - h;
|
||||
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height - h);
|
||||
((Graphics2D)g).setPaint(UIUtil.getGradientPaint(
|
||||
0, y, g.getColor(),
|
||||
0, y + h, ColorUtil.toAlpha(g.getColor(), 0)));
|
||||
g.fillRect(bounds.x, y, bounds.width, h + h);
|
||||
}
|
||||
else {
|
||||
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
mySeparator.setSize(bounds.width - 1, bounds.height);
|
||||
mySeparator.paint(g.create(bounds.x + 1, bounds.y, bounds.width - 1, bounds.height));
|
||||
}
|
||||
}
|
||||
|
||||
void selectFirst() {
|
||||
for (ConfigurableGroup eachGroup : myRoot.myGroups) {
|
||||
Configurable[] kids = eachGroup.getConfigurables();
|
||||
if (kids.length > 0) {
|
||||
select(kids[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ActionCallback select(@Nullable final Configurable configurable) {
|
||||
if (myBuilder.isSelectionBeingAdjusted()) {
|
||||
return new ActionCallback.Rejected();
|
||||
}
|
||||
final ActionCallback callback = new ActionCallback();
|
||||
myQueuedConfigurable = configurable;
|
||||
myQueue.queue(new Update(this) {
|
||||
public void run() {
|
||||
if (configurable == myQueuedConfigurable) {
|
||||
if (configurable == null) {
|
||||
fireSelected(null, callback);
|
||||
}
|
||||
else {
|
||||
myBuilder.getReady(this).doWhenDone(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (configurable != myQueuedConfigurable) return;
|
||||
|
||||
MyNode editorNode = myConfigurableToNodeMap.get(configurable);
|
||||
FilteringTreeStructure.FilteringNode editorUiNode = myBuilder.getVisibleNodeFor(editorNode);
|
||||
if (editorUiNode == null) return;
|
||||
|
||||
if (!myBuilder.getSelectedElements().contains(editorUiNode)) {
|
||||
myBuilder.select(editorUiNode, new Runnable() {
|
||||
public void run() {
|
||||
fireSelected(configurable, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
myBuilder.scrollSelectionToVisible(new Runnable() {
|
||||
public void run() {
|
||||
fireSelected(configurable, callback);
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRejected() {
|
||||
super.setRejected();
|
||||
callback.setRejected();
|
||||
}
|
||||
});
|
||||
return callback;
|
||||
}
|
||||
|
||||
private void fireSelected(Configurable configurable, ActionCallback callback) {
|
||||
myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
myQueuedConfigurable = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionCallback onSelected(@Nullable Configurable configurable, Configurable oldConfigurable) {
|
||||
return select(configurable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionCallback onModifiedAdded(Configurable configurable) {
|
||||
myTree.repaint();
|
||||
return new ActionCallback.Done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionCallback onModifiedRemoved(Configurable configurable) {
|
||||
myTree.repaint();
|
||||
return new ActionCallback.Done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionCallback onErrorsChanged() {
|
||||
return new ActionCallback.Done();
|
||||
}
|
||||
|
||||
private final class MyRoot extends CachingSimpleNode {
|
||||
private final ConfigurableGroup[] myGroups;
|
||||
|
||||
private MyRoot(ConfigurableGroup[] groups) {
|
||||
super(null);
|
||||
myGroups = groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpleNode[] buildChildren() {
|
||||
if (myGroups == null || myGroups.length == 0) {
|
||||
return NO_CHILDREN;
|
||||
}
|
||||
SimpleNode[] result = new SimpleNode[myGroups.length];
|
||||
for (int i = 0; i < myGroups.length; i++) {
|
||||
result[i] = new MyNode(this, myGroups[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyNode extends CachingSimpleNode {
|
||||
private final Configurable.Composite myComposite;
|
||||
private final Configurable myConfigurable;
|
||||
private final String myDisplayName;
|
||||
|
||||
private MyNode(CachingSimpleNode parent, Configurable configurable) {
|
||||
super(parent);
|
||||
myComposite = configurable instanceof Configurable.Composite ? (Configurable.Composite)configurable : null;
|
||||
myConfigurable = configurable;
|
||||
String name = configurable.getDisplayName();
|
||||
myDisplayName = name != null ? name.replace("\n", " ") : "{ " + configurable.getClass().getSimpleName() + " }";
|
||||
|
||||
myConfigurableToNodeMap.put(configurable, this);
|
||||
}
|
||||
|
||||
private MyNode(CachingSimpleNode parent, ConfigurableGroup group) {
|
||||
super(parent);
|
||||
myComposite = group;
|
||||
myConfigurable = null;
|
||||
String name = group.getDisplayName();
|
||||
myDisplayName = name != null ? name.replace("\n", " ") : "{ " + group.getClass().getSimpleName() + " }";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpleNode[] buildChildren() {
|
||||
if (myComposite == null) {
|
||||
return NO_CHILDREN;
|
||||
}
|
||||
Configurable[] configurables = myComposite.getConfigurables();
|
||||
if (configurables == null || configurables.length == 0) {
|
||||
return NO_CHILDREN;
|
||||
}
|
||||
SimpleNode[] result = new SimpleNode[configurables.length];
|
||||
for (int i = 0; i < configurables.length; i++) {
|
||||
result[i] = new MyNode(this, configurables[i]);
|
||||
if (myConfigurable != null) {
|
||||
myContext.registerKid(myConfigurable, configurables[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysLeaf() {
|
||||
return myComposite == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeight() {
|
||||
return WeightBasedComparator.UNDEFINED_WEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyRenderer extends GroupedElementsRenderer.Tree {
|
||||
private JLabel myNodeIcon;
|
||||
private JLabel myProjectIcon;
|
||||
|
||||
protected JComponent createItemComponent() {
|
||||
myTextLabel = new ErrorLabel();
|
||||
return myTextLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void layout() {
|
||||
myNodeIcon = new JLabel(" ", SwingConstants.RIGHT);
|
||||
myProjectIcon = new JLabel(" ", SwingConstants.LEFT);
|
||||
myProjectIcon.setOpaque(true);
|
||||
myRendererComponent.add(BorderLayout.NORTH, mySeparatorComponent);
|
||||
myRendererComponent.add(BorderLayout.CENTER, myComponent);
|
||||
myRendererComponent.add(BorderLayout.WEST, myNodeIcon);
|
||||
myRendererComponent.add(BorderLayout.EAST, myProjectIcon);
|
||||
}
|
||||
|
||||
public Component getTreeCellRendererComponent(JTree tree,
|
||||
Object value,
|
||||
boolean selected,
|
||||
boolean expanded,
|
||||
boolean leaf,
|
||||
int row,
|
||||
boolean focused) {
|
||||
myTextLabel.setOpaque(selected);
|
||||
myTextLabel.setFont(UIUtil.getLabelFont());
|
||||
|
||||
String text;
|
||||
boolean hasSeparatorAbove = false;
|
||||
int preferredForcedWidth = -1;
|
||||
|
||||
MyNode node = extractNode(value);
|
||||
if (node == null) {
|
||||
text = value.toString();
|
||||
}
|
||||
else {
|
||||
text = node.myDisplayName;
|
||||
// show groups in bold
|
||||
if (myRoot == node.getParent()) {
|
||||
hasSeparatorAbove = node != myRoot.getChildAt(0);
|
||||
myTextLabel.setFont(myTextLabel.getFont().deriveFont(Font.BOLD));
|
||||
}
|
||||
TreePath path = tree.getPathForRow(row);
|
||||
if (path == null) {
|
||||
if (value instanceof DefaultMutableTreeNode) {
|
||||
path = new TreePath(((DefaultMutableTreeNode)value).getPath());
|
||||
}
|
||||
}
|
||||
int forcedWidth = 2000;
|
||||
if (path != null && tree.isVisible()) {
|
||||
Rectangle visibleRect = tree.getVisibleRect();
|
||||
|
||||
int nestingLevel = tree.isRootVisible() ? path.getPathCount() - 1 : path.getPathCount() - 2;
|
||||
|
||||
int left = UIUtil.getTreeLeftChildIndent();
|
||||
int right = UIUtil.getTreeRightChildIndent();
|
||||
|
||||
Insets treeInsets = tree.getInsets();
|
||||
|
||||
int indent = (left + right) * nestingLevel + (treeInsets != null ? treeInsets.left + treeInsets.right : 0);
|
||||
|
||||
forcedWidth = visibleRect.width > 0 ? visibleRect.width - indent : forcedWidth;
|
||||
}
|
||||
preferredForcedWidth = forcedWidth - 4;
|
||||
}
|
||||
Component result = configureComponent(text, null, null, null, selected, hasSeparatorAbove, null, preferredForcedWidth);
|
||||
// update font color for modified configurables
|
||||
if (!selected && node != null) {
|
||||
Configurable configurable = node.myConfigurable;
|
||||
if (configurable != null) {
|
||||
if (myContext.getErrors().containsKey(configurable)) {
|
||||
myTextLabel.setForeground(JBColor.RED);
|
||||
}
|
||||
else if (myContext.getModified().contains(configurable)) {
|
||||
myTextLabel.setForeground(JBColor.BLUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
// configure project icon
|
||||
Project project = null;
|
||||
if (node != null) {
|
||||
SimpleNode parent = node.getParent();
|
||||
if (parent instanceof MyNode) {
|
||||
if (myRoot == parent.getParent()) {
|
||||
project = findConfigurableProject(node); // show icon for top-level nodes
|
||||
if (node.myConfigurable instanceof NodeConfigurable) { // special case for custom subgroups (build.tools)
|
||||
Configurable[] configurables = ((NodeConfigurable)node.myConfigurable).getConfigurables();
|
||||
if (configurables != null) { // assume that all configurables have the same project
|
||||
project = findConfigurableProject(configurables[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (((MyNode)parent).myConfigurable instanceof NodeConfigurable) {
|
||||
if (((MyNode)node.getParent()).myConfigurable instanceof NodeConfigurable) {
|
||||
project = findConfigurableProject(node); // special case for custom subgroups
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (project != null) {
|
||||
myProjectIcon.setIcon(selected
|
||||
? AllIcons.General.ProjectConfigurableSelected
|
||||
: AllIcons.General.ProjectConfigurable);
|
||||
myProjectIcon.setToolTipText(OptionsBundle.message(project.isDefault()
|
||||
? "configurable.default.project.tooltip"
|
||||
: "configurable.current.project.tooltip"));
|
||||
myProjectIcon.setBackground(myTextLabel.getBackground());
|
||||
myProjectIcon.setVisible(true);
|
||||
}
|
||||
else {
|
||||
myProjectIcon.setVisible(false);
|
||||
}
|
||||
// configure node icon
|
||||
if (value instanceof DefaultMutableTreeNode) {
|
||||
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value;
|
||||
TreePath treePath = new TreePath(treeNode.getPath());
|
||||
myNodeIcon.setIcon(myTree.getHandleIcon(treeNode, treePath));
|
||||
}
|
||||
else {
|
||||
myNodeIcon.setIcon(null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public boolean isUnderHandle(Point point) {
|
||||
Point handlePoint = SwingUtilities.convertPoint(myRendererComponent, point, myNodeIcon);
|
||||
Rectangle bounds = myNodeIcon.getBounds();
|
||||
return bounds.x < handlePoint.x && bounds.getMaxX() >= handlePoint.x;
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyTree extends SimpleTree {
|
||||
@Override
|
||||
public String getToolTipText(MouseEvent event) {
|
||||
if (event != null) {
|
||||
Component component = getDeepestRendererComponentAt(event.getX(), event.getY());
|
||||
if (component instanceof JLabel) {
|
||||
JLabel label = (JLabel)component;
|
||||
if (label.getIcon() != null) {
|
||||
String text = label.getToolTipText();
|
||||
if (text != null) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.getToolTipText(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean paintNodes() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean highlightSingleNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUI(TreeUI ui) {
|
||||
TreeUI actualUI = ui;
|
||||
if (!(ui instanceof MyTreeUi)) {
|
||||
actualUI = new MyTreeUi();
|
||||
}
|
||||
super.setUI(actualUI);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCustomUI() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureUiHelper(TreeUIHelper helper) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getScrollableTracksViewportWidth() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void processKeyEvent(KeyEvent e) {
|
||||
TreePath path = myTree.getSelectionPath();
|
||||
if (path != null) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
|
||||
if (isExpanded(path)) {
|
||||
collapsePath(path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
|
||||
if (isCollapsed(path)) {
|
||||
expandPath(path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.processKeyEvent(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processMouseEvent(MouseEvent e) {
|
||||
MyTreeUi ui = (MyTreeUi)myTree.getUI();
|
||||
boolean toggleNow = MouseEvent.MOUSE_RELEASED == e.getID()
|
||||
&& UIUtil.isActionClick(e, MouseEvent.MOUSE_RELEASED)
|
||||
&& !ui.isToggleEvent(e);
|
||||
|
||||
if (toggleNow || MouseEvent.MOUSE_PRESSED == e.getID()) {
|
||||
TreePath path = getPathForLocation(e.getX(), e.getY());
|
||||
if (path != null) {
|
||||
Rectangle bounds = getPathBounds(path);
|
||||
if (bounds != null && path.getLastPathComponent() instanceof DefaultMutableTreeNode) {
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
|
||||
boolean selected = isPathSelected(path);
|
||||
boolean expanded = isExpanded(path);
|
||||
Component comp =
|
||||
myRenderer.getTreeCellRendererComponent(this, node, selected, expanded, node.isLeaf(), getRowForPath(path), isFocusOwner());
|
||||
|
||||
comp.setBounds(bounds);
|
||||
comp.validate();
|
||||
|
||||
Point point = new Point(e.getX() - bounds.x, e.getY() - bounds.y);
|
||||
if (myRenderer.isUnderHandle(point)) {
|
||||
if (toggleNow) {
|
||||
ui.toggleExpandState(path);
|
||||
}
|
||||
e.consume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.processMouseEvent(e);
|
||||
}
|
||||
|
||||
private final class MyTreeUi extends BasicTreeUI {
|
||||
|
||||
@Override
|
||||
public void toggleExpandState(TreePath path) {
|
||||
super.toggleExpandState(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToggleEvent(MouseEvent event) {
|
||||
return super.isToggleEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldPaintExpandControl(TreePath path,
|
||||
int row,
|
||||
boolean isExpanded,
|
||||
boolean hasBeenExpanded,
|
||||
boolean isLeaf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintHorizontalPartOfLeg(Graphics g,
|
||||
Rectangle clipBounds,
|
||||
Insets insets,
|
||||
Rectangle bounds,
|
||||
TreePath path,
|
||||
int row,
|
||||
boolean isExpanded,
|
||||
boolean hasBeenExpanded,
|
||||
boolean isLeaf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g, JComponent c) {
|
||||
GraphicsUtil.setupAntialiasing(g);
|
||||
super.paint(g, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class MyBuilder extends FilteringTreeBuilder {
|
||||
|
||||
List<Object> myToExpandOnResetFilter;
|
||||
boolean myRefilteringNow;
|
||||
boolean myWasHoldingFilter;
|
||||
|
||||
public MyBuilder(SimpleTreeStructure structure) {
|
||||
super(myTree, myContext.getFilter(), structure, new WeightBasedComparator(false));
|
||||
myTree.addTreeExpansionListener(new TreeExpansionListener() {
|
||||
public void treeExpanded(TreeExpansionEvent event) {
|
||||
invalidateExpansions();
|
||||
}
|
||||
|
||||
public void treeCollapsed(TreeExpansionEvent event) {
|
||||
invalidateExpansions();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void invalidateExpansions() {
|
||||
if (!myRefilteringNow) {
|
||||
myToExpandOnResetFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSelectable(Object object) {
|
||||
return object instanceof MyNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoExpandNode(NodeDescriptor nodeDescriptor) {
|
||||
return myContext.isHoldingFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToEnsureSelectionOnFocusGained() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionCallback refilterNow(Object preferredSelection, boolean adjustSelection) {
|
||||
final List<Object> toRestore = new ArrayList<Object>();
|
||||
if (myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
|
||||
myToExpandOnResetFilter = myBuilder.getUi().getExpandedElements();
|
||||
}
|
||||
else if (!myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
|
||||
toRestore.addAll(myToExpandOnResetFilter);
|
||||
myToExpandOnResetFilter = null;
|
||||
}
|
||||
|
||||
myWasHoldingFilter = myContext.isHoldingFilter();
|
||||
|
||||
ActionCallback result = super.refilterNow(preferredSelection, adjustSelection);
|
||||
myRefilteringNow = true;
|
||||
return result.doWhenDone(new Runnable() {
|
||||
public void run() {
|
||||
myRefilteringNow = false;
|
||||
if (!myContext.isHoldingFilter() && getSelectedElements().isEmpty()) {
|
||||
restoreExpandedState(toRestore);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void restoreExpandedState(List<Object> toRestore) {
|
||||
TreePath[] selected = myTree.getSelectionPaths();
|
||||
if (selected == null) {
|
||||
selected = new TreePath[0];
|
||||
}
|
||||
|
||||
List<TreePath> toCollapse = new ArrayList<TreePath>();
|
||||
|
||||
for (int eachRow = 0; eachRow < myTree.getRowCount(); eachRow++) {
|
||||
if (!myTree.isExpanded(eachRow)) continue;
|
||||
|
||||
TreePath eachVisiblePath = myTree.getPathForRow(eachRow);
|
||||
if (eachVisiblePath == null) continue;
|
||||
|
||||
Object eachElement = myBuilder.getElementFor(eachVisiblePath.getLastPathComponent());
|
||||
if (toRestore.contains(eachElement)) continue;
|
||||
|
||||
|
||||
for (TreePath eachSelected : selected) {
|
||||
if (!eachVisiblePath.isDescendant(eachSelected)) {
|
||||
toCollapse.add(eachVisiblePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (TreePath each : toCollapse) {
|
||||
myTree.collapsePath(each);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,6 +394,7 @@ console.too.much.text.buffer.ratio.description=Used for disabling of console pro
|
||||
when there is too much of text to process.\n\
|
||||
The ratio is used against the console cycle buffer size (idea.cycle.buffer.size/theRatio=maxTextLength).
|
||||
ide.file.settings.order.new=false
|
||||
ide.file.settings.tree.new=false
|
||||
ide.new.project.settings=true
|
||||
ide.new.project.settings.description=Temporary key for new project settings dialog UI
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.execution.ui.ConsoleView;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.execution.ui.RunnerLayoutUi;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpoint;
|
||||
@@ -45,6 +46,7 @@ import javax.swing.event.HyperlinkListener;
|
||||
* @author nik
|
||||
*/
|
||||
public interface XDebugSession extends AbstractDebuggerSession {
|
||||
DataKey<XDebugSession> DATA_KEY = DataKey.create("XDebugSessionTab.XDebugSession");
|
||||
|
||||
@NotNull
|
||||
Project getProject();
|
||||
|
||||
@@ -170,6 +170,7 @@ public class XDebugSessionImpl implements XDebugSession {
|
||||
myPauseActionSupported = isSupported;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<AnAction> getRestartActions() {
|
||||
return myRestartActions;
|
||||
}
|
||||
@@ -180,6 +181,7 @@ public class XDebugSessionImpl implements XDebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<AnAction> getExtraActions() {
|
||||
return myExtraActions;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import com.intellij.util.SingleAlarm;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -71,11 +70,11 @@ public abstract class XDebugView implements Disposable {
|
||||
ViewContext viewContext = ViewContext.CONTEXT_KEY.getData(dataContext);
|
||||
ContentManager contentManager = viewContext == null ? null : viewContext.getContentManager();
|
||||
if (contentManager != null) {
|
||||
XDebugSession session = XDebugSessionTab.SESSION_KEY.getData(DataManager.getInstance().getDataContext(contentManager.getComponent()));
|
||||
XDebugSession session = XDebugSession.DATA_KEY.getData(DataManager.getInstance().getDataContext(contentManager.getComponent()));
|
||||
if (session != null) {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
return XDebugSessionTab.SESSION_KEY.getData(dataContext);
|
||||
return XDebugSession.DATA_KEY.getData(dataContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ import java.util.List;
|
||||
|
||||
public class XDebugSessionTab extends DebuggerSessionTabBase {
|
||||
private static final DataKey<XDebugSessionTab> TAB_KEY = DataKey.create("XDebugSessionTab");
|
||||
public static final DataKey<XDebugSession> SESSION_KEY = DataKey.create("XDebugSessionTab.XDebugSession");
|
||||
|
||||
private XWatchesViewImpl myWatchesView;
|
||||
private final List<XDebugView> myViews = new ArrayList<XDebugView>();
|
||||
@@ -146,7 +145,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
|
||||
}
|
||||
|
||||
if (mySession != null) {
|
||||
if (SESSION_KEY.is(dataId)) {
|
||||
if (XDebugSession.DATA_KEY.is(dataId)) {
|
||||
return mySession;
|
||||
}
|
||||
else if (LangDataKeys.CONSOLE_VIEW.is(dataId)) {
|
||||
|
||||
@@ -416,20 +416,6 @@ unstash.unstashing=Unstashing...
|
||||
unstash.view.tooltip=View selected stash
|
||||
unstash.view=&View
|
||||
unstashing.title=UnStashing changes...
|
||||
update.locally.modified.files.tooltip=Locally modified files.
|
||||
update.locally.modified.files=&Files:
|
||||
update.locally.modified.git.root=Git Root:
|
||||
update.locally.modified.message=<html><p>The following files under this root are locally modified. <br/>\
|
||||
Possible reasons: uncommitted changes; a problem with crlf conversion; {0} configuration file auto-save.</p>\
|
||||
<p><ul>\
|
||||
<li>Press <b>Revert Files</b> to discard these local changes and continue the update process.</li>\
|
||||
<li>Press <b>Cancel</b> to cancel the update process. <br/> Use Auto-Stash option to stash local changes before update and restore them after it.</li>\
|
||||
</ul></p> \
|
||||
</html>
|
||||
update.locally.modified.rescan.tooltip=<html>Rescan the repository to check for locally modified files again.<br/>Use this button if you have resolved the problem manually.</html>
|
||||
update.locally.modified.rescan=Re&scan
|
||||
update.locally.modified.revert=Revert Files
|
||||
update.locally.modified.title=Locally modified files are detected
|
||||
update.options.display.name=Git Update Settings
|
||||
update.options.no.commit=No &Commit
|
||||
update.options.save.before.update=Clean working tree before update
|
||||
|
||||
@@ -30,6 +30,7 @@ import git4idea.commands.*;
|
||||
import git4idea.merge.GitConflictResolver;
|
||||
import git4idea.update.GitUpdateResult;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import git4idea.util.LocalChangesWouldBeOverwrittenHelper;
|
||||
import git4idea.util.StringScanner;
|
||||
import git4idea.util.UntrackedFilesNotifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -43,6 +44,8 @@ import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static git4idea.commands.GitLocalChangesWouldBeOverwrittenDetector.Operation.CHECKOUT;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@@ -77,7 +80,9 @@ public class GitRebaser {
|
||||
final GitRebaseProblemDetector rebaseConflictDetector = new GitRebaseProblemDetector();
|
||||
rebaseHandler.addLineListener(rebaseConflictDetector);
|
||||
GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector = new GitUntrackedFilesOverwrittenByOperationDetector(root);
|
||||
GitLocalChangesWouldBeOverwrittenDetector localChangesDetector = new GitLocalChangesWouldBeOverwrittenDetector(root, CHECKOUT);
|
||||
rebaseHandler.addLineListener(untrackedFilesDetector);
|
||||
rebaseHandler.addLineListener(localChangesDetector);
|
||||
|
||||
String progressTitle = "Rebasing";
|
||||
GitTask rebaseTask = new GitTask(myProject, rebaseHandler, progressTitle);
|
||||
@@ -108,7 +113,7 @@ public class GitRebaser {
|
||||
});
|
||||
|
||||
if (failure.get()) {
|
||||
updateResult.set(handleRebaseFailure(rebaseHandler, root, rebaseConflictDetector, untrackedFilesDetector));
|
||||
updateResult.set(handleRebaseFailure(rebaseHandler, root, rebaseConflictDetector, untrackedFilesDetector, localChangesDetector));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -333,19 +338,27 @@ public class GitRebaser {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GitUpdateResult handleRebaseFailure(@NotNull GitLineHandler handler, @NotNull VirtualFile root,
|
||||
public GitUpdateResult handleRebaseFailure(@NotNull GitLineHandler handler,
|
||||
@NotNull VirtualFile root,
|
||||
@NotNull GitRebaseProblemDetector rebaseConflictDetector,
|
||||
@NotNull GitMessageWithFilesDetector untrackedWouldBeOverwrittenDetector) {
|
||||
@NotNull GitMessageWithFilesDetector untrackedWouldBeOverwrittenDetector,
|
||||
@NotNull GitLocalChangesWouldBeOverwrittenDetector localChangesDetector) {
|
||||
if (rebaseConflictDetector.isMergeConflict()) {
|
||||
LOG.info("handleRebaseFailure merge conflict");
|
||||
final boolean allMerged = new GitRebaser.ConflictResolver(myProject, myGit, root, this).merge();
|
||||
return allMerged ? GitUpdateResult.SUCCESS_WITH_RESOLVED_CONFLICTS : GitUpdateResult.INCOMPLETE;
|
||||
} else if (untrackedWouldBeOverwrittenDetector.wasMessageDetected()) {
|
||||
}
|
||||
else if (untrackedWouldBeOverwrittenDetector.wasMessageDetected()) {
|
||||
LOG.info("handleRebaseFailure: untracked files would be overwritten by checkout");
|
||||
UntrackedFilesNotifier.notifyUntrackedFilesOverwrittenBy(myProject, root,
|
||||
untrackedWouldBeOverwrittenDetector.getRelativeFilePaths(), "rebase", null);
|
||||
return GitUpdateResult.ERROR;
|
||||
} else {
|
||||
}
|
||||
else if (localChangesDetector.wasMessageDetected()) {
|
||||
LocalChangesWouldBeOverwrittenHelper.showErrorNotification(myProject, root, "rebase", localChangesDetector.getRelativeFilePaths());
|
||||
return GitUpdateResult.ERROR;
|
||||
}
|
||||
else {
|
||||
LOG.info("handleRebaseFailure error " + handler.errors());
|
||||
GitUIUtil.notifyImportantError(myProject, "Rebase error", GitUIUtil.stringifyErrors(handler.errors()));
|
||||
return GitUpdateResult.ERROR;
|
||||
|
||||
@@ -51,6 +51,7 @@ import git4idea.merge.GitConflictResolver;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.stash.GitStashUtils;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import git4idea.util.LocalChangesWouldBeOverwrittenHelper;
|
||||
import git4idea.util.UntrackedFilesNotifier;
|
||||
import git4idea.validators.GitBranchNameValidator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -68,6 +69,8 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static git4idea.commands.GitLocalChangesWouldBeOverwrittenDetector.Operation.MERGE;
|
||||
|
||||
/**
|
||||
* The unstash dialog
|
||||
*/
|
||||
@@ -349,7 +352,9 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
}
|
||||
});
|
||||
GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector = new GitUntrackedFilesOverwrittenByOperationDetector(root);
|
||||
GitLocalChangesWouldBeOverwrittenDetector localChangesDetector = new GitLocalChangesWouldBeOverwrittenDetector(root, MERGE);
|
||||
h.addLineListener(untrackedFilesDetector);
|
||||
h.addLineListener(localChangesDetector);
|
||||
|
||||
GitUtil.workingTreeChangeStarted(myProject);
|
||||
try {
|
||||
@@ -371,6 +376,8 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
} else if (untrackedFilesDetector.wasMessageDetected()) {
|
||||
UntrackedFilesNotifier.notifyUntrackedFilesOverwrittenBy(myProject, root, untrackedFilesDetector.getRelativeFilePaths(),
|
||||
"unstash", null);
|
||||
} else if (localChangesDetector.wasMessageDetected()) {
|
||||
LocalChangesWouldBeOverwrittenHelper.showErrorDialog(myProject, root, "unstash", localChangesDetector.getRelativeFilePaths());
|
||||
} else if (!res.success()) {
|
||||
GitUIUtil.showOperationErrors(myProject, h.errors(), h.printableCommandLine());
|
||||
}
|
||||
|
||||
@@ -45,14 +45,8 @@ import javax.swing.event.HyperlinkEvent;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The popup which allows to quickly switch and control Git branches.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use {@link #asListPopup()} to achieve the {@link ListPopup} itself.
|
||||
* </p>
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
* <p/>
|
||||
*/
|
||||
class GitBranchPopup {
|
||||
|
||||
@@ -160,32 +154,28 @@ class GitBranchPopup {
|
||||
}
|
||||
|
||||
private void notifyAboutSyncedBranches() {
|
||||
VcsNotifier.getInstance(myProject).notifyImportantInfo("Synchronous branch control enabled",
|
||||
"You have several Git roots in the project and they all are checked out at the same branch. " +
|
||||
"We've enabled synchronous branch control for the project. <br/>" +
|
||||
"If you wish to control branches in different roots separately, you may <a href='settings'>disable</a> the setting.",
|
||||
new NotificationListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(@NotNull Notification notification,
|
||||
@NotNull HyperlinkEvent event) {
|
||||
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(myProject, myVcs
|
||||
.getConfigurable().getDisplayName());
|
||||
if (myVcsSettings.getSyncSetting() == GitBranchSyncSetting.DONT) {
|
||||
notification.expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
String description = "You have several Git roots in the project and they all are checked out at the same branch. " +
|
||||
"We've enabled synchronous branch control for the project. <br/>" +
|
||||
"If you wish to control branches in different roots separately, " +
|
||||
"you may <a href='settings'>disable</a> the setting.";
|
||||
NotificationListener listener = new NotificationListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
|
||||
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(myProject, myVcs.getConfigurable().getDisplayName());
|
||||
if (myVcsSettings.getSyncSetting() == GitBranchSyncSetting.DONT) {
|
||||
notification.expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
VcsNotifier.getInstance(myProject).notifyImportantInfo("Synchronous branch control enabled", description, listener);
|
||||
}
|
||||
|
||||
private ActionGroup createActions() {
|
||||
DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
|
||||
|
||||
GitRepositoryManager repositoryManager = myRepositoryManager;
|
||||
if (repositoryManager.moreThanOneRoot()) {
|
||||
|
||||
if (userWantsSyncControl()) {
|
||||
fillWithCommonRepositoryActions(popupGroup, repositoryManager);
|
||||
}
|
||||
@@ -196,7 +186,6 @@ class GitBranchPopup {
|
||||
else {
|
||||
fillPopupWithCurrentRepositoryActions(popupGroup, null);
|
||||
}
|
||||
|
||||
popupGroup.addSeparator();
|
||||
return popupGroup;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitBranchPopupActions {
|
||||
|
||||
private final Project myProject;
|
||||
@@ -123,7 +119,7 @@ class GitBranchPopupActions {
|
||||
public void update(AnActionEvent e) {
|
||||
if (myRepository.isFresh()) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
e.getPresentation().setDescription("Checkout is not possible before the first commit.");
|
||||
e.getPresentation().setDescription("Checkout is not possible before the first commit");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,10 @@ package git4idea.update;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsNotifier;
|
||||
import com.intellij.openapi.vcs.update.UpdatedFiles;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import git4idea.GitBranch;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.branch.GitBranchPair;
|
||||
@@ -78,42 +76,12 @@ public class GitRebaseUpdater extends GitUpdater {
|
||||
return dest.getName();
|
||||
}
|
||||
|
||||
// TODO
|
||||
//if (!checkLocallyModified(myRoot)) {
|
||||
// cancel();
|
||||
// updateSucceeded.set(false);
|
||||
//}
|
||||
|
||||
|
||||
// TODO: show at any case of update successfullibility, also don't show here but for all roots
|
||||
//if (mySkippedCommits.size() > 0) {
|
||||
// GitSkippedCommits.showSkipped(myProject, mySkippedCommits);
|
||||
//}
|
||||
|
||||
public void cancel() {
|
||||
myRebaser.abortRebase(myRoot);
|
||||
myProgressIndicator.setText2("Refreshing files for the root " + myRoot.getPath());
|
||||
myRoot.refresh(false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and process locally modified files
|
||||
*
|
||||
* @param root the project root
|
||||
* @param ex the exception holder
|
||||
*/
|
||||
protected boolean checkLocallyModified(final VirtualFile root) throws VcsException {
|
||||
final Ref<Boolean> cancelled = new Ref<Boolean>(false);
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
if (!GitUpdateLocallyModifiedDialog.showIfNeeded(myProject, root)) {
|
||||
cancelled.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
return !cancelled.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Rebase updater";
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="git4idea.update.GitUpdateLocallyModifiedDialog">
|
||||
<grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="514" height="322"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="62c84" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="git4idea/i18n/GitBundle" key="update.locally.modified.git.root"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="24443" class="javax.swing.JLabel" binding="myGitRoot">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="e43af" class="javax.swing.JLabel" binding="myDescriptionLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
<scrollpane class="com.intellij.ui.components.JBScrollPane" id="bde6e">
|
||||
<constraints>
|
||||
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="5d604" class="com.intellij.ui.components.JBList" binding="myFilesList" default-binding="true">
|
||||
<constraints/>
|
||||
<properties>
|
||||
<toolTipText resource-bundle="git4idea/i18n/GitBundle" key="update.locally.modified.files.tooltip"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</scrollpane>
|
||||
<component id="8f763" class="javax.swing.JButton" binding="myRescanButton" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="git4idea/i18n/GitBundle" key="update.locally.modified.rescan"/>
|
||||
<toolTipText resource-bundle="git4idea/i18n/GitBundle" key="update.locally.modified.rescan.tooltip"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="ab434" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="bde6e"/>
|
||||
<text resource-bundle="git4idea/i18n/GitBundle" key="update.locally.modified.files"/>
|
||||
<verticalAlignment value="0"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package git4idea.update;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitSimpleHandler;
|
||||
import git4idea.util.StringScanner;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.rollback.GitRollbackEnvironment;
|
||||
import git4idea.util.GitUIUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* The dialog that displays locally modified files during update process
|
||||
*/
|
||||
public class GitUpdateLocallyModifiedDialog extends DialogWrapper {
|
||||
/**
|
||||
* The rescan button
|
||||
*/
|
||||
private JButton myRescanButton;
|
||||
/**
|
||||
* The list of files to revert
|
||||
*/
|
||||
private JList myFilesList;
|
||||
|
||||
private JLabel myDescriptionLabel;
|
||||
/**
|
||||
* The git root label
|
||||
*/
|
||||
private JLabel myGitRoot;
|
||||
/**
|
||||
* The root panel
|
||||
*/
|
||||
private JPanel myRootPanel;
|
||||
/**
|
||||
* The collection with locally modified files
|
||||
*/
|
||||
private final List<String> myLocallyModifiedFiles;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param project the current project
|
||||
* @param root the vcs root
|
||||
* @param locallyModifiedFiles the collection of locally modified files to use
|
||||
*/
|
||||
protected GitUpdateLocallyModifiedDialog(final Project project, final VirtualFile root, List<String> locallyModifiedFiles) {
|
||||
super(project, true);
|
||||
myLocallyModifiedFiles = locallyModifiedFiles;
|
||||
setTitle(GitBundle.getString("update.locally.modified.title"));
|
||||
myGitRoot.setText(root.getPresentableUrl());
|
||||
myFilesList.setModel(new DefaultListModel());
|
||||
setOKButtonText(GitBundle.getString("update.locally.modified.revert"));
|
||||
syncListModel();
|
||||
myRescanButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myLocallyModifiedFiles.clear();
|
||||
try {
|
||||
scanFiles(project, root, myLocallyModifiedFiles);
|
||||
}
|
||||
catch (VcsException ex) {
|
||||
GitUIUtil.showOperationError(project, ex, "Checking for locally modified files");
|
||||
}
|
||||
}
|
||||
});
|
||||
myDescriptionLabel
|
||||
.setText(GitBundle.message("update.locally.modified.message", ApplicationNamesInfo.getInstance().getFullProductName()));
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh list model according to the current content of the collection
|
||||
*/
|
||||
private void syncListModel() {
|
||||
DefaultListModel listModel = (DefaultListModel)myFilesList.getModel();
|
||||
listModel.removeAllElements();
|
||||
for (String p : myLocallyModifiedFiles) {
|
||||
listModel.addElement(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return myRootPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String getDimensionServiceKey() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan working tree and detect locally modified files
|
||||
*
|
||||
* @param project the project to scan
|
||||
* @param root the root to scan
|
||||
* @param files the collection with files
|
||||
* @throws VcsException if there problem with running git or working tree is dirty in unsupported way
|
||||
*/
|
||||
private static void scanFiles(Project project, VirtualFile root, List<String> files) throws VcsException {
|
||||
String rootPath = root.getPath();
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.DIFF);
|
||||
h.addParameters("--name-status");
|
||||
h.setSilent(true);
|
||||
h.setStdoutSuppressed(true);
|
||||
StringScanner s = new StringScanner(h.run());
|
||||
while (s.hasMoreData()) {
|
||||
if (s.isEol()) {
|
||||
s.line();
|
||||
continue;
|
||||
}
|
||||
if (s.tryConsume("M\t")) {
|
||||
String path = rootPath + "/" + GitUtil.unescapePath(s.line());
|
||||
files.add(path);
|
||||
}
|
||||
else {
|
||||
throw new VcsException("Working tree is dirty in unsupported way: " + s.line());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the dialog if needed
|
||||
*
|
||||
* @param project the project
|
||||
* @param root the vcs root
|
||||
* @return true if showing is not needed or operation completed successfully
|
||||
*/
|
||||
public static boolean showIfNeeded(final Project project, final VirtualFile root) {
|
||||
final ArrayList<String> files = new ArrayList<String>();
|
||||
try {
|
||||
scanFiles(project, root, files);
|
||||
final AtomicBoolean rc = new AtomicBoolean(true);
|
||||
if (!files.isEmpty()) {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
GitUpdateLocallyModifiedDialog d = new GitUpdateLocallyModifiedDialog(project, root, files);
|
||||
d.show();
|
||||
rc.set(d.isOK());
|
||||
}
|
||||
});
|
||||
if (rc.get()) {
|
||||
if (!files.isEmpty()) {
|
||||
revertFiles(project, root, files);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc.get();
|
||||
}
|
||||
catch (final VcsException e) {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
GitUIUtil.showOperationError(project, e, "Checking for locally modified files");
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert files from the list
|
||||
*
|
||||
* @param project the project
|
||||
* @param root the vcs root
|
||||
* @param files the files to revert
|
||||
*/
|
||||
private static void revertFiles(Project project, VirtualFile root, ArrayList<String> files) throws VcsException {
|
||||
// TODO consider deleted files
|
||||
GitRollbackEnvironment rollback = GitRollbackEnvironment.getInstance(project);
|
||||
ArrayList<FilePath> list = new ArrayList<FilePath>(files.size());
|
||||
for (String p : files) {
|
||||
list.add(VcsUtil.getFilePath(p));
|
||||
}
|
||||
rollback.revert(root, list);
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,12 @@ import java.util.List;
|
||||
public class LocalChangesWouldBeOverwrittenHelper {
|
||||
|
||||
@NotNull
|
||||
public static String getErrorNotificationDescription() {
|
||||
private static String getErrorNotificationDescription() {
|
||||
return getErrorDescription(true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getErrorDialogDescription() {
|
||||
private static String getErrorDialogDescription() {
|
||||
return getErrorDescription(false);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class LocalChangesWouldBeOverwrittenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static void showErrorNotification(@NotNull final Project project, @NotNull VirtualFile root, @NotNull final String operationName,
|
||||
public static void showErrorNotification(@NotNull final Project project, @NotNull final VirtualFile root, @NotNull final String operationName,
|
||||
@NotNull final Collection<String> relativeFilePaths) {
|
||||
final Collection<String> absolutePaths = GitUtil.toAbsolute(root, relativeFilePaths);
|
||||
final List<Change> changes = GitUtil.findLocalChangesForPaths(project, root, absolutePaths, false);
|
||||
@@ -66,20 +66,33 @@ public class LocalChangesWouldBeOverwrittenHelper {
|
||||
@Override
|
||||
protected void hyperlinkActivated(@NotNull Notification notification,
|
||||
@NotNull HyperlinkEvent e) {
|
||||
String title = "Local Changes Prevent from " + StringUtil.capitalize(operationName);
|
||||
String description = getErrorDialogDescription();
|
||||
if (changes.isEmpty()) {
|
||||
GitUtil.showPathsInDialog(project, absolutePaths, title, description);
|
||||
}
|
||||
else {
|
||||
DialogBuilder builder = new DialogBuilder(project);
|
||||
builder.setNorthPanel(new MultiLineLabel(description));
|
||||
builder.setCenterPanel(new ChangesBrowserWithRollback(project, changes));
|
||||
builder.addOkAction();
|
||||
builder.setTitle(title);
|
||||
builder.show();
|
||||
}
|
||||
showErrorDialog(project, operationName, changes, absolutePaths);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void showErrorDialog(@NotNull Project project, @NotNull VirtualFile root, @NotNull String operationName,
|
||||
@NotNull Collection<String> relativeFilePaths) {
|
||||
Collection<String> absolutePaths = GitUtil.toAbsolute(root, relativeFilePaths);
|
||||
List<Change> changes = GitUtil.findLocalChangesForPaths(project, root, absolutePaths, false);
|
||||
showErrorDialog(project, operationName, changes, absolutePaths);
|
||||
}
|
||||
|
||||
private static void showErrorDialog(@NotNull Project project, @NotNull String operationName, @NotNull List<Change> changes,
|
||||
@NotNull Collection<String> absolutePaths) {
|
||||
String title = "Local Changes Prevent from " + StringUtil.capitalize(operationName);
|
||||
String description = getErrorDialogDescription();
|
||||
if (changes.isEmpty()) {
|
||||
GitUtil.showPathsInDialog(project, absolutePaths, title, description);
|
||||
}
|
||||
else {
|
||||
DialogBuilder builder = new DialogBuilder(project);
|
||||
builder.setNorthPanel(new MultiLineLabel(description));
|
||||
builder.setCenterPanel(new ChangesBrowserWithRollback(project, changes));
|
||||
builder.addOkAction();
|
||||
builder.setTitle(title);
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.jetbrains.plugins.github.util.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import static git4idea.commands.GitLocalChangesWouldBeOverwrittenDetector.Operation.CHECKOUT;
|
||||
import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled;
|
||||
|
||||
/**
|
||||
@@ -256,7 +257,9 @@ public class GithubRebaseAction extends DumbAwareAction {
|
||||
|
||||
final GitUntrackedFilesOverwrittenByOperationDetector untrackedFilesDetector =
|
||||
new GitUntrackedFilesOverwrittenByOperationDetector(root);
|
||||
final GitLocalChangesWouldBeOverwrittenDetector localChangesDetector = new GitLocalChangesWouldBeOverwrittenDetector(root, CHECKOUT);
|
||||
handler.addLineListener(untrackedFilesDetector);
|
||||
handler.addLineListener(localChangesDetector);
|
||||
|
||||
GitTask pullTask = new GitTask(project, handler, "Rebasing from upstream/master");
|
||||
pullTask.setProgressIndicator(indicator);
|
||||
@@ -271,7 +274,8 @@ public class GithubRebaseAction extends DumbAwareAction {
|
||||
|
||||
@Override
|
||||
protected void onFailure() {
|
||||
GitUpdateResult result = rebaser.handleRebaseFailure(handler, root, rebaseConflictDetector, untrackedFilesDetector);
|
||||
GitUpdateResult result = rebaser.handleRebaseFailure(handler, root, rebaseConflictDetector,
|
||||
untrackedFilesDetector, localChangesDetector);
|
||||
repositoryManager.updateRepository(root);
|
||||
if (result == GitUpdateResult.NOTHING_TO_UPDATE ||
|
||||
result == GitUpdateResult.SUCCESS ||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.jetbrains.plugins.groovy.lang.formatter
|
||||
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
|
||||
import org.jetbrains.plugins.groovy.GroovyLanguage
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
@@ -24,7 +25,7 @@ class WrappingTest extends GroovyFormatterTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp()
|
||||
myTempSettings.RIGHT_MARGIN = 10
|
||||
myTempSettings.setRightMargin(GroovyLanguage.INSTANCE, 10);
|
||||
}
|
||||
|
||||
void testWrapChainedMethodCalls() {
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.zmlx.hg4idea;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsNotifier;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.zmlx.hg4idea.action.HgCommandResultNotifier;
|
||||
import org.zmlx.hg4idea.command.HgPushCommand;
|
||||
import org.zmlx.hg4idea.execution.HgCommandResult;
|
||||
import org.zmlx.hg4idea.execution.HgCommandResultHandler;
|
||||
import org.zmlx.hg4idea.ui.HgPushDialog;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HgPusher {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(HgPusher.class);
|
||||
private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*added (\\d+) changesets.*");
|
||||
// hg push command has definite exit values for some cases:
|
||||
// mercurial returns 0 if push was successful, 1 if nothing to push. see hg push --help
|
||||
private static int PUSH_SUCCEEDED_EXIT_VALUE = 0;
|
||||
private static int NOTHING_TO_PUSH_EXIT_VALUE = 1;
|
||||
|
||||
private final Project myProject;
|
||||
|
||||
public HgPusher(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
/* public void showDialogAndPush(@NotNull List<? extends Repository> selectedRepositories) {
|
||||
|
||||
if (selectedRepositories.isEmpty()) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "No Mercurial repositories in the project", MessageType.ERROR);
|
||||
return;
|
||||
}
|
||||
final AtomicReference<HgPushCommand> pushCommand = new AtomicReference<HgPushCommand>();
|
||||
final HgPushDialog dialog = new HgPushDialog(myProject, repositories, selectedRepo);
|
||||
dialog.show();
|
||||
if (d2.isOK()) {
|
||||
pushCommand.set(preparePushCommand(myProject, dialog));
|
||||
new Task.Backgroundable(myProject, "Pushing...", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
if (pushCommand.get() != null) {
|
||||
push(myProject, pushCommand.get());
|
||||
}
|
||||
}
|
||||
}.queue();
|
||||
}
|
||||
}*/
|
||||
|
||||
public static void push(final Project project, HgPushCommand command) {
|
||||
final VirtualFile repo = command.getRepo();
|
||||
command.execute(new HgCommandResultHandler() {
|
||||
@Override
|
||||
public void process(@Nullable HgCommandResult result) {
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.getExitValue() == PUSH_SUCCEEDED_EXIT_VALUE) {
|
||||
int commitsNum = getNumberOfPushedCommits(result);
|
||||
String successTitle = "Pushed successfully";
|
||||
String successDescription = String.format("Pushed %d %s [%s]", commitsNum, StringUtil.pluralize("commit", commitsNum),
|
||||
repo.getPresentableName());
|
||||
VcsNotifier.getInstance(project).notifySuccess(successTitle, successDescription);
|
||||
}
|
||||
else if (result.getExitValue() == NOTHING_TO_PUSH_EXIT_VALUE) {
|
||||
VcsNotifier.getInstance(project).notifySuccess("Nothing to push");
|
||||
}
|
||||
else {
|
||||
new HgCommandResultNotifier(project).notifyError(result, "Push failed",
|
||||
"Failed to push to [" + repo.getPresentableName() + "]");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static HgPushCommand preparePushCommand(Project project, HgPushDialog dialog) {
|
||||
final HgPushCommand command = new HgPushCommand(project, dialog.getRepository().getRoot(), dialog.getTarget());
|
||||
command.setRevision(dialog.getRevision());
|
||||
command.setForce(dialog.isForce());
|
||||
command.setBranchName(dialog.getBranch());
|
||||
command.setBookmarkName(dialog.getBookmarkName());
|
||||
command.setIsNewBranch(dialog.isNewBranch());
|
||||
return command;
|
||||
}
|
||||
|
||||
private static int getNumberOfPushedCommits(HgCommandResult result) {
|
||||
int numberOfCommitsInAllSubrepos = 0;
|
||||
final List<String> outputLines = result.getOutputLines();
|
||||
for (String outputLine : outputLines) {
|
||||
outputLine = outputLine.trim();
|
||||
final Matcher matcher = PUSH_COMMITS_PATTERN.matcher(outputLine);
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
numberOfCommitsInAllSubrepos += Integer.parseInt(matcher.group(1));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
LOG.error("getNumberOfPushedCommits ", e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return numberOfCommitsInAllSubrepos;
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider {
|
||||
if (HgErrorUtil.isAbortLine(error)) {
|
||||
if (HgErrorUtil.isAuthorizationError(error)) {
|
||||
VcsError authorizationError =
|
||||
new VcsError(error + "<a href='authentificate'>" + LOGIN_AND_REFRESH_LINK + "</a>", new VcsErrorHandler() {
|
||||
new VcsError(error + "<a href='authenticate'>" + LOGIN_AND_REFRESH_LINK + "</a>", new VcsErrorHandler() {
|
||||
public void handleError(@NotNull CommitLoader commitLoader) {
|
||||
commitLoader.reloadCommits();
|
||||
}
|
||||
|
||||
+12
-5
@@ -16,16 +16,23 @@
|
||||
package org.zmlx.hg4idea.push;
|
||||
|
||||
import com.intellij.dvcs.push.PushSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class HgSource implements PushSource {
|
||||
String mySource;
|
||||
public class HgPushSource implements PushSource {
|
||||
@NotNull private String myBranch;
|
||||
|
||||
public HgSource(String branch) {
|
||||
mySource = branch;
|
||||
public HgPushSource(@NotNull String branch) {
|
||||
myBranch = branch;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentation() {
|
||||
return mySource;
|
||||
return myBranch;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getBranch() {
|
||||
return myBranch; // presentation may differ from branch
|
||||
}
|
||||
}
|
||||
@@ -80,9 +80,9 @@ public class HgPushSupport extends PushSupport<HgRepository> {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HgSource getSource(@NotNull HgRepository repository) {
|
||||
public HgPushSource getSource(@NotNull HgRepository repository) {
|
||||
String localBranch = HgUtil.getActiveBranchName(repository);
|
||||
return new HgSource(localBranch);
|
||||
return new HgPushSource(localBranch);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,16 +19,34 @@ import com.intellij.dvcs.push.PushSpec;
|
||||
import com.intellij.dvcs.push.Pusher;
|
||||
import com.intellij.dvcs.push.VcsPushOptionValue;
|
||||
import com.intellij.dvcs.repo.Repository;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsNotifier;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.zmlx.hg4idea.action.HgCommandResultNotifier;
|
||||
import org.zmlx.hg4idea.command.HgPushCommand;
|
||||
import org.zmlx.hg4idea.execution.HgCommandResult;
|
||||
import org.zmlx.hg4idea.execution.HgCommandResultHandler;
|
||||
import org.zmlx.hg4idea.repo.HgRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HgPusher extends Pusher {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(HgPusher.class);
|
||||
private static final String ONE = "one";
|
||||
private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*(?:added|pushed) (\\d+|" + ONE + ") changeset.*");
|
||||
// hg push command has definite exit values for some cases:
|
||||
// mercurial returns 0 if push was successful, 1 if nothing to push. see hg push --help
|
||||
private static int PUSH_SUCCEEDED_EXIT_VALUE = 0;
|
||||
private static int NOTHING_TO_PUSH_EXIT_VALUE = 1;
|
||||
|
||||
@Override
|
||||
public void push(@NotNull Map<Repository, PushSpec> pushSpecs, @Nullable VcsPushOptionValue vcsPushOptionValue, boolean force) {
|
||||
for (Map.Entry<Repository, PushSpec> entry : pushSpecs.entrySet()) {
|
||||
@@ -39,23 +57,71 @@ public class HgPusher extends Pusher {
|
||||
if (destination == null) {
|
||||
continue;
|
||||
}
|
||||
HgSource source = (HgSource)hgSpec.getSource();
|
||||
HgPushSource source = (HgPushSource)hgSpec.getSource();
|
||||
Project project = repository.getProject();
|
||||
final HgPushCommand pushCommand = new HgPushCommand(project, repository.getRoot(), destination.myTarget);
|
||||
pushCommand.setIsNewBranch(true); // set always true, because it just allow mercurial to create a new one if needed
|
||||
pushCommand.setForce(force);
|
||||
if (source.mySource.equals(hgRepository.getCurrentBookmark())) {
|
||||
String branchName = source.getBranch();
|
||||
if (branchName.equals(hgRepository.getCurrentBookmark())) {
|
||||
if (vcsPushOptionValue == HgVcsPushOptionValue.Current) {
|
||||
pushCommand.setBookmarkName(source.mySource);
|
||||
pushCommand.setBookmarkName(branchName);
|
||||
}
|
||||
else {
|
||||
pushCommand.setRevision(source.mySource);
|
||||
pushCommand.setRevision(branchName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
pushCommand.setBranchName(source.mySource);
|
||||
pushCommand.setBranchName(branchName);
|
||||
}
|
||||
org.zmlx.hg4idea.HgPusher.push(project, pushCommand);
|
||||
push(project, pushCommand);
|
||||
}
|
||||
}
|
||||
|
||||
public static void push(@NotNull final Project project, @NotNull HgPushCommand command) {
|
||||
final VirtualFile repo = command.getRepo();
|
||||
command.execute(new HgCommandResultHandler() {
|
||||
@Override
|
||||
public void process(@Nullable HgCommandResult result) {
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.getExitValue() == PUSH_SUCCEEDED_EXIT_VALUE) {
|
||||
int commitsNum = getNumberOfPushedCommits(result);
|
||||
String successTitle = "Pushed successfully";
|
||||
String successDescription = String.format("Pushed %d %s [%s]", commitsNum, StringUtil.pluralize("commit", commitsNum),
|
||||
repo.getPresentableName());
|
||||
VcsNotifier.getInstance(project).notifySuccess(successTitle, successDescription);
|
||||
}
|
||||
else if (result.getExitValue() == NOTHING_TO_PUSH_EXIT_VALUE) {
|
||||
VcsNotifier.getInstance(project).notifySuccess("Nothing to push");
|
||||
}
|
||||
else {
|
||||
new HgCommandResultNotifier(project).notifyError(result, "Push failed",
|
||||
"Failed to push to [" + repo.getPresentableName() + "]");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static int getNumberOfPushedCommits(@NotNull HgCommandResult result) {
|
||||
int numberOfCommitsInAllSubrepos = 0;
|
||||
final List<String> outputLines = result.getOutputLines();
|
||||
for (String outputLine : outputLines) {
|
||||
outputLine = outputLine.trim();
|
||||
final Matcher matcher = PUSH_COMMITS_PATTERN.matcher(outputLine);
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
String numberOfCommits = matcher.group(1);
|
||||
numberOfCommitsInAllSubrepos += ONE.equals(numberOfCommits) ? 1 : Integer.parseInt(numberOfCommits);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
LOG.error("getNumberOfPushedCommits ", e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return numberOfCommitsInAllSubrepos;
|
||||
}
|
||||
}
|
||||
|
||||
+32
-7
@@ -11,11 +11,13 @@ import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.VerticalFlowLayout;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.HyperlinkLabel;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -42,8 +44,10 @@ public class SceneBuilderEditor extends UserDataHolderBase implements FileEditor
|
||||
private final CardLayout myLayout = new CardLayout();
|
||||
private final JPanel myPanel = new JPanel(myLayout);
|
||||
|
||||
private final JPanel myErrorPanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 10, 5, true, false));
|
||||
//private final JPanel myErrorPanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 10, 5, true, false));
|
||||
private final JPanel myErrorPanel = new JPanel(new BorderLayout());
|
||||
private final HyperlinkLabel myErrorLabel = new HyperlinkLabel();
|
||||
private JTextArea myErrorStack;
|
||||
|
||||
private final Document myDocument;
|
||||
private final ExternalChangeListener myChangeListener;
|
||||
@@ -72,11 +76,19 @@ public class SceneBuilderEditor extends UserDataHolderBase implements FileEditor
|
||||
}
|
||||
});
|
||||
|
||||
myErrorPanel.add(myErrorLabel);
|
||||
myErrorStack = new JTextArea(50, 20);
|
||||
myErrorStack.setEditable(false);
|
||||
|
||||
myErrorPanel.add(myErrorLabel, BorderLayout.NORTH);
|
||||
myErrorPanel.add(ScrollPaneFactory.createScrollPane(myErrorStack), BorderLayout.CENTER);
|
||||
myPanel.add(myErrorPanel);
|
||||
}
|
||||
|
||||
private void showErrorPage(State state, Throwable e) {
|
||||
if (e != null) {
|
||||
LOG.info(e);
|
||||
}
|
||||
|
||||
removeSceneBuilder();
|
||||
|
||||
if (e == null) {
|
||||
@@ -93,12 +105,21 @@ public class SceneBuilderEditor extends UserDataHolderBase implements FileEditor
|
||||
}
|
||||
myErrorLabel.setIcon(Messages.getWarningIcon());
|
||||
}
|
||||
|
||||
myErrorStack.setText(null);
|
||||
myErrorStack.setVisible(false);
|
||||
}
|
||||
else {
|
||||
myErrorLabel.setHyperlinkText("Error: " + e.getMessage(), "", "");
|
||||
String message = e.getMessage();
|
||||
if (message == null) {
|
||||
message = e.getClass().getName();
|
||||
}
|
||||
|
||||
myErrorLabel.setHyperlinkText("Error: " + message, "", "");
|
||||
myErrorLabel.setIcon(Messages.getErrorIcon());
|
||||
|
||||
LOG.info(e);
|
||||
myErrorStack.setText(ExceptionUtil.getThrowableText(e));
|
||||
myErrorStack.setVisible(true);
|
||||
}
|
||||
myLayout.show(myPanel, ERROR_CARD);
|
||||
}
|
||||
@@ -139,8 +160,12 @@ public class SceneBuilderEditor extends UserDataHolderBase implements FileEditor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(Throwable e) {
|
||||
showErrorPage(null, e);
|
||||
public void handleError(final Throwable e) {
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
showErrorPage(null, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initSceneBuilder(boolean choosePathIfEmpty) {
|
||||
|
||||
+75
-27
@@ -11,6 +11,8 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -33,7 +35,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public class StudyCheckAction extends DumbAwareAction {
|
||||
|
||||
@@ -111,13 +114,26 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
if (openedFile != null) {
|
||||
StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
|
||||
final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
|
||||
List<VirtualFile> filesToDelete = new ArrayList<VirtualFile>();
|
||||
if (selectedTaskFile != null) {
|
||||
VirtualFile windowsDescription = StudyUtils.flushWindows(selectedEditor.getDocument(), selectedTaskFile, openedFile);
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
final VirtualFile taskDir = openedFile.getParent();
|
||||
Task currentTask = selectedTaskFile.getTask();
|
||||
StudyStatus oldStatus = currentTask.getStatus();
|
||||
Map<String, TaskFile> taskFiles = selectedTaskFile.getTask().getTaskFiles();
|
||||
for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
TaskFile taskFile = entry.getValue();
|
||||
VirtualFile virtualFile = taskDir.findChild(name);
|
||||
if (virtualFile == null) {
|
||||
continue;
|
||||
}
|
||||
VirtualFile windowFile = StudyUtils.flushWindows(FileDocumentManager.getInstance().getDocument(virtualFile), taskFile, virtualFile);
|
||||
filesToDelete.add(windowFile);
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
}
|
||||
|
||||
StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID);
|
||||
if (runAction != null) {
|
||||
if (runAction != null && currentTask.getTaskFiles().size() == 1) {
|
||||
runAction.run(project);
|
||||
}
|
||||
final StudyTestRunner testRunner = new StudyTestRunner(currentTask, taskDir);
|
||||
@@ -131,36 +147,68 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
if (testProcess != null) {
|
||||
String failedMessage = testRunner.getPassedTests(testProcess);
|
||||
if (failedMessage.equals(StudyTestRunner.TEST_OK)) {
|
||||
currentTask.setStatus(StudyStatus.Solved);
|
||||
currentTask.setStatus(StudyStatus.Solved, oldStatus);
|
||||
StudyUtils.updateStudyToolWindow(project);
|
||||
selectedTaskFile.drawAllWindows(selectedEditor);
|
||||
ProjectView.getInstance(project).refresh();
|
||||
for (VirtualFile file:filesToDelete) {
|
||||
try {
|
||||
file.delete(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
createTestResultPopUp("Congratulations!", JBColor.GREEN, project);
|
||||
return;
|
||||
}
|
||||
|
||||
final TaskFile taskFileCopy = new TaskFile();
|
||||
final VirtualFile copyWithAnswers = getCopyWithAnswers(taskDir, openedFile, selectedTaskFile, taskFileCopy);
|
||||
for (final TaskWindow taskWindow : taskFileCopy.getTaskWindows()) {
|
||||
if (!taskWindow.isValid(selectedEditor.getDocument())) {
|
||||
for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
TaskFile taskFile = entry.getValue();
|
||||
TaskFile answerTaskFile = new TaskFile();
|
||||
VirtualFile virtualFile = taskDir.findChild(name);
|
||||
if (virtualFile == null) {
|
||||
continue;
|
||||
}
|
||||
check(project, taskWindow, copyWithAnswers, taskFileCopy, selectedTaskFile, selectedEditor.getDocument(), testRunner,
|
||||
openedFile);
|
||||
VirtualFile answerFile = getCopyWithAnswers(taskDir, virtualFile, taskFile, answerTaskFile);
|
||||
for (TaskWindow taskWindow : answerTaskFile.getTaskWindows()) {
|
||||
Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
|
||||
if (document == null) {
|
||||
continue;
|
||||
}
|
||||
if (!taskWindow.isValid(document)) {
|
||||
continue;
|
||||
}
|
||||
check(project, taskWindow, answerFile, answerTaskFile, taskFile, document, testRunner, virtualFile);
|
||||
}
|
||||
FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile);
|
||||
Editor editor = null;
|
||||
if (fileEditor instanceof StudyEditor) {
|
||||
StudyEditor studyEditor = (StudyEditor) fileEditor;
|
||||
editor = studyEditor.getEditor();
|
||||
}
|
||||
|
||||
if (editor != null) {
|
||||
taskFile.drawAllWindows(editor);
|
||||
StudyUtils.synchronize();
|
||||
}
|
||||
try {
|
||||
answerFile.delete(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
copyWithAnswers.delete(this);
|
||||
for (VirtualFile file:filesToDelete) {
|
||||
try {
|
||||
file.delete(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
try {
|
||||
windowsDescription.delete(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error("failed to delete windows description", e);
|
||||
}
|
||||
selectedTaskFile.drawAllWindows(selectedEditor);
|
||||
currentTask.setStatus(StudyStatus.Failed, oldStatus);
|
||||
StudyUtils.updateStudyToolWindow(project);
|
||||
createTestResultPopUp(failedMessage, JBColor.RED, project);
|
||||
}
|
||||
}
|
||||
@@ -183,7 +231,7 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
VirtualFile openedFile) {
|
||||
|
||||
try {
|
||||
VirtualFile windowCopy = answerFile.copy(this, answerFile.getParent(), "window" + taskWindow.getIndex() + ".py");
|
||||
VirtualFile windowCopy = answerFile.copy(this, answerFile.getParent(), answerFile.getNameWithoutExtension() + "_window" + taskWindow.getIndex() + ".py");
|
||||
final FileDocumentManager documentManager = FileDocumentManager.getInstance();
|
||||
final Document windowDocument = documentManager.getDocument(windowCopy);
|
||||
if (windowDocument != null) {
|
||||
@@ -216,7 +264,7 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
VirtualFile fileWindows = StudyUtils.flushWindows(windowDocument, windowTaskFile, windowCopy);
|
||||
Process smartTestProcess = testRunner.launchTests(project, windowCopy.getPath());
|
||||
boolean res = testRunner.getPassedTests(smartTestProcess).equals(StudyTestRunner.TEST_OK);
|
||||
userTaskWindow.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed);
|
||||
userTaskWindow.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed, StudyStatus.Unchecked);
|
||||
windowCopy.delete(this);
|
||||
fileWindows.delete(this);
|
||||
if (!resourceFile.delete()) {
|
||||
@@ -240,7 +288,7 @@ public class StudyCheckAction extends DumbAwareAction {
|
||||
VirtualFile copy = null;
|
||||
try {
|
||||
|
||||
copy = file.copy(this, taskDir, "answers.py");
|
||||
copy = file.copy(this, taskDir, file.getNameWithoutExtension() +"_answers.py");
|
||||
final FileDocumentManager documentManager = FileDocumentManager.getInstance();
|
||||
final Document document = documentManager.getDocument(copy);
|
||||
if (document != null) {
|
||||
|
||||
+2
-7
@@ -81,13 +81,8 @@ public class StudyRefreshTaskAction extends DumbAwareAction {
|
||||
document.setText(patternText);
|
||||
StudyStatus oldStatus = currentTask.getStatus();
|
||||
LessonInfo lessonInfo = currentTask.getLesson().getLessonInfo();
|
||||
if (oldStatus == StudyStatus.Failed) {
|
||||
lessonInfo.setTaskFailed(lessonInfo.getTaskFailed() - 1);
|
||||
}
|
||||
if (oldStatus == StudyStatus.Solved) {
|
||||
lessonInfo.setTaskSolved(lessonInfo.getTaskSolved() - 1);
|
||||
}
|
||||
lessonInfo.setTaskUnchecked(lessonInfo.getTaskUnchecked() + 1);
|
||||
lessonInfo.update(oldStatus, -1);
|
||||
lessonInfo.update(StudyStatus.Unchecked, +1);
|
||||
StudyUtils.updateStudyToolWindow(project);
|
||||
for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) {
|
||||
taskWindow.reset();
|
||||
|
||||
+10
-1
@@ -67,12 +67,21 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction {
|
||||
if (taskDir == null) {
|
||||
return;
|
||||
}
|
||||
for (String name : nextTaskFiles.keySet()) {
|
||||
VirtualFile shouldBeActive = null;
|
||||
for (Map.Entry<String, TaskFile> entry : nextTaskFiles.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
TaskFile taskFile = entry.getValue();
|
||||
VirtualFile vf = taskDir.findChild(name);
|
||||
if (vf != null) {
|
||||
FileEditorManager.getInstance(project).openFile(vf, true);
|
||||
if (!taskFile.getTaskWindows().isEmpty()) {
|
||||
shouldBeActive = vf;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldBeActive != null) {
|
||||
FileEditorManager.getInstance(project).openFile(shouldBeActive, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract JButton getButton(StudyEditor selectedStudyEditor);
|
||||
|
||||
@@ -33,9 +33,9 @@ public class Lesson implements Stateful{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(StudyStatus status) {
|
||||
public void setStatus(StudyStatus status, StudyStatus oldStatus) {
|
||||
for (Task task : taskList) {
|
||||
task.setStatus(status);
|
||||
task.setStatus(status, oldStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,4 +40,21 @@ public class LessonInfo {
|
||||
public void setTaskUnchecked(int taskUnchecked) {
|
||||
myTaskUnchecked = taskUnchecked;
|
||||
}
|
||||
|
||||
public void update(StudyStatus status, int delta) {
|
||||
switch (status) {
|
||||
case Solved: {
|
||||
myTaskSolved += delta;
|
||||
break;
|
||||
}
|
||||
case Failed: {
|
||||
myTaskFailed += delta;
|
||||
break;
|
||||
}
|
||||
case Unchecked: {
|
||||
myTaskUnchecked += delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ package com.jetbrains.python.edu.course;
|
||||
|
||||
public interface Stateful {
|
||||
StudyStatus getStatus();
|
||||
void setStatus(StudyStatus status);
|
||||
void setStatus(StudyStatus status, StudyStatus oldStatus);
|
||||
}
|
||||
|
||||
@@ -55,21 +55,14 @@ public class Task implements Stateful{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setStatus(@NotNull final StudyStatus status) {
|
||||
public void setStatus(@NotNull final StudyStatus status, @NotNull final StudyStatus oldStatus) {
|
||||
LessonInfo lessonInfo = myLesson.getLessonInfo();
|
||||
StudyStatus oldStatus = getStatus();
|
||||
if (status != oldStatus) {
|
||||
if (status == StudyStatus.Failed) {
|
||||
lessonInfo.setTaskFailed(lessonInfo.getTaskFailed() + 1);
|
||||
lessonInfo.setTaskUnchecked(lessonInfo.getTaskUnchecked() - 1);
|
||||
}
|
||||
if (status == StudyStatus.Solved) {
|
||||
lessonInfo.setTaskSolved(lessonInfo.getTaskSolved() + 1);
|
||||
lessonInfo.setTaskUnchecked(lessonInfo.getTaskUnchecked() - 1);
|
||||
}
|
||||
for (TaskFile taskFile : taskFiles.values()) {
|
||||
taskFile.setStatus(status);
|
||||
}
|
||||
lessonInfo.update(oldStatus, -1);
|
||||
lessonInfo.update(status, +1);
|
||||
}
|
||||
for (TaskFile taskFile : taskFiles.values()) {
|
||||
taskFile.setStatus(status, oldStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -200,9 +200,9 @@ public class TaskFile implements Stateful{
|
||||
this.taskWindows = taskWindows;
|
||||
}
|
||||
|
||||
public void setStatus(@NotNull final StudyStatus status) {
|
||||
public void setStatus(@NotNull final StudyStatus status, @NotNull final StudyStatus oldStatus) {
|
||||
for (TaskWindow taskWindow : taskWindows) {
|
||||
taskWindow.setStatus(status);
|
||||
taskWindow.setStatus(status, oldStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public class TaskWindow implements Comparable, Stateful {
|
||||
return myStatus;
|
||||
}
|
||||
|
||||
public void setStatus(StudyStatus status) {
|
||||
public void setStatus(StudyStatus status, StudyStatus oldStatus) {
|
||||
myStatus = status;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ common.elem.phrasing |= math
|
||||
|
||||
SVG.foreignObject.content |=
|
||||
( math
|
||||
| html.elem
|
||||
| body.elem
|
||||
| common.inner.flow
|
||||
)
|
||||
|
||||
|
||||
@@ -377,6 +377,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
| common.attrs.aria.role.combobox
|
||||
| common.attrs.aria.role.dialog
|
||||
| common.attrs.aria.role.directory
|
||||
| common.attrs.aria.role.group
|
||||
| common.attrs.aria.role.heading
|
||||
| common.attrs.aria.role.img
|
||||
| common.attrs.aria.role.link
|
||||
@@ -425,7 +426,16 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
( common.attrs
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
| common.attrs.aria.role.button
|
||||
)?
|
||||
)
|
||||
summary.inner =
|
||||
( common.inner.phrasing )
|
||||
( common.inner.phrasing
|
||||
| h1.elem
|
||||
| h2.elem
|
||||
| h3.elem
|
||||
| h4.elem
|
||||
| h5.elem
|
||||
| h6.elem
|
||||
| hgroup.elem
|
||||
)
|
||||
|
||||
@@ -133,15 +133,7 @@ common.attrs.aria.implicit.toolbar |=
|
||||
& aria.prop.activedescendant?
|
||||
)
|
||||
|
||||
common.attrs.aria.implicit.columnheader |=
|
||||
( aria.prop.sort?
|
||||
& aria.prop.readonly?
|
||||
& aria.prop.required?
|
||||
& aria.state.selected?
|
||||
& aria.state.expanded?
|
||||
)
|
||||
|
||||
common.attrs.aria.implicit.rowheader |=
|
||||
common.attrs.aria.implicit.column-or-row-header |=
|
||||
( aria.prop.sort?
|
||||
& aria.prop.readonly?
|
||||
& aria.prop.required?
|
||||
|
||||
@@ -112,6 +112,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
& ol.attrs.reversed?
|
||||
& ol.attrs.type?
|
||||
& ( ( common.attrs.aria.role.directory
|
||||
| common.attrs.aria.role.group
|
||||
| common.attrs.aria.role.list
|
||||
| common.attrs.aria.role.listbox
|
||||
| common.attrs.aria.role.menu
|
||||
|
||||
@@ -113,9 +113,7 @@ common.attrs =
|
||||
)
|
||||
|
||||
common.attrs.basic =
|
||||
( ( common.attrs.id
|
||||
| common.attrs.xml-id
|
||||
)? # REVISIT assuming only either one is allowed
|
||||
( common.attrs.id?
|
||||
& common.attrs.class?
|
||||
& common.attrs.title?
|
||||
& common.attrs.base?
|
||||
@@ -125,10 +123,6 @@ common.attrs.basic =
|
||||
attribute id {
|
||||
common.data.id
|
||||
}
|
||||
common.attrs.xml-id =
|
||||
attribute xml:id {
|
||||
xsd:NCName
|
||||
} & XMLonly
|
||||
common.attrs.class =
|
||||
attribute class {
|
||||
common.data.tokens
|
||||
@@ -387,6 +381,10 @@ common.attrs.other =
|
||||
common.data.keylabellist =
|
||||
w:keylabellist
|
||||
|
||||
## List of Source Sizes
|
||||
common.data.source.size.list =
|
||||
w:source-size-list
|
||||
|
||||
## Microdata Properties
|
||||
common.data.microdata-properties =
|
||||
list { w:microdata-property+ }
|
||||
@@ -466,7 +464,7 @@ common.attrs.aria.implicit.article = ( notAllowed )
|
||||
common.attrs.aria.implicit.banner = ( notAllowed )
|
||||
common.attrs.aria.implicit.button = ( notAllowed )
|
||||
common.attrs.aria.implicit.checkbox = ( notAllowed )
|
||||
common.attrs.aria.implicit.columnheader = ( notAllowed )
|
||||
common.attrs.aria.implicit.column-or-row-header = ( notAllowed )
|
||||
common.attrs.aria.implicit.combobox = ( notAllowed )
|
||||
common.attrs.aria.implicit.complementary = ( notAllowed )
|
||||
common.attrs.aria.implicit.contentinfo = ( notAllowed )
|
||||
@@ -486,7 +484,6 @@ common.attrs.aria.implicit.option = ( notAllowed )
|
||||
common.attrs.aria.implicit.progressbar = ( notAllowed )
|
||||
common.attrs.aria.implicit.radio = ( notAllowed )
|
||||
common.attrs.aria.implicit.region = ( notAllowed )
|
||||
common.attrs.aria.implicit.rowheader = ( notAllowed )
|
||||
common.attrs.aria.implicit.section = ( notAllowed )
|
||||
common.attrs.aria.implicit.select = ( notAllowed )
|
||||
common.attrs.aria.implicit.slider = ( notAllowed )
|
||||
|
||||
@@ -15,6 +15,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
( common.attrs
|
||||
& script.attrs.type?
|
||||
& script.attrs.language? # restricted in Schematron
|
||||
& embedded.content.attrs.crossorigin?
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
@@ -29,6 +30,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
& script.attrs.type?
|
||||
& script.attrs.charset?
|
||||
& script.attrs.language? # restricted in Schematron
|
||||
& embedded.content.attrs.crossorigin?
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
|
||||
@@ -15,12 +15,15 @@ namespace local = ""
|
||||
img.attrs =
|
||||
( common.attrs
|
||||
& img.attrs.src
|
||||
& img.attrs.srcset?
|
||||
& img.attrs.sizes?
|
||||
& img.attrs.alt? # ARIA: if alt empty, only allowed role value is "presentation"; check in assertions
|
||||
& img.attrs.height?
|
||||
& img.attrs.width?
|
||||
& img.attrs.usemap?
|
||||
& img.attrs.ismap?
|
||||
& img.attrs.border? # obsolete
|
||||
& embedded.content.attrs.crossorigin?
|
||||
& ( common.attrs.aria.implicit.img
|
||||
| common.attrs.aria
|
||||
)?
|
||||
@@ -29,6 +32,14 @@ namespace local = ""
|
||||
attribute src {
|
||||
common.data.uri.non-empty
|
||||
}
|
||||
img.attrs.srcset =
|
||||
attribute srcset {
|
||||
string
|
||||
} & v5only
|
||||
img.attrs.sizes =
|
||||
attribute sizes {
|
||||
common.data.source.size.list
|
||||
} & v5only
|
||||
img.attrs.alt =
|
||||
attribute alt {
|
||||
text
|
||||
@@ -58,6 +69,54 @@ namespace local = ""
|
||||
|
||||
common.elem.phrasing |= img.elem
|
||||
|
||||
## Image with multiple sources: <picture>
|
||||
|
||||
picture.elem =
|
||||
element picture { picture.inner & picture.attrs }
|
||||
& v5only
|
||||
picture.attrs =
|
||||
( common.attrs )
|
||||
picture.inner =
|
||||
( ( source.picture.elem*
|
||||
& common.elem.script-supporting*
|
||||
),
|
||||
( img.elem
|
||||
& common.elem.script-supporting*
|
||||
)
|
||||
)
|
||||
|
||||
common.elem.phrasing |= picture.elem
|
||||
|
||||
## Picture source: <source srcset>
|
||||
|
||||
source.picture.elem =
|
||||
element source { source.picture.inner & source.picture.attrs }
|
||||
source.picture.attrs =
|
||||
( common.attrs
|
||||
& source.picture.attrs.media?
|
||||
& source.picture.attrs.srcset
|
||||
& source.picture.attrs.sizes?
|
||||
& source.picture.attrs.type?
|
||||
)
|
||||
source.picture.attrs.media =
|
||||
attribute media {
|
||||
common.data.mediaquery
|
||||
}
|
||||
source.picture.attrs.srcset =
|
||||
attribute srcset {
|
||||
string
|
||||
}
|
||||
source.picture.attrs.sizes =
|
||||
attribute sizes {
|
||||
common.data.source.size.list
|
||||
}
|
||||
source.picture.attrs.type =
|
||||
attribute type {
|
||||
common.data.mimetype
|
||||
}
|
||||
source.picture.inner =
|
||||
( empty )
|
||||
|
||||
## Plug-ins: <embed>
|
||||
|
||||
embed.elem =
|
||||
@@ -72,6 +131,7 @@ namespace local = ""
|
||||
& ( common.attrs.aria.landmark.application
|
||||
| common.attrs.aria.landmark.document
|
||||
| common.attrs.aria.role.img
|
||||
| common.attrs.aria.role.presentation
|
||||
)?
|
||||
)
|
||||
embed.attrs.src =
|
||||
@@ -292,6 +352,7 @@ namespace local = ""
|
||||
& ( common.attrs.aria.landmark.application
|
||||
| common.attrs.aria.landmark.document
|
||||
| common.attrs.aria.role.img
|
||||
| common.attrs.aria.role.presentation
|
||||
)?
|
||||
)
|
||||
object.attrs.data =
|
||||
@@ -370,6 +431,7 @@ namespace local = ""
|
||||
& ( common.attrs.aria.landmark.application
|
||||
| common.attrs.aria.landmark.document
|
||||
| common.attrs.aria.role.img
|
||||
| common.attrs.aria.role.presentation
|
||||
)?
|
||||
)
|
||||
iframe.attrs.src =
|
||||
@@ -548,7 +610,7 @@ namespace local = ""
|
||||
w:string "allowfullscreen" | w:string ""
|
||||
} & v5only
|
||||
iframe.inner =
|
||||
( text )
|
||||
( ( text & HTMLonly ) | empty )
|
||||
|
||||
common.elem.phrasing |= iframe.elem
|
||||
|
||||
@@ -655,3 +717,10 @@ namespace local = ""
|
||||
( empty )
|
||||
|
||||
common.elem.phrasing |= area.elem
|
||||
|
||||
## Attributes Common to Embedded Content
|
||||
|
||||
embedded.content.attrs.crossorigin =
|
||||
attribute crossorigin {
|
||||
w:string "anonymous" | w:string "use-credentials" | w:string ""
|
||||
} & v5only
|
||||
|
||||
@@ -812,6 +812,12 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
}
|
||||
object.attrs &= object.attrs.border?
|
||||
|
||||
table.attrs.border =
|
||||
attribute border {
|
||||
string
|
||||
}
|
||||
table.attrs &= table.attrs.border?
|
||||
|
||||
## cellpadding attribute
|
||||
|
||||
table.attrs.cellpadding =
|
||||
|
||||
@@ -14,6 +14,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
& media.attrs.loop?
|
||||
& media.attrs.mediagroup?
|
||||
& media.attrs.muted?
|
||||
& embedded.content.attrs.crossorigin?
|
||||
)
|
||||
media.attrs.autoplay =
|
||||
attribute autoplay {
|
||||
@@ -48,7 +49,6 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
( common.attrs
|
||||
& source.attrs.src
|
||||
& source.attrs.type?
|
||||
& source.attrs.media?
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
@@ -61,10 +61,6 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
attribute type {
|
||||
common.data.mimetype
|
||||
}
|
||||
source.attrs.media =
|
||||
attribute media {
|
||||
common.data.mediaquery
|
||||
}
|
||||
source.inner =
|
||||
( empty )
|
||||
|
||||
|
||||
@@ -164,6 +164,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
& shared-hyperlink.attrs.type?
|
||||
& link.attrs.sizes?
|
||||
# link.attrs.title included in common.attrs
|
||||
& embedded.content.attrs.crossorigin?
|
||||
& ( common.attrs.aria.role.link
|
||||
| common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
|
||||
@@ -25,7 +25,7 @@ common.attrs.microdata =
|
||||
}
|
||||
common.attrs.microdata.itemtype =
|
||||
attribute itemtype {
|
||||
common.data.uri.absolute
|
||||
list { common.data.uri.absolute+ }
|
||||
}
|
||||
common.attrs.microdata.itemid =
|
||||
attribute itemid {
|
||||
@@ -58,6 +58,7 @@ base.attrs &= common.attrs.microdata
|
||||
& shared-hyperlink.attrs.type?
|
||||
& link.attrs.sizes?
|
||||
# link.attrs.title included in common.attrs
|
||||
& embedded.content.attrs.crossorigin?
|
||||
& ( common.attrs.aria.role.link
|
||||
| common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
nonRDFaLite = empty
|
||||
# #####################################################################
|
||||
# #####################################################################
|
||||
## RELAX NG Schema for HTML 5: RDFa 1.1 and RDFa Lite 1.1 #
|
||||
# #####################################################################
|
||||
|
||||
@@ -9,12 +9,12 @@ nonRDFaLite = empty
|
||||
|
||||
common.data.rdfa.safecurie =
|
||||
xsd:string {
|
||||
pattern = "\[(([\i-[:]][\c-[:]]*)?:)?[^\s]+\]"
|
||||
minLength = "3"
|
||||
pattern = "\[(([\i-[:]][\c-[:]]*)?:?)[^\s]*\]"
|
||||
minLength = "2"
|
||||
}
|
||||
common.data.rdfa.curie =
|
||||
xsd:string {
|
||||
pattern = "(([\i-[:]][\c-[:]]*)?:)?[^\s]+"
|
||||
pattern = "(([\i-[:]][\c-[:]]*)?:)[^\s]*"
|
||||
minLength = "1"
|
||||
}
|
||||
common.data.rdfa.term =
|
||||
@@ -182,15 +182,11 @@ link.rdfa.attrs.metadata =
|
||||
& common.attrs.present
|
||||
& common.attrs.other
|
||||
& ( ( common.attrs.rdfa.property
|
||||
& ( link.attrs.rel
|
||||
| common.attrs.rdfa.rel
|
||||
)?
|
||||
& link.attrs.rel?
|
||||
)
|
||||
|
|
||||
( common.attrs.rdfa.property?
|
||||
& ( link.attrs.rel
|
||||
| common.attrs.rdfa.rel
|
||||
)
|
||||
& link.attrs.rel
|
||||
)
|
||||
)
|
||||
& link.attrs.href
|
||||
@@ -208,6 +204,11 @@ link.rdfa.attrs.metadata =
|
||||
& shared-hyperlink.attrs.type?
|
||||
& link.attrs.sizes?
|
||||
# link.attrs.title included in common.attrs
|
||||
& embedded.content.attrs.crossorigin?
|
||||
& ( common.attrs.aria.role.link
|
||||
| common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
)
|
||||
link.rdfa.attrs.phrasing =
|
||||
( common.attrs.basic
|
||||
@@ -215,9 +216,7 @@ link.rdfa.attrs.phrasing =
|
||||
& common.attrs.present
|
||||
& common.attrs.other
|
||||
& common.attrs.rdfa.property
|
||||
& ( link.attrs.rel
|
||||
| common.attrs.rdfa.rel
|
||||
)?
|
||||
& link.attrs.rel?
|
||||
& ( ( common.attrs.rdfa.resource
|
||||
& link.attrs.href?
|
||||
)
|
||||
@@ -239,6 +238,11 @@ link.rdfa.attrs.phrasing =
|
||||
& shared-hyperlink.attrs.type?
|
||||
& link.attrs.sizes?
|
||||
# link.attrs.title included in common.attrs
|
||||
& embedded.content.attrs.crossorigin?
|
||||
& ( common.attrs.aria.role.link
|
||||
| common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
)
|
||||
common.elem.metadata |= link.rdfa.elem.metadata
|
||||
common.elem.phrasing |= link.rdfa.elem.phrasing
|
||||
|
||||
@@ -50,13 +50,8 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
element table { table.inner & table.attrs }
|
||||
table.attrs =
|
||||
( common.attrs
|
||||
& table.attrs.border?
|
||||
& common.attrs.aria?
|
||||
)
|
||||
table.attrs.border =
|
||||
attribute border {
|
||||
string
|
||||
}
|
||||
table.inner =
|
||||
( caption.elem?
|
||||
, common.elem.script-supporting*
|
||||
@@ -84,9 +79,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
element caption { caption.inner & caption.attrs }
|
||||
caption.attrs =
|
||||
( common.attrs
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
& common.attrs.aria?
|
||||
)
|
||||
caption.inner =
|
||||
( common.inner.flow )
|
||||
@@ -100,9 +93,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
element colgroup { colgroup.inner & colgroup.attrs }
|
||||
colgroup.attrs =
|
||||
( common.attrs
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
& common.attrs.aria?
|
||||
)
|
||||
colgroup.attrs.span =
|
||||
attribute span {
|
||||
@@ -122,9 +113,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
col.attrs =
|
||||
( common.attrs
|
||||
& col.attrs.span?
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
& common.attrs.aria?
|
||||
)
|
||||
col.attrs.span =
|
||||
attribute span {
|
||||
@@ -139,9 +128,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
element thead { thead.inner & thead.attrs }
|
||||
thead.attrs =
|
||||
( common.attrs
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
& common.attrs.aria?
|
||||
)
|
||||
thead.inner =
|
||||
( tr.elem*
|
||||
@@ -154,9 +141,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
element tfoot { tfoot.inner & tfoot.attrs }
|
||||
tfoot.attrs =
|
||||
( common.attrs
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
& common.attrs.aria?
|
||||
)
|
||||
tfoot.inner =
|
||||
( tr.elem*
|
||||
@@ -169,9 +154,7 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
element tbody { tbody.inner & tbody.attrs }
|
||||
tbody.attrs =
|
||||
( common.attrs
|
||||
& ( common.attrs.aria.role.presentation
|
||||
| common.attrs.aria.role.menuitem
|
||||
)?
|
||||
& common.attrs.aria?
|
||||
)
|
||||
tbody.inner =
|
||||
( tr.elem*
|
||||
@@ -253,7 +236,9 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
& tables.attrs.scope?
|
||||
& tables.attrs.headers?
|
||||
# & tables.attrs.alignment
|
||||
& common.attrs.aria?
|
||||
& ( common.attrs.aria?
|
||||
| common.attrs.aria.implicit.column-or-row-header
|
||||
)
|
||||
)
|
||||
th.inner =
|
||||
( common.inner.flow )
|
||||
|
||||
@@ -812,6 +812,12 @@ datatypes w = "http://whattf.org/datatype-draft"
|
||||
}
|
||||
object.attrs &= object.attrs.border?
|
||||
|
||||
table.attrs.border =
|
||||
attribute border {
|
||||
string
|
||||
}
|
||||
table.attrs &= table.attrs.border?
|
||||
|
||||
## cellpadding attribute
|
||||
|
||||
table.attrs.cellpadding =
|
||||
|
||||
@@ -97,7 +97,7 @@ grammar {
|
||||
attribute overline-thickness { Number.datatype }?
|
||||
a:documentation [ "\x{a}" ~ " glyph: Glyph Element\x{a}" ~ " " ]
|
||||
SVG.glyph.class = notAllowed
|
||||
SVG.glyph.content = SVG.Description.class*, SVG.glyph.class*
|
||||
SVG.glyph.content = SVG.Description.class* | SVG.glyph.class*
|
||||
glyph = element glyph { attlist.glyph, SVG.glyph.content }
|
||||
attlist.glyph &=
|
||||
SVG.Core.attrib,
|
||||
@@ -120,7 +120,7 @@ grammar {
|
||||
]
|
||||
SVG.missing-glyph.class = notAllowed
|
||||
SVG.missing-glyph.content =
|
||||
SVG.Description.class*, SVG.missing-glyph.class*
|
||||
SVG.Description.class* | SVG.missing-glyph.class*
|
||||
missing-glyph =
|
||||
element missing-glyph {
|
||||
attlist.missing-glyph, SVG.missing-glyph.content
|
||||
|
||||
@@ -62,8 +62,7 @@ grammar {
|
||||
| SVG.Conditional.class
|
||||
| SVG.Image.class
|
||||
| SVG.Shape.class
|
||||
| SVG.Hyperlink.class
|
||||
| SVG.Extensibility.class)*
|
||||
| SVG.Hyperlink.class)*
|
||||
switch = element switch { attlist.switch, SVG.switch.content }
|
||||
attlist.switch &=
|
||||
SVG.Core.attrib,
|
||||
|
||||
@@ -57,3 +57,14 @@ foreignElement =
|
||||
| text
|
||||
| foreignElement)*
|
||||
}
|
||||
SVG.a.content &= SVG.Extensibility.class*
|
||||
SVG.defs.content &= SVG.Extensibility.class*
|
||||
SVG.glyph.content &= SVG.Extensibility.class*
|
||||
SVG.g.content &= SVG.Extensibility.class*
|
||||
SVG.marker.content &= SVG.Extensibility.class*
|
||||
SVG.mask.content &= SVG.Extensibility.class*
|
||||
SVG.missing-glyph.content &= SVG.Extensibility.class*
|
||||
SVG.pattern.content &= SVG.Extensibility.class*
|
||||
SVG.svg.content &= SVG.Extensibility.class*
|
||||
SVG.switch.content &= SVG.Extensibility.class*
|
||||
SVG.symbol.content &= SVG.Extensibility.class*
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
- shared-hyperlink.attrs.ping =
|
||||
- attribute ping {
|
||||
- common.data.uris
|
||||
- } & v5only & nonW3C
|
||||
- } & v5only
|
||||
|
||||
## Emphatic Stress: <em>
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
diff -r dd84d714a0da build.py
|
||||
--- a/build.py Fri Oct 25 13:00:39 2013 +0900
|
||||
+++ b/build.py Fri Jan 24 13:53:06 2014 +0400
|
||||
@@ -147,8 +147,8 @@
|
||||
diff --git a/build.py b/build.py
|
||||
index ac7ecb3..db7de9c 100755
|
||||
--- a/build.py
|
||||
+++ b/build.py
|
||||
@@ -153,13 +153,13 @@ dependencyJars = runDependencyJars + buildOnlyDependencyJars
|
||||
|
||||
moduleNames = [
|
||||
"syntax",
|
||||
@@ -10,9 +11,18 @@ diff -r dd84d714a0da build.py
|
||||
+ # "util",
|
||||
+ # "xmlparser",
|
||||
"validator",
|
||||
- "jing-trang",
|
||||
- "htmlparser",
|
||||
- "nu-validator-site",
|
||||
- "tests",
|
||||
+ # "jing-trang",
|
||||
+ # "htmlparser",
|
||||
+ # "nu-validator-site",
|
||||
+ # "tests",
|
||||
]
|
||||
|
||||
@@ -875,19 +875,19 @@
|
||||
javaSafeNamePat = re.compile(r'[^a-zA-Z0-9]')
|
||||
@@ -926,19 +926,19 @@ def downloadDependencies():
|
||||
downloadDependency(url, md5sum)
|
||||
|
||||
def buildAll():
|
||||
@@ -42,36 +52,5 @@ diff -r dd84d714a0da build.py
|
||||
+ # buildXmlParser()
|
||||
+ # buildValidator()
|
||||
|
||||
def hgCloneOrUpdate(mod, baseUrl):
|
||||
def gitCloneOrUpdate(mod, baseUrl):
|
||||
if os.path.exists(mod):
|
||||
@@ -925,18 +925,18 @@
|
||||
# XXX root dir
|
||||
for mod in moduleNames:
|
||||
hgCloneOrUpdate(mod, hgRoot)
|
||||
- gitCloneOrUpdate("nu-validator-site", gitRoot)
|
||||
- runCmd('"%s" co http://jing-trang.googlecode.com/svn/branches/validator-nu jing-trang' % (svnCmd))
|
||||
- hgCloneOrUpdate("htmlparser", parserHgRoot)
|
||||
- testsRemote = "https://github.com/validator/tests.git"
|
||||
- testsBranch = "master"
|
||||
- testsDir = "tests"
|
||||
- if os.path.exists(testsDir):
|
||||
- os.chdir(testsDir)
|
||||
- runCmd('"%s" pull %s %s' % (gitCmd, testsRemote, testsBranch))
|
||||
- os.chdir("..")
|
||||
- else:
|
||||
- runCmd('"%s" clone %s %s' % (gitCmd, testsRemote, testsDir))
|
||||
+ # gitCloneOrUpdate("nu-validator-site", gitRoot)
|
||||
+ # runCmd('"%s" co http://jing-trang.googlecode.com/svn/branches/validator-nu jing-trang' % (svnCmd))
|
||||
+ # hgCloneOrUpdate("htmlparser", parserHgRoot)
|
||||
+ # testsRemote = "https://github.com/validator/tests.git"
|
||||
+ # testsBranch = "master"
|
||||
+ # testsDir = "tests"
|
||||
+ # if os.path.exists(testsDir):
|
||||
+ # os.chdir(testsDir)
|
||||
+ # runCmd('"%s" pull %s %s' % (gitCmd, testsRemote, testsBranch))
|
||||
+ # os.chdir("..")
|
||||
+ # else:
|
||||
+ # runCmd('"%s" clone %s %s' % (gitCmd, testsRemote, testsDir))
|
||||
|
||||
def selfUpdate():
|
||||
hgCloneOrUpdate("build", hgRoot)
|
||||
|
||||
@@ -11,9 +11,9 @@ mkdir temp
|
||||
cd temp
|
||||
|
||||
echo ">>>>> Preparing validator build"
|
||||
hg clone https://bitbucket.org/validator/build build
|
||||
git clone https://github.com/validator/build build
|
||||
cd build
|
||||
hg import "$PATCHES/patch_build.patch" --no-commit
|
||||
git apply "$PATCHES/patch_build.patch"
|
||||
cd ..
|
||||
|
||||
echo
|
||||
|
||||
Reference in New Issue
Block a user