diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java index 82cf36946b9e..346a4446090a 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java @@ -885,13 +885,13 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, getTools(toolId, project).removeScope(scopeIdx); } - public void removeScope(@NotNull String toolId, @NotNull NamedScope scope, Project project) { - getTools(toolId, project).removeScope(scope); + public void removeScope(@NotNull String toolId, @NotNull String scopeName, Project project) { + getTools(toolId, project).removeScope(scopeName); } - public void removeScopes(@NotNull List toolIds, @NotNull NamedScope scope, Project project) { + public void removeScopes(@NotNull List toolIds, @NotNull String scopeName, Project project) { for (final String toolId : toolIds) { - removeScope(toolId, scope, project); + removeScope(toolId, scopeName, project); } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java index 267c0ee67fc3..caeb02a2316f 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java @@ -267,25 +267,26 @@ public class ToolsImpl implements Tools { public void removeScope(int scopeIdx) { if (myTools != null && scopeIdx >= 0 && myTools.size() > scopeIdx) { myTools.remove(scopeIdx); - if (myTools.isEmpty()) { - myTools = null; - setEnabled(myDefaultState.isEnabled()); - } + checkToolsIsEmpty(); } } - public void removeScope(final NamedScope scope) { + public void removeScope(final @NotNull String scopeName) { if (myTools != null) { - for (final ScopeToolState tool : myTools) { - if (Comparing.equal(tool.getScopeName(), scope.getName())) { + for (ScopeToolState tool : myTools) { + if (scopeName.equals(tool.getScopeName())) { myTools.remove(tool); break; } } - if (myTools.isEmpty()) { - myTools = null; - setEnabled(myDefaultState.isEnabled()); - } + checkToolsIsEmpty(); + } + } + + private void checkToolsIsEmpty() { + if (myTools.isEmpty()) { + myTools = null; + setEnabled(myDefaultState.isEnabled()); } } diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingRegionsPopup.java b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingRegionsPopup.java new file mode 100644 index 000000000000..203179709dae --- /dev/null +++ b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingRegionsPopup.java @@ -0,0 +1,133 @@ +/* + * 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.lang.customFolding; + +import com.intellij.ide.IdeBundle; +import com.intellij.lang.folding.FoldingDescriptor; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.PopupChooserBuilder; +import com.intellij.psi.PsiElement; +import com.intellij.ui.components.JBList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.*; + +/** + * @author Rustam Vishnyakov + */ +public class CustomFoldingRegionsPopup { + private final @NotNull JBList myRegionsList; + private final @NotNull JBPopup myPopup; + private final @NotNull Editor myEditor; + + CustomFoldingRegionsPopup(@NotNull Collection descriptors, + @NotNull final Editor editor, + @NotNull final Project project) { + myEditor = editor; + myRegionsList = new JBList(); + //noinspection unchecked + myRegionsList.setModel(new MyListModel(orderByPosition(descriptors))); + myRegionsList.setSelectedIndex(0); + + final PopupChooserBuilder popupBuilder = JBPopupFactory.getInstance().createListPopupBuilder(myRegionsList); + myPopup = popupBuilder + .setTitle(IdeBundle.message("goto.custom.region.command")) + .setResizable(false) + .setMovable(false) + .setItemChoosenCallback(new Runnable() { + @Override + public void run() { + PsiElement navigationElement = getNavigationElement(); + if (navigationElement != null) { + navigateTo(editor, navigationElement); + IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation(); + } + } + }).createPopup(); + } + + void show() { + myPopup.showInBestPositionFor(myEditor); + } + + private static class MyListModel extends DefaultListModel { + private MyListModel(Collection descriptors) { + for (FoldingDescriptor descriptor : descriptors) { + //noinspection unchecked + super.addElement(new MyFoldingDescriptorWrapper(descriptor)); + } + } + } + + private static class MyFoldingDescriptorWrapper { + private final @NotNull FoldingDescriptor myDescriptor; + + private MyFoldingDescriptorWrapper(@NotNull FoldingDescriptor descriptor) { + myDescriptor = descriptor; + } + + @NotNull + public FoldingDescriptor getDescriptor() { + return myDescriptor; + } + + @Nullable + @Override + public String toString() { + return myDescriptor.getPlaceholderText(); + } + } + + @Nullable + public PsiElement getNavigationElement() { + Object selection = myRegionsList.getSelectedValue(); + if (selection instanceof MyFoldingDescriptorWrapper) { + return ((MyFoldingDescriptorWrapper)selection).getDescriptor().getElement().getPsi(); + } + return null; + } + + private static Collection orderByPosition(Collection descriptors) { + List sorted = new ArrayList(descriptors.size()); + sorted.addAll(descriptors); + Collections.sort(sorted, new Comparator() { + @Override + public int compare(FoldingDescriptor descriptor1, FoldingDescriptor descriptor2) { + int pos1 = descriptor1.getElement().getTextRange().getStartOffset(); + int pos2 = descriptor2.getElement().getTextRange().getStartOffset(); + return pos1 - pos2; + } + }); + return sorted; + } + + private static void navigateTo(@NotNull Editor editor, @NotNull PsiElement element) { + int offset = element.getTextRange().getStartOffset(); + if (offset >= 0 && offset < editor.getDocument().getTextLength()) { + editor.getCaretModel().removeSecondaryCarets(); + editor.getCaretModel().moveToOffset(offset); + editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + editor.getSelectionModel().removeSelection(); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java index 016f7f14cc4d..e0117affbcad 100644 --- a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java +++ b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java @@ -16,26 +16,35 @@ package com.intellij.lang.customFolding; import com.intellij.ide.IdeBundle; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.lang.Language; +import com.intellij.lang.folding.*; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Disposer; +import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.util.containers.HashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Set; /** * @author Rustam Vishnyakov */ -public class GotoCustomRegionAction extends AnAction implements DumbAware { +public class GotoCustomRegionAction extends AnAction implements DumbAware, PopupAction { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(final AnActionEvent e) { final Project project = e.getProject(); final Editor editor = e.getData(CommonDataKeys.EDITOR); if (Boolean.TRUE.equals(e.getData(PlatformDataKeys.IS_MODAL_CONTEXT))) { @@ -52,14 +61,13 @@ public class GotoCustomRegionAction extends AnAction implements DumbAware { new Runnable() { @Override public void run() { - GotoCustomRegionDialog dialog = new GotoCustomRegionDialog(project, editor); - dialog.show(); - if (dialog.isOK()) { - PsiElement navigationElement = dialog.getNavigationElement(); - if (navigationElement != null) { - navigateTo(editor, navigationElement); - IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation(); - } + Collection foldingDescriptors = getCustomFoldingDescriptors(editor, project); + if (foldingDescriptors.size() > 0) { + CustomFoldingRegionsPopup regionsPopup = new CustomFoldingRegionsPopup(foldingDescriptors, editor, project); + regionsPopup.show(); + } + else { + notifyCustomRegionsUnavailable(editor, project); } } }, @@ -71,7 +79,7 @@ public class GotoCustomRegionAction extends AnAction implements DumbAware { @Override public void update(AnActionEvent e) { Presentation presentation = e.getPresentation(); - presentation.setText("Custom Region..."); + presentation.setText(IdeBundle.message("goto.custom.region.menu.item")); final Editor editor = e.getData(CommonDataKeys.EDITOR); final Project project = e.getProject(); boolean isAvailable = editor != null && project != null; @@ -79,13 +87,49 @@ public class GotoCustomRegionAction extends AnAction implements DumbAware { presentation.setVisible(isAvailable); } - private static void navigateTo(Editor editor, PsiElement element) { - int offset = element.getTextRange().getStartOffset(); - if (offset >= 0 && offset < editor.getDocument().getTextLength()) { - editor.getCaretModel().removeSecondaryCarets(); - editor.getCaretModel().moveToOffset(offset); - editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); - editor.getSelectionModel().removeSelection(); + @NotNull + private static Collection getCustomFoldingDescriptors(@NotNull Editor editor, @NotNull Project project) { + Set foldingDescriptors = new HashSet(); + final Document document = editor.getDocument(); + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + PsiFile file = documentManager != null ? documentManager.getPsiFile(document) : null; + if (file != null) { + final FileViewProvider viewProvider = file.getViewProvider(); + for (final Language language : viewProvider.getLanguages()) { + final PsiFile psi = viewProvider.getPsi(language); + final FoldingBuilder foldingBuilder = LanguageFolding.INSTANCE.forLanguage(language); + if (psi != null) { + for (FoldingDescriptor descriptor : LanguageFolding.buildFoldingDescriptors(foldingBuilder, psi, document, false)) { + CustomFoldingBuilder customFoldingBuilder = getCustomFoldingBuilder(foldingBuilder, descriptor); + if (customFoldingBuilder != null) { + if (customFoldingBuilder.isCustomRegionStart(descriptor.getElement())) { + foldingDescriptors.add(descriptor); + } + } + } + } + } } + return foldingDescriptors; + } + + @Nullable + private static CustomFoldingBuilder getCustomFoldingBuilder(FoldingBuilder builder, FoldingDescriptor descriptor) { + if (builder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)builder; + FoldingBuilder originalBuilder = descriptor.getElement().getUserData(CompositeFoldingBuilder.FOLDING_BUILDER); + if (originalBuilder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)originalBuilder; + return null; + } + + private static void notifyCustomRegionsUnavailable(@NotNull Editor editor, @NotNull Project project) { + final JBPopupFactory popupFactory = JBPopupFactory.getInstance(); + Balloon balloon = popupFactory + .createHtmlTextBalloonBuilder(IdeBundle.message("goto.custom.region.message.unavailable"), MessageType.INFO, null) + .setFadeoutTime(2000) + .setHideOnClickOutside(true) + .setHideOnKeyOutside(true) + .createBalloon(); + Disposer.register(project, balloon); + balloon.show(popupFactory.guessBestPopupLocation(editor), Balloon.Position.above); } } diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.form b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.form deleted file mode 100644 index c155616c8186..000000000000 --- a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.form +++ /dev/null @@ -1,25 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - -
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.java b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.java deleted file mode 100644 index 49d63dfe24b9..000000000000 --- a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.lang.customFolding; - -import com.intellij.ide.IdeBundle; -import com.intellij.lang.Language; -import com.intellij.lang.folding.*; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.psi.FileViewProvider; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.ui.components.JBList; -import com.intellij.ui.components.JBScrollPane; -import com.intellij.util.containers.HashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.util.*; -import java.util.List; - -/** - * @author Rustam Vishnyakov - */ -public class GotoCustomRegionDialog extends DialogWrapper { - private JBList myRegionsList; - private JPanel myContentPane; - private JBScrollPane myScrollPane; - private final Editor myEditor; - private final Project myProject; - - protected GotoCustomRegionDialog(@Nullable Project project, @NotNull Editor editor) { - super(project); - myEditor = editor; - myProject = project; - Collection descriptors = getCustomFoldingDescriptors(); - init(); - if (descriptors.size() == 0) { - myScrollPane.setVisible(false); - myContentPane.add(new JLabel(IdeBundle.message("goto.custom.region.message.unavailable")), BorderLayout.NORTH); - setOKActionEnabled(false); - } - else { - myRegionsList.setModel(new MyListModel(orderByPosition(descriptors))); - myRegionsList.setSelectedIndex(0); - } - setTitle(IdeBundle.message("goto.custom.region.command")); - } - - @Override - public JComponent getPreferredFocusedComponent() { - if (!myRegionsList.isEmpty()) { - return myRegionsList; - } - return super.getPreferredFocusedComponent(); - } - - @Override - protected JComponent createCenterPanel() { - return myContentPane; - } - - private Collection getCustomFoldingDescriptors() { - Set foldingDescriptors = new HashSet(); - final Document document = myEditor.getDocument(); - PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); - PsiFile file = documentManager != null ? documentManager.getPsiFile(document) : null; - if (file != null) { - final FileViewProvider viewProvider = file.getViewProvider(); - for (final Language language : viewProvider.getLanguages()) { - final PsiFile psi = viewProvider.getPsi(language); - final FoldingBuilder foldingBuilder = LanguageFolding.INSTANCE.forLanguage(language); - if (psi != null) { - for (FoldingDescriptor descriptor : LanguageFolding.buildFoldingDescriptors(foldingBuilder, psi, document, false)) { - CustomFoldingBuilder customFoldingBuilder = getCustomFoldingBuilder(foldingBuilder, descriptor); - if (customFoldingBuilder != null) { - if (customFoldingBuilder.isCustomRegionStart(descriptor.getElement())) { - foldingDescriptors.add(descriptor); - } - } - } - } - } - } - return foldingDescriptors; - } - - private static Collection orderByPosition(Collection descriptors) { - List sorted = new ArrayList(descriptors.size()); - sorted.addAll(descriptors); - Collections.sort(sorted, new Comparator() { - @Override - public int compare(FoldingDescriptor descriptor1, FoldingDescriptor descriptor2) { - int pos1 = descriptor1.getElement().getTextRange().getStartOffset(); - int pos2 = descriptor2.getElement().getTextRange().getStartOffset(); - return pos1 - pos2; - } - }); - return sorted; - } - - private void createUIComponents() { - myRegionsList = new JBList(); - myScrollPane = new JBScrollPane(myRegionsList); - } - - @Nullable - private static CustomFoldingBuilder getCustomFoldingBuilder(FoldingBuilder builder, FoldingDescriptor descriptor) { - if (builder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)builder; - FoldingBuilder originalBuilder = descriptor.getElement().getUserData(CompositeFoldingBuilder.FOLDING_BUILDER); - if (originalBuilder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)originalBuilder; - return null; - } - - - private static class MyListModel extends DefaultListModel { - private MyListModel(Collection descriptors) { - for (FoldingDescriptor descriptor : descriptors) { - super.addElement(new MyFoldingDescriptorWrapper(descriptor)); - } - } - } - - private static class MyFoldingDescriptorWrapper { - private final @NotNull FoldingDescriptor myDescriptor; - - private MyFoldingDescriptorWrapper(@NotNull FoldingDescriptor descriptor) { - myDescriptor = descriptor; - } - - @NotNull - public FoldingDescriptor getDescriptor() { - return myDescriptor; - } - - @Nullable - @Override - public String toString() { - return myDescriptor.getPlaceholderText(); - } - } - - @Nullable - public PsiElement getNavigationElement() { - Object selection = myRegionsList.getSelectedValue(); - if (selection instanceof MyFoldingDescriptorWrapper) { - return ((MyFoldingDescriptorWrapper)selection).getDescriptor().getElement().getPsi(); - } - return null; - } -} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java index 385b764af027..58e35083a247 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java @@ -357,6 +357,9 @@ public class ScopesAndSeveritiesTable extends JBTable { } else if (columnIndex == SCOPE_ENABLED_COLUMN) { final NamedScope scope = getScope(rowIndex); + if (scope == null) { + return; + } if ((Boolean)value) { if (rowIndex == lastRowIndex()) { myInspectionProfile.enableToolsByDefault(myKeyNames, myProject); @@ -381,7 +384,7 @@ public class ScopesAndSeveritiesTable extends JBTable { @Override public void removeRow(final int idx) { if (idx != lastRowIndex()) { - myInspectionProfile.removeScopes(myKeyNames, getScope(idx), myProject); + myInspectionProfile.removeScopes(myKeyNames, getScopeName(idx), myProject); refreshAggregatedScopes(); myTableSettings.onScopeRemoved(getRowCount()); } diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 720ac40cc1eb..e5a1ecc0f649 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1142,8 +1142,9 @@ whatsnew.action.custom.text=What''s _New in {0} whatsnew.action.custom.description=Find out about the new features in this version of {0} diff.dialog.title=Diff Between ''{0}'' and ''{1}'' -goto.custom.region.command=Go to Custom Region -goto.custom.region.message.dumb.mode=Go to Custom Region action is not available until indices are built. +goto.custom.region.menu.item=Custom Folding Region... +goto.custom.region.command=Go to Custom Folding Region +goto.custom.region.message.dumb.mode=Go to Custom Folding Region action is not available until indices are built. goto.custom.region.message.unavailable=There are no custom folding regions in the current file. alphabetical.mode.is.on.warning=Alphabetical order for tabs is ON. Switch it OFF? diff --git a/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java b/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java index 73b8cfeaf267..c5a806a1125c 100644 --- a/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java +++ b/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java @@ -32,6 +32,7 @@ public class MockVirtualFileSystem extends DeprecatedVirtualFileSystem { public static final String PROTOCOL = "mock"; @Override + @NotNull public VirtualFile findFileByPath(@NotNull String path) { path = path.replace(File.separatorChar, '/'); path = path.replace('/', ':'); @@ -106,6 +107,7 @@ public class MockVirtualFileSystem extends DeprecatedVirtualFileSystem { return MockVirtualFileSystem.this; } + @NotNull public MyVirtualFile getOrCreate(String name) { MyVirtualFile file = myChildren.get(name); if (file == null) { diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java index 010caad8fcd2..ecc5bff4dc50 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java @@ -37,6 +37,7 @@ public abstract class IdeaTestFixtureFactory { } } + @NotNull public static IdeaTestFixtureFactory getFixtureFactory() { return ourInstance; } @@ -59,6 +60,7 @@ public abstract class IdeaTestFixtureFactory { public abstract TestFixtureBuilder createFixtureBuilder(@NotNull String name); + @NotNull public abstract TestFixtureBuilder createLightFixtureBuilder(); public abstract TestFixtureBuilder createLightFixtureBuilder(@Nullable LightProjectDescriptor projectDescriptor); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java index b275ec521c8c..1d0e648611ef 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java @@ -17,11 +17,13 @@ package com.intellij.testFramework.fixtures; import com.intellij.testFramework.builders.ModuleFixtureBuilder; +import org.jetbrains.annotations.NotNull; /** * @author mike */ public interface TestFixtureBuilder { + @NotNull T getFixture(); M addModule(Class builderClass); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java index c7b7779fe92a..412c87ee5bce 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java @@ -22,6 +22,7 @@ import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; import com.intellij.testFramework.fixtures.TestFixtureBuilder; import com.intellij.util.pico.ConstructorInjectionComponentAdapter; import com.intellij.util.pico.IdeaPicoContainer; +import org.jetbrains.annotations.NotNull; import org.picocontainer.MutablePicoContainer; import java.lang.reflect.Field; @@ -50,6 +51,7 @@ class HeavyTestFixtureBuilderImpl implements TestFixtureBuilder createLightFixtureBuilder() { return new LightTestFixtureBuilderImpl(new LightIdeaTestFixtureImpl( diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java index 43a2ee7c031c..a196e4211649 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java @@ -19,6 +19,7 @@ package com.intellij.testFramework.fixtures.impl; import com.intellij.testFramework.builders.ModuleFixtureBuilder; import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; import com.intellij.testFramework.fixtures.TestFixtureBuilder; +import org.jetbrains.annotations.NotNull; /** * @author mike @@ -31,6 +32,7 @@ class LightTestFixtureBuilderImpl implements T myFixture = fixture; } + @NotNull @Override public F getFixture() { return myFixture; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java index 683c27e30e18..00ceef568c21 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java @@ -39,7 +39,7 @@ public class WatchInplaceEditor extends XDebuggerTreeInplaceEditor { @Nullable private final WatchNode myOldNode; public WatchInplaceEditor(@NotNull WatchesRootNode rootNode, - @NotNull XDebugSession session, XWatchesView watchesView, final WatchNode node, + @Nullable XDebugSession session, XWatchesView watchesView, final WatchNode node, @NonNls final String historyId, final @Nullable WatchNode oldNode) { super((XDebuggerTreeNode)node, historyId); @@ -47,7 +47,9 @@ public class WatchInplaceEditor extends XDebuggerTreeInplaceEditor { myWatchesView = watchesView; myOldNode = oldNode; myExpressionEditor.setExpression(oldNode != null ? oldNode.getExpression() : null); - new WatchEditorSessionListener(session).install(); + if (session != null) { + new WatchEditorSessionListener(session).install(); + } } @Override diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java index 0007ec2f9997..847dd9004a49 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java @@ -19,6 +19,7 @@ import com.intellij.execution.ui.layout.ViewContext; import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.DataKey; import com.intellij.ui.content.ContentManager; import com.intellij.util.SingleAlarm; import com.intellij.xdebugger.XDebugSession; @@ -66,15 +67,20 @@ public abstract class XDebugView implements Disposable { @Nullable public static XDebugSession getSession(@NotNull Component component) { + return getData(XDebugSession.DATA_KEY, component); + } + + @Nullable + public static T getData(DataKey key, @NotNull Component component) { DataContext dataContext = DataManager.getInstance().getDataContext(component); ViewContext viewContext = ViewContext.CONTEXT_KEY.getData(dataContext); ContentManager contentManager = viewContext == null ? null : viewContext.getContentManager(); if (contentManager != null) { - XDebugSession session = XDebugSession.DATA_KEY.getData(DataManager.getInstance().getDataContext(contentManager.getComponent())); - if (session != null) { - return session; + T data = key.getData(DataManager.getInstance().getDataContext(contentManager.getComponent())); + if (data != null) { + return data; } } - return XDebugSession.DATA_KEY.getData(dataContext); + return key.getData(dataContext); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java index c510cd17c90a..8b94e2c4858a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java @@ -40,6 +40,7 @@ import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; +import com.intellij.xdebugger.impl.ui.XDebugSessionData; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel; @@ -220,13 +221,9 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa @Override public void addWatchExpression(@NotNull XExpression expression, int index, final boolean navigateToWatchNode) { XDebugSession session = getSession(getTree()); - if (session == null) { - return; - } - - myRootNode.addWatchExpression(session.getDebugProcess().getEvaluator(), expression, index, navigateToWatchNode); + myRootNode.addWatchExpression(session != null ? session.getDebugProcess().getEvaluator() : null, expression, index, navigateToWatchNode); updateSessionData(); - if (navigateToWatchNode) { + if (navigateToWatchNode && session != null) { showWatchesTab((XDebugSessionImpl)session); } } @@ -342,8 +339,15 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa } XDebugSession session = getSession(getTree()); + XExpression[] expressions = watchExpressions.toArray(new XExpression[watchExpressions.size()]); if (session != null) { - ((XDebugSessionImpl)session).setWatchExpressions(watchExpressions.toArray(new XExpression[watchExpressions.size()])); + ((XDebugSessionImpl)session).setWatchExpressions(expressions); + } + else { + XDebugSessionData data = getData(XDebugSessionData.DATA_KEY, getTree()); + if (data != null) { + data.setWatchExpressions(expressions); + } } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java index cf67f7d5fdb5..2e4e168b8d84 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java @@ -188,9 +188,7 @@ public class WatchesRootNode extends XDebuggerTreeNode { fireNodeStructureChanged(messageNode); } XDebugSession session = XDebugView.getSession(myTree); - if (session != null) { - new WatchInplaceEditor(this, session, myWatchesView, messageNode, "watch", node).show(); - } + new WatchInplaceEditor(this, session, myWatchesView, messageNode, "watch", node).show(); } private class MyEvaluationCallback extends XEvaluationCallbackBase { diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 3a9855add0e1..6ef74a16947b 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -480,49 +480,44 @@ public abstract class TestObject implements JavaCommandLine { return StringUtil.compare(o1.getName(), o2.getName(), true); } }) : null; - final PrintWriter writer = new PrintWriter(myTempFile, CharsetToolkit.UTF8); - try { - writer.println(packageName); - final JUnitConfiguration.Data data = myConfiguration.getPersistentData(); - final String category = data.TEST_OBJECT == JUnitConfiguration.TEST_CATEGORY ? data.getCategory() : ""; - writer.println(category); - final List testNames = new ArrayList(); - for (final T element : elements) { - final String name = nameFunction.fun(element); - if (name == null) { - LOG.error("invalid element " + element); - return; - } - if (perModule != null && element instanceof PsiElement) { - final Module module = ModuleUtilCore.findModuleForPsiElement((PsiElement)element); - if (module != null) { - List list = perModule.get(module); - if (list == null) { - list = new ArrayList(); - perModule.put(module, list); - } - list.add(name); + final List testNames = new ArrayList(); + + for (final T element : elements) { + final String name = nameFunction.fun(element); + if (name == null) { + LOG.error("invalid element " + element); + return; + } + + if (perModule != null && element instanceof PsiElement) { + final Module module = ModuleUtilCore.findModuleForPsiElement((PsiElement)element); + if (module != null) { + List list = perModule.get(module); + if (list == null) { + list = new ArrayList(); + perModule.put(module, list); } - } else { - testNames.add(name); + list.add(name); } } - if (perModule != null) { - for (List perModuleClasses : perModule.values()) { - Collections.sort(perModuleClasses); - testNames.addAll(perModuleClasses); - } - } else { - Collections.sort(testNames); //sort tests in FQN order - } - for (String testName : testNames) { - writer.println(testName); + else { + testNames.add(name); } } - finally { - writer.close(); + if (perModule != null) { + for (List perModuleClasses : perModule.values()) { + Collections.sort(perModuleClasses); + testNames.addAll(perModuleClasses); + } } + else { + Collections.sort(testNames); //sort tests in FQN order + } + + final JUnitConfiguration.Data data = myConfiguration.getPersistentData(); + final String category = data.TEST_OBJECT == JUnitConfiguration.TEST_CATEGORY ? data.getCategory() : ""; + JUnitStarter.printClassesList(testNames, packageName, category, myTempFile); if (perModule != null && perModule.size() > 1) { final PrintWriter wWriter = new PrintWriter(myWorkingDirsFile, CharsetToolkit.UTF8); diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java index 29735a9f559b..e79ab8e677b3 100644 --- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java @@ -106,37 +106,27 @@ public class JUnitForkedStarter { final String packageName = perDirReader.readLine(); String workingDir; while ((workingDir = perDirReader.readLine()) != null) { + final String classpath = perDirReader.readLine(); try { - File tempFile = File.createTempFile("idea_junit", ".tmp"); - tempFile.deleteOnExit(); - - final FileOutputStream writer = new FileOutputStream(tempFile); - - final String classpath = perDirReader.readLine(); List classNames = new ArrayList(); - try { - final int classNamesSize = Integer.parseInt(perDirReader.readLine()); - writer.write((packageName + ", working directory: \'" + workingDir + "\'\n").getBytes("UTF-8")); //instead of package name - writer.write("\n".getBytes("UTF-8")); //category - for (int i = 0; i < classNamesSize; i++) { - String className = perDirReader.readLine(); - if (className == null) { - System.err.println("Class name is expected. Working dir: " + workingDir); - return -1; - } - classNames.add(className); - writer.write((className + "\n").getBytes("UTF-8")); + final int classNamesSize = Integer.parseInt(perDirReader.readLine()); + for (int i = 0; i < classNamesSize; i++) { + String className = perDirReader.readLine(); + if (className == null) { + System.err.println("Class name is expected. Working dir: " + workingDir); + return -1; } - } - finally { - writer.close(); + classNames.add(className); } final Object rootDescriptor = findByClassName(testRunner, (String)classNames.get(0), description); final int childResult; final File dir = new File(workingDir); if (forkMode.equals("none")) { + File tempFile = File.createTempFile("idea_junit", ".tmp"); + tempFile.deleteOnExit(); + JUnitStarter.printClassesList(classNames, packageName + ", working directory: \'" + workingDir + "\'", "", tempFile); childResult = runChild(isJUnit4, listeners, out, err, parameters, "@" + tempFile.getAbsolutePath(), dir, String.valueOf(testRunner.getRegistry().getKnownObject(rootDescriptor) - 1), classpath); diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java index cb398d9a0262..5c0edbb9ded8 100644 --- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java @@ -226,4 +226,19 @@ public class JUnitStarter { : Class.forName("com.intellij.junit3.JUnit3IdeaTestRunner"); } + + public static void printClassesList(List classNames, String packageName, String category, File tempFile) throws IOException { + final PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tempFile), "UTF-8")); + + try { + writer.println(packageName); //package name + writer.println(category); //category + for (int i = 0; i < classNames.size(); i++) { + writer.println(classNames.get(i)); + } + } + finally { + writer.close(); + } + } } diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java index 20e7753e0247..8b524dbffd4b 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java @@ -96,7 +96,9 @@ public class CCProjectComponent implements ProjectComponent { } public void projectClosed() { - VirtualFileManager.getInstance().removeVirtualFileListener(myListener); + if (myListener != null) { + VirtualFileManager.getInstance().removeVirtualFileListener(myListener); + } } private class FileDeletedListener extends VirtualFileAdapter { diff --git a/python/edu/learn-python/resources/META-INF/plugin.xml b/python/edu/learn-python/resources/META-INF/plugin.xml index f1652728ac99..7c9c96e88bc1 100644 --- a/python/edu/learn-python/resources/META-INF/plugin.xml +++ b/python/edu/learn-python/resources/META-INF/plugin.xml @@ -67,6 +67,7 @@ + diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java index a9448ddea0e3..a6c16d2553bf 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java @@ -22,108 +22,139 @@ import com.jetbrains.python.edu.StudyTaskManager; import com.jetbrains.python.edu.StudyUtils; import com.jetbrains.python.edu.course.*; import com.jetbrains.python.edu.editor.StudyEditor; +import org.jetbrains.annotations.NotNull; import java.io.*; public class StudyRefreshTaskFileAction extends DumbAwareAction { private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName()); - public void refresh(final Project project) { - ApplicationManager.getApplication().invokeLater(new Runnable() { + public static void refresh(final Project project) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") - @Override - public void run() { - final Editor editor = StudyEditor.getSelectedEditor(project); - assert editor != null; - final Document document = editor.getDocument(); - StudyDocumentListener listener = StudyEditor.getListener(document); - if (listener != null) { - document.removeDocumentListener(listener); - } - final int lineCount = document.getLineCount(); - if (lineCount != 0) { - CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { - @Override - public void run() { - document.deleteString(0, document.getLineEndOffset(lineCount - 1)); - } - }); - } - StudyTaskManager taskManager = StudyTaskManager.getInstance(project); - Course course = taskManager.getCourse(); - assert course != null; - File resourceFile = new File(course.getResourcePath()); - File resourceRoot = resourceFile.getParentFile(); - FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); - VirtualFile openedFile = fileDocumentManager.getFile(document); - assert openedFile != null; - final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile); - assert selectedTaskFile != null; - Task currentTask = selectedTaskFile.getTask(); - String lessonDir = Lesson.LESSON_DIR + String.valueOf(currentTask.getLesson().getIndex() + 1); - String taskDir = Task.TASK_DIR + String.valueOf(currentTask.getIndex() + 1); - File pattern = new File(new File(new File(resourceRoot, lessonDir), taskDir), openedFile.getName()); - BufferedReader reader = null; - try { - reader = new BufferedReader(new InputStreamReader(new FileInputStream(pattern))); - String line; - StringBuilder patternText = new StringBuilder(); - while ((line = reader.readLine()) != null) { - patternText.append(line); - patternText.append("\n"); - } - int patternLength = patternText.length(); - if (patternText.charAt(patternLength - 1) == '\n') { - patternText.delete(patternLength - 1, patternLength); - } - document.setText(patternText); - StudyStatus oldStatus = currentTask.getStatus(); - LessonInfo lessonInfo = currentTask.getLesson().getLessonInfo(); - lessonInfo.update(oldStatus, -1); - lessonInfo.update(StudyStatus.Unchecked, +1); - StudyUtils.updateStudyToolWindow(project); - for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) { - taskWindow.reset(); - } - ProjectView.getInstance(project).refresh(); - if (listener != null) { - document.addDocumentListener(listener); - } - selectedTaskFile.drawAllWindows(editor); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true); - } - }); - selectedTaskFile.navigateToFirstTaskWindow(editor); - BalloonBuilder balloonBuilder = - JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("You can now start again", MessageType.INFO, null); - final Balloon balloon = balloonBuilder.createBalloon(); - StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project); - assert selectedStudyEditor != null; - balloon.showInCenterOf(selectedStudyEditor.getRefreshButton()); - Disposer.register(project, balloon); - } - catch (FileNotFoundException e1) { - LOG.error(e1); - } - catch (IOException e1) { - LOG.error(e1); - } - finally { - StudyUtils.closeSilently(reader); - } - } - }); + final Editor editor = StudyEditor.getSelectedEditor(project); + assert editor != null; + final Document document = editor.getDocument(); + refreshFile(editor, document, project); } }); + } + }); } - public void actionPerformed(AnActionEvent e) { + public static void refreshFile(@NotNull final Editor editor, @NotNull final Document document, @NotNull final Project project) { + StudyTaskManager taskManager = StudyTaskManager.getInstance(project); + Course course = taskManager.getCourse(); + assert course != null; + FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + VirtualFile openedFile = fileDocumentManager.getFile(document); + assert openedFile != null; + final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile); + assert selectedTaskFile != null; + String openedFileName = openedFile.getName(); + Task currentTask = selectedTaskFile.getTask(); + resetTaskFile(document, project, course, selectedTaskFile, openedFileName, currentTask); + selectedTaskFile.drawAllWindows(editor); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true); + } + }); + selectedTaskFile.navigateToFirstTaskWindow(editor); + showBaloon(project); + } + + public static void resetTaskFile(Document document, Project project, Course course, TaskFile taskFile, String name, Task task) { + resetDocument(document, course, name, task); + updateLessonInfo(task); + StudyUtils.updateStudyToolWindow(project); + resetTaskWindows(taskFile); + ProjectView.getInstance(project).refresh(); + } + + private static void showBaloon(Project project) { + BalloonBuilder balloonBuilder = + JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("You can now start again", MessageType.INFO, null); + final Balloon balloon = balloonBuilder.createBalloon(); + StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project); + assert selectedStudyEditor != null; + balloon.showInCenterOf(selectedStudyEditor.getRefreshButton()); + Disposer.register(project, balloon); + } + + private static void resetTaskWindows(TaskFile selectedTaskFile) { + for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) { + taskWindow.reset(); + } + } + + private static void updateLessonInfo(Task currentTask) { + StudyStatus oldStatus = currentTask.getStatus(); + LessonInfo lessonInfo = currentTask.getLesson().getLessonInfo(); + lessonInfo.update(oldStatus, -1); + lessonInfo.update(StudyStatus.Unchecked, +1); + } + + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + private static void resetDocument(Document document, Course course, String fileName, Task task) { + BufferedReader reader = null; + StudyDocumentListener listener = StudyEditor.getListener(document); + if (listener != null) { + document.removeDocumentListener(listener); + } + clearDocument(document); + try { + String lessonDir = Lesson.LESSON_DIR + String.valueOf(task.getLesson().getIndex() + 1); + String taskDir = Task.TASK_DIR + String.valueOf(task.getIndex() + 1); + File resourceFile = new File(course.getResourcePath()); + File resourceRoot = resourceFile.getParentFile(); + File pattern = new File(new File(new File(resourceRoot, lessonDir), taskDir), fileName); + reader = new BufferedReader(new InputStreamReader(new FileInputStream(pattern))); + String line; + StringBuilder patternText = new StringBuilder(); + while ((line = reader.readLine()) != null) { + patternText.append(line); + patternText.append("\n"); + } + int patternLength = patternText.length(); + if (patternText.charAt(patternLength - 1) == '\n') { + patternText.delete(patternLength - 1, patternLength); + } + document.setText(patternText); + } + catch (FileNotFoundException e) { + LOG.error(e); + } + catch (IOException e) { + LOG.error(e); + } + finally { + StudyUtils.closeSilently(reader); + } + if (listener != null) { + document.addDocumentListener(listener); + } + } + + private static void clearDocument(final Document document) { + final int lineCount = document.getLineCount(); + if (lineCount != 0) { + CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { + @Override + public void run() { + document.deleteString(0, document.getLineEndOffset(lineCount - 1)); + } + }); + } + } + + public void actionPerformed(@NotNull AnActionEvent e) { refresh(e.getProject()); } } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyReloadCourseAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyReloadCourseAction.java new file mode 100644 index 000000000000..beefaaa94f7e --- /dev/null +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyReloadCourseAction.java @@ -0,0 +1,134 @@ +/* + * 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.jetbrains.python.edu.actions; + +import com.intellij.ide.projectView.ProjectView; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ui.tree.TreeUtil; +import com.jetbrains.python.edu.StudyTaskManager; +import com.jetbrains.python.edu.StudyUtils; +import com.jetbrains.python.edu.course.Course; +import com.jetbrains.python.edu.course.Lesson; +import com.jetbrains.python.edu.course.Task; +import com.jetbrains.python.edu.course.TaskFile; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.tree.TreePath; +import java.util.List; +import java.util.Map; + +public class StudyReloadCourseAction extends DumbAwareAction { + + public StudyReloadCourseAction() { + super("Reload Course", "Reload Course", null); + } + + @Override + public void update(@NotNull AnActionEvent e) { + Presentation presentation = e.getPresentation(); + Project project = e.getProject(); + if (project != null) { + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course != null) { + presentation.setVisible(true); + presentation.setEnabled(true); + } + } + presentation.setVisible(false); + presentation.setEnabled(false); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = e.getProject(); + if (project == null) { + return; + } + reloadCourse(project); + } + + public static void reloadCourse(@NotNull final Project project) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return; + } + for (VirtualFile file : FileEditorManager.getInstance(project).getOpenFiles()) { + FileEditorManager.getInstance(project).closeFile(file); + } + JTree tree = ProjectView.getInstance(project).getCurrentProjectViewPane().getTree(); + TreePath path = TreeUtil.getFirstNodePath(tree); + tree.collapsePath(path); + List lessons = course.getLessons(); + for (Lesson lesson : lessons) { + List tasks = lesson.getTaskList(); + VirtualFile lessonDir = project.getBaseDir().findChild(Lesson.LESSON_DIR + (lesson.getIndex() + 1)); + if (lessonDir == null) { + continue; + } + for (Task task : tasks) { + VirtualFile taskDir = lessonDir.findChild(Task.TASK_DIR + (task.getIndex() + 1)); + if (taskDir == null) { + continue; + } + Map taskFiles = task.getTaskFiles(); + for (Map.Entry entry : taskFiles.entrySet()) { + String name = entry.getKey(); + TaskFile taskFile = entry.getValue(); + VirtualFile file = taskDir.findChild(name); + if (file == null) { + continue; + } + Document document = FileDocumentManager.getInstance().getDocument(file); + if (document == null) { + continue; + } + StudyRefreshTaskFileAction.resetTaskFile(document, project, course, taskFile, name, task); + } + } + } + Lesson firstLesson = StudyUtils.getFirst(lessons); + if (firstLesson == null) { + return; + } + Task firstTask = StudyUtils.getFirst(firstLesson.getTaskList()); + VirtualFile lessonDir = project.getBaseDir().findChild(Lesson.LESSON_DIR + (firstLesson.getIndex() + 1)); + if (lessonDir != null) { + VirtualFile taskDir = lessonDir.findChild(Task.TASK_DIR + (firstTask.getIndex() + 1)); + if (taskDir != null) { + ProjectView.getInstance(project).select(taskDir, taskDir, true); + } + } + } + }); + } + }); + } +} diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java index a553978c416a..0f8c5a53511a 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java @@ -9,6 +9,7 @@ import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import com.intellij.util.ui.UIUtil; import com.jetbrains.python.edu.StudyTaskManager; +import com.jetbrains.python.edu.actions.StudyReloadCourseAction; import com.jetbrains.python.edu.course.Course; import com.jetbrains.python.edu.course.Lesson; import com.jetbrains.python.edu.course.LessonInfo; @@ -17,6 +18,8 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.List; public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware { @@ -41,7 +44,15 @@ public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware { contentPanel.add(new JLabel(authorLabel)); contentPanel.add(Box.createRigidArea(new Dimension(0, 10))); contentPanel.add(new JLabel(description)); + contentPanel.add(Box.createRigidArea(new Dimension(0, 10))); + JButton reloadCourseButton = new JButton("reload course"); + reloadCourseButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + StudyReloadCourseAction.reloadCourse(project); + } + }); + contentPanel.add(reloadCourseButton); int taskNum = 0; int taskSolved = 0; int lessonsCompleted = 0;