From 1ca73cfc0f01d2ba9b4cbe4be2fd6a22f0f232f9 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 18 Aug 2014 15:38:45 +0400 Subject: [PATCH 01/27] reduce debugger views flickering - process all events with delay --- .../xdebugger/impl/frame/XDebugView.java | 33 +++++++++---------- .../impl/frame/XDebugViewSessionListener.java | 2 +- .../xdebugger/impl/frame/XFramesView.java | 4 +-- .../xdebugger/impl/frame/XVariablesView.java | 3 +- .../impl/frame/XWatchesViewImpl.java | 3 +- .../xdebugger/impl/ui/XDebugSessionTab.java | 2 +- 6 files changed, 20 insertions(+), 27 deletions(-) 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 b92069b6dea7..3e0433b804af 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 @@ -20,7 +20,7 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.ui.content.ContentManager; -import com.intellij.util.SingleAlarm; +import com.intellij.util.Alarm; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import org.jetbrains.annotations.NotNull; @@ -35,29 +35,26 @@ import java.util.EventObject; public abstract class XDebugView implements Disposable { public enum SessionEvent {PAUSED, BEFORE_RESUME, RESUMED, STOPPED, FRAME_CHANGED, SETTINGS_CHANGED} - private final SingleAlarm myClearAlarm; - private static final int VIEW_CLEAR_DELAY = 100; //ms + private final Alarm myUpdateAlarm; + private static final int VIEW_UPDATE_DELAY = 100; //ms public XDebugView() { - myClearAlarm = new SingleAlarm(new Runnable() { - @Override - public void run() { - clear(); - } - }, VIEW_CLEAR_DELAY, this); - } - - protected final void requestClear() { - myClearAlarm.cancelAndRequest(); - } - - protected final void cancelClear() { - myClearAlarm.cancel(); + myUpdateAlarm = new Alarm(this); } protected abstract void clear(); - public abstract void processSessionEvent(@NotNull SessionEvent event); + public void onSessionEvent(@NotNull final SessionEvent event) { + myUpdateAlarm.cancelAllRequests(); + myUpdateAlarm.addRequest(new Runnable() { + @Override + public void run() { + processSessionEvent(event); + } + }, VIEW_UPDATE_DELAY); + } + + protected abstract void processSessionEvent(@NotNull SessionEvent event); @Nullable protected static XDebugSession getSession(@NotNull EventObject e) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java index d790113b1816..2e21ed0f2248 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java @@ -36,7 +36,7 @@ public class XDebugViewSessionListener extends XDebugSessionAdapter { AppUIUtil.invokeLaterIfProjectAlive(session.getProject(), new Runnable() { @Override public void run() { - myDebugView.processSessionEvent(event); + myDebugView.onSessionEvent(event); } }); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java index b98440b5d69f..6ab8acd1152e 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java @@ -221,13 +221,11 @@ public class XFramesView extends XDebugView { mySelectedStack = null; XSuspendContext suspendContext = session == null ? null : session.getSuspendContext(); if (suspendContext == null) { - requestClear(); + clear(); return; } if (event == SessionEvent.PAUSED) { - // clear immediately - cancelClear(); clear(); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java index df43b1147419..c1232b572433 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java @@ -57,11 +57,10 @@ public class XVariablesView extends XVariablesViewBase { tree.markNodesObsolete(); if (stackFrame != null) { - cancelClear(); buildTreeAndRestoreState(stackFrame); } else { - requestClear(); + clear(); } } 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..b8d088d79231 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 @@ -275,7 +275,6 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa XDebugSession session = getSession(getMainPanel()); XStackFrame stackFrame = session == null ? null : session.getCurrentStackFrame(); if (stackFrame != null) { - cancelClear(); tree.setSourcePosition(stackFrame.getSourcePosition()); myRootNode.updateWatches(stackFrame.getEvaluator()); if (myTreeState != null) { @@ -283,7 +282,7 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa } } else { - requestClear(); + clear(); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index 0fd33b5f0a2d..7f46d0483e2c 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -198,7 +198,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { @Override public void run() { for (XDebugView view : myViews) { - view.processSessionEvent(XDebugView.SessionEvent.SETTINGS_CHANGED); + view.onSessionEvent(XDebugView.SessionEvent.SETTINGS_CHANGED); } } }); From 7f95d997fb693eae662708968fdd40bb3dfa6f8a Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Mon, 18 Aug 2014 15:46:34 +0400 Subject: [PATCH 02/27] IDEA-126882 Throwable at com.intellij.openapi.application.impl.ApplicationImpl.assertIsDispatchThread --- .../sceneBuilder/SceneBuilderEditor.java | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditor.java index f0c1eccd86f1..a0a90efe9c74 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditor.java @@ -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) { From 3bf29c9c255def4cc985858665156fafb0007383 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 18 Aug 2014 16:00:12 +0400 Subject: [PATCH 03/27] EA-31437 - assert: DocumentFoldingInfo.writeExternal --- .../PsiNamesElementSignatureProvider.java | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java index 17a85304d4a1..3409d3f93fc8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java @@ -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"); + } } From 4185e066b7c4a5851b9503b5b0c3e3b08873aec9 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 18 Aug 2014 16:04:04 +0400 Subject: [PATCH 04/27] EA-57323 - assert: PositionManagerImpl.getSourcePosition --- .../intellij/debugger/engine/JavaValue.java | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index 1603ed928ded..9cfb2bfde84e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -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() { From d4bc8b431058d4a2257e66b61cb2e53e47244e18 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 18 Aug 2014 14:47:26 +0200 Subject: [PATCH 05/27] =?UTF-8?q?js=20"Inspect=20in=20IDE"=20=E2=80=94=20a?= =?UTF-8?q?dd=20rerun=20action=20(actually,=20"reload=20page",=20to=20be?= =?UTF-8?q?=20discussed)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/intellij/xdebugger/XDebugSession.java | 2 ++ .../src/com/intellij/xdebugger/impl/XDebugSessionImpl.java | 2 ++ .../src/com/intellij/xdebugger/impl/frame/XDebugView.java | 5 ++--- .../src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java | 3 +-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java index be71aac98d1e..33fa877064db 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java @@ -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 DATA_KEY = DataKey.create("XDebugSessionTab.XDebugSession"); @NotNull Project getProject(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index 6ff63601d06a..8ee2f1ee587a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -170,6 +170,7 @@ public class XDebugSessionImpl implements XDebugSession { myPauseActionSupported = isSupported; } + @NotNull public List getRestartActions() { return myRestartActions; } @@ -180,6 +181,7 @@ public class XDebugSessionImpl implements XDebugSession { } } + @NotNull public List getExtraActions() { return myExtraActions; } 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 3e0433b804af..d26258d39d2a 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 @@ -22,7 +22,6 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.ui.content.ContentManager; import com.intellij.util.Alarm; import com.intellij.xdebugger.XDebugSession; -import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -68,11 +67,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); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index 7f46d0483e2c..d7e2354835fd 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -56,7 +56,6 @@ import java.util.List; public class XDebugSessionTab extends DebuggerSessionTabBase { private static final DataKey TAB_KEY = DataKey.create("XDebugSessionTab"); - public static final DataKey SESSION_KEY = DataKey.create("XDebugSessionTab.XDebugSession"); private XWatchesViewImpl myWatchesView; private final List myViews = new ArrayList(); @@ -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)) { From d0567bf63e9d3871b2ea83b3797810f303c61323 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Mon, 18 Aug 2014 17:09:19 +0400 Subject: [PATCH 06/27] IDEA-126632 wrong Mercurial commits number notification * hg push successful message pattern extended; * annotations added --- .../src/org/zmlx/hg4idea/HgPusher.java | 48 +++---------------- 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java index c8e6075649ce..18294df94a66 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java @@ -20,12 +20,12 @@ 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.ui.HgPushDialog; import java.util.List; import java.util.regex.Matcher; @@ -34,40 +34,13 @@ 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.*"); + 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; - private final Project myProject; - - public HgPusher(Project project) { - myProject = project; - } - - /* public void showDialogAndPush(@NotNull List selectedRepositories) { - - if (selectedRepositories.isEmpty()) { - VcsBalloonProblemNotifier.showOverChangesView(myProject, "No Mercurial repositories in the project", MessageType.ERROR); - return; - } - final AtomicReference pushCommand = new AtomicReference(); - 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() { @@ -95,17 +68,7 @@ public class HgPusher { }); } - 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) { + private static int getNumberOfPushedCommits(@NotNull HgCommandResult result) { int numberOfCommitsInAllSubrepos = 0; final List outputLines = result.getOutputLines(); for (String outputLine : outputLines) { @@ -113,7 +76,8 @@ public class HgPusher { final Matcher matcher = PUSH_COMMITS_PATTERN.matcher(outputLine); if (matcher.matches()) { try { - numberOfCommitsInAllSubrepos += Integer.parseInt(matcher.group(1)); + String numberOfCommits = matcher.group(1); + numberOfCommitsInAllSubrepos += ONE.equals(numberOfCommits) ? 1 : Integer.parseInt(numberOfCommits); } catch (NumberFormatException e) { LOG.error("getNumberOfPushedCommits ", e); From 00c2b0b12546bfe50e92c9ef4444677c41420ec4 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 18 Aug 2014 17:16:39 +0400 Subject: [PATCH 07/27] typo --- .../completion/JavaGenerateMemberCompletionContributor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java index 0deafb45cad9..351eca4857fd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java @@ -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) { From b520ce6d71b7ac306d013bbb3de7f8bdf4bc6178 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 17 Aug 2014 20:41:52 +0400 Subject: [PATCH 08/27] [git] formatting --- .../git4idea/ui/branch/GitBranchPopup.java | 45 +++++++------------ 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java index bd9c8fb3a1b3..1cb7cf6a66c9 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java @@ -45,14 +45,8 @@ import javax.swing.event.HyperlinkEvent; import java.util.List; /** - *

* The popup which allows to quickly switch and control Git branches. - *

- *

- * Use {@link #asListPopup()} to achieve the {@link ListPopup} itself. - *

- * - * @author Kirill Likhodedov + *

*/ 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.
" + - "If you wish to control branches in different roots separately, you may disable 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.
" + + "If you wish to control branches in different roots separately, " + + "you may disable 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; } From b2741e77c71b2a1aaf37736d4278f13c93ad3d46 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 18 Aug 2014 17:18:40 +0400 Subject: [PATCH 09/27] [git] cosmetics: remove dot in the end of action description --- .../dvcs-impl/src/com/intellij/dvcs/ui/NewBranchAction.java | 5 +---- .../src/git4idea/ui/branch/GitBranchPopupActions.java | 6 +----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/ui/NewBranchAction.java b/platform/dvcs-impl/src/com/intellij/dvcs/ui/NewBranchAction.java index 29481e236c2a..92ba9515b5d6 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/ui/NewBranchAction.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/ui/NewBranchAction.java @@ -25,9 +25,6 @@ import org.jetbrains.annotations.NotNull; import java.util.List; -/** - * @author Nadya Zabrodina - */ public abstract class NewBranchAction extends DumbAwareAction { protected final List myRepositories; protected Project myProject; @@ -43,7 +40,7 @@ public abstract class NewBranchAction 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"); } } diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index dbd3f8c902e5..b3cba24540de 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -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"); } } } From d80afac72fac5a89b08d7efe70767aa3c1af65de Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 18 Aug 2014 17:19:26 +0400 Subject: [PATCH 10/27] [dvcs] branch popup: show disabled actions to avoid confusion like in IDEA-128449 --- .../src/com/intellij/dvcs/ui/BranchActionGroupPopup.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/ui/BranchActionGroupPopup.java b/platform/dvcs-impl/src/com/intellij/dvcs/ui/BranchActionGroupPopup.java index 3b935745a212..44b4c8c5c3f0 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/ui/BranchActionGroupPopup.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/ui/BranchActionGroupPopup.java @@ -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 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); } From a9dc0f131e9e380749fd3fee41498951b4101c45 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Mon, 18 Aug 2014 17:27:58 +0400 Subject: [PATCH 11/27] refactoring: unnecessary old HgPusher removed --- .../src/org/zmlx/hg4idea/HgPusher.java | 90 ------------------- .../src/org/zmlx/hg4idea/push/HgPusher.java | 67 +++++++++++++- 2 files changed, 66 insertions(+), 91 deletions(-) delete mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java deleted file mode 100644 index 18294df94a66..000000000000 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java +++ /dev/null @@ -1,90 +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.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 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 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; - - 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 int getNumberOfPushedCommits(@NotNull HgCommandResult result) { - int numberOfCommitsInAllSubrepos = 0; - final List 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; - } -} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java index dcbfa314d03e..e09a09d9d3f1 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java @@ -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 pushSpecs, @Nullable VcsPushOptionValue vcsPushOptionValue, boolean force) { for (Map.Entry entry : pushSpecs.entrySet()) { @@ -55,7 +73,54 @@ public class HgPusher extends Pusher { else { pushCommand.setBranchName(source.mySource); } - 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 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; + } } From 0069c97b87b2e67332164ccaf50d1bcdfaacf55b Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 18 Aug 2014 17:21:48 +0400 Subject: [PATCH 12/27] including module's configured roots in a configuration fingerprint --- .../src/org/jetbrains/jps/incremental/ModuleBuildTarget.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java index a6ac897a1d2d..05c185862399 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java @@ -165,6 +165,10 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget Date: Mon, 18 Aug 2014 17:57:29 +0400 Subject: [PATCH 13/27] reverted view update delay, BEFORE_RESUME can not be delayed --- .../xdebugger/impl/frame/XDebugView.java | 33 ++++++++++--------- .../impl/frame/XDebugViewSessionListener.java | 2 +- .../xdebugger/impl/frame/XFramesView.java | 4 ++- .../xdebugger/impl/frame/XVariablesView.java | 3 +- .../impl/frame/XWatchesViewImpl.java | 3 +- .../xdebugger/impl/ui/XDebugSessionTab.java | 2 +- 6 files changed, 27 insertions(+), 20 deletions(-) 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 d26258d39d2a..0007ec2f9997 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 @@ -20,7 +20,7 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.ui.content.ContentManager; -import com.intellij.util.Alarm; +import com.intellij.util.SingleAlarm; import com.intellij.xdebugger.XDebugSession; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,26 +34,29 @@ import java.util.EventObject; public abstract class XDebugView implements Disposable { public enum SessionEvent {PAUSED, BEFORE_RESUME, RESUMED, STOPPED, FRAME_CHANGED, SETTINGS_CHANGED} - private final Alarm myUpdateAlarm; - private static final int VIEW_UPDATE_DELAY = 100; //ms + private final SingleAlarm myClearAlarm; + private static final int VIEW_CLEAR_DELAY = 100; //ms public XDebugView() { - myUpdateAlarm = new Alarm(this); + myClearAlarm = new SingleAlarm(new Runnable() { + @Override + public void run() { + clear(); + } + }, VIEW_CLEAR_DELAY, this); + } + + protected final void requestClear() { + myClearAlarm.cancelAndRequest(); + } + + protected final void cancelClear() { + myClearAlarm.cancel(); } protected abstract void clear(); - public void onSessionEvent(@NotNull final SessionEvent event) { - myUpdateAlarm.cancelAllRequests(); - myUpdateAlarm.addRequest(new Runnable() { - @Override - public void run() { - processSessionEvent(event); - } - }, VIEW_UPDATE_DELAY); - } - - protected abstract void processSessionEvent(@NotNull SessionEvent event); + public abstract void processSessionEvent(@NotNull SessionEvent event); @Nullable protected static XDebugSession getSession(@NotNull EventObject e) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java index 2e21ed0f2248..d790113b1816 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java @@ -36,7 +36,7 @@ public class XDebugViewSessionListener extends XDebugSessionAdapter { AppUIUtil.invokeLaterIfProjectAlive(session.getProject(), new Runnable() { @Override public void run() { - myDebugView.onSessionEvent(event); + myDebugView.processSessionEvent(event); } }); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java index 6ab8acd1152e..b98440b5d69f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java @@ -221,11 +221,13 @@ public class XFramesView extends XDebugView { mySelectedStack = null; XSuspendContext suspendContext = session == null ? null : session.getSuspendContext(); if (suspendContext == null) { - clear(); + requestClear(); return; } if (event == SessionEvent.PAUSED) { + // clear immediately + cancelClear(); clear(); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java index c1232b572433..df43b1147419 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java @@ -57,10 +57,11 @@ public class XVariablesView extends XVariablesViewBase { tree.markNodesObsolete(); if (stackFrame != null) { + cancelClear(); buildTreeAndRestoreState(stackFrame); } else { - clear(); + requestClear(); } } 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 b8d088d79231..c510cd17c90a 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 @@ -275,6 +275,7 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa XDebugSession session = getSession(getMainPanel()); XStackFrame stackFrame = session == null ? null : session.getCurrentStackFrame(); if (stackFrame != null) { + cancelClear(); tree.setSourcePosition(stackFrame.getSourcePosition()); myRootNode.updateWatches(stackFrame.getEvaluator()); if (myTreeState != null) { @@ -282,7 +283,7 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa } } else { - clear(); + requestClear(); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index d7e2354835fd..4c3766f23f5d 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -197,7 +197,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { @Override public void run() { for (XDebugView view : myViews) { - view.onSessionEvent(XDebugView.SessionEvent.SETTINGS_CHANGED); + view.processSessionEvent(XDebugView.SessionEvent.SETTINGS_CHANGED); } } }); From 1d23281fe7697e3536c2ec83284c5793d2e85b2b Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 18 Aug 2014 18:24:11 +0400 Subject: [PATCH 14/27] [git] IDEA-87092 handle local changes overwritten error on unstash Unstashing is currently a modal process => show a dialog instead of a notification. --- .../src/git4idea/ui/GitUnstashDialog.java | 7 +++ .../LocalChangesWouldBeOverwrittenHelper.java | 45 ++++++++++++------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java b/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java index eccaa446b0ed..44e4f1fab4b9 100644 --- a/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java +++ b/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java @@ -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()); } diff --git a/plugins/git4idea/src/git4idea/util/LocalChangesWouldBeOverwrittenHelper.java b/plugins/git4idea/src/git4idea/util/LocalChangesWouldBeOverwrittenHelper.java index 021ce824b9a7..7659c50e362a 100644 --- a/plugins/git4idea/src/git4idea/util/LocalChangesWouldBeOverwrittenHelper.java +++ b/plugins/git4idea/src/git4idea/util/LocalChangesWouldBeOverwrittenHelper.java @@ -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 relativeFilePaths) { final Collection absolutePaths = GitUtil.toAbsolute(root, relativeFilePaths); final List 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 relativeFilePaths) { + Collection absolutePaths = GitUtil.toAbsolute(root, relativeFilePaths); + List changes = GitUtil.findLocalChangesForPaths(project, root, absolutePaths, false); + showErrorDialog(project, operationName, changes, absolutePaths); + } + + private static void showErrorDialog(@NotNull Project project, @NotNull String operationName, @NotNull List changes, + @NotNull Collection 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(); + } + } + } From 7ee57a2fd1333107346925b8cecc88e319b7b7ef Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 18 Aug 2014 18:26:24 +0400 Subject: [PATCH 15/27] [git] remove some obsolete dialog --- .../src/git4idea/i18n/GitBundle.properties | 14 -- .../src/git4idea/update/GitRebaseUpdater.java | 32 --- .../GitUpdateLocallyModifiedDialog.form | 71 ------ .../GitUpdateLocallyModifiedDialog.java | 211 ------------------ 4 files changed, 328 deletions(-) delete mode 100644 plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.form delete mode 100644 plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.java diff --git a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties index 03803fbf985c..f89657535f8a 100644 --- a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties +++ b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties @@ -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=

The following files under this root are locally modified.
\ - Possible reasons: uncommitted changes; a problem with crlf conversion; {0} configuration file auto-save.

\ -

    \ -
  • Press Revert Files to discard these local changes and continue the update process.
  • \ -
  • Press Cancel to cancel the update process.
    Use Auto-Stash option to stash local changes before update and restore them after it.
  • \ -

\ - -update.locally.modified.rescan.tooltip=Rescan the repository to check for locally modified files again.
Use this button if you have resolved the problem manually. -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 diff --git a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java index 04ed3ac845ca..e22c15076170 100644 --- a/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitRebaseUpdater.java @@ -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 cancelled = new Ref(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"; diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.form b/plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.form deleted file mode 100644 index a97507f24ec9..000000000000 --- a/plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.form +++ /dev/null @@ -1,71 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.java b/plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.java deleted file mode 100644 index c3384cea20b0..000000000000 --- a/plugins/git4idea/src/git4idea/update/GitUpdateLocallyModifiedDialog.java +++ /dev/null @@ -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 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 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 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 files = new ArrayList(); - 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 files) throws VcsException { - // TODO consider deleted files - GitRollbackEnvironment rollback = GitRollbackEnvironment.getInstance(project); - ArrayList list = new ArrayList(files.size()); - for (String p : files) { - list.add(VcsUtil.getFilePath(p)); - } - rollback.revert(root, list); - } -} From 717bf0d971b31494c3d8248c901375d6a9fb1a0f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 18 Aug 2014 18:30:49 +0400 Subject: [PATCH 16/27] [git] IDEA-128259 handle local changes would be overwritten during rebase Update Project procedure should normally detect local changes before rebasing, but in case it didn't it should show them in a proper notification. --- .../src/git4idea/rebase/GitRebaser.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaser.java b/plugins/git4idea/src/git4idea/rebase/GitRebaser.java index aabf913fbf61..d5a0470d1667 100644 --- a/plugins/git4idea/src/git4idea/rebase/GitRebaser.java +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaser.java @@ -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; From 51538a0ef218bb3893f4d15ab2552908fdd2ab20 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 18 Aug 2014 18:32:25 +0400 Subject: [PATCH 17/27] [git] handle local changes overwritten error during github rebase --- .../org/jetbrains/plugins/github/GithubRebaseAction.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java index bfceb0ceec39..719f8b956432 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java @@ -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 || From 1dbc09ac368aebfa1587dca61efaa80156b534f2 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 18 Aug 2014 17:45:46 +0400 Subject: [PATCH 18/27] update html5 schema builder with new repository --- .../src/resources/patches/patch_build.patch | 53 ++++++------------- .../src/resources/update_html5_schema.sh | 4 +- 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/xml/relaxng/src/resources/patches/patch_build.patch b/xml/relaxng/src/resources/patches/patch_build.patch index ba4c30769bd0..88e4148c2420 100644 --- a/xml/relaxng/src/resources/patches/patch_build.patch +++ b/xml/relaxng/src/resources/patches/patch_build.patch @@ -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) diff --git a/xml/relaxng/src/resources/update_html5_schema.sh b/xml/relaxng/src/resources/update_html5_schema.sh index 299129868253..20d28e53762e 100755 --- a/xml/relaxng/src/resources/update_html5_schema.sh +++ b/xml/relaxng/src/resources/update_html5_schema.sh @@ -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 From e43aeff7e766cf77863bbc15ac4a3971bfb4c80a Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 18 Aug 2014 17:46:06 +0400 Subject: [PATCH 19/27] update ping patch --- xml/relaxng/src/resources/patches/0004_ping.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xml/relaxng/src/resources/patches/0004_ping.patch b/xml/relaxng/src/resources/patches/0004_ping.patch index 6f825ac4a2e0..4e47a934c7d6 100644 --- a/xml/relaxng/src/resources/patches/0004_ping.patch +++ b/xml/relaxng/src/resources/patches/0004_ping.patch @@ -7,7 +7,7 @@ - shared-hyperlink.attrs.ping = - attribute ping { - common.data.uris -- } & v5only & nonW3C +- } & v5only ## Emphatic Stress: From 98ad6480fa78996149b1509e45d00c65c286497e Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 18 Aug 2014 17:55:27 +0400 Subject: [PATCH 20/27] update html5 schema --- .../html5-schema/html5-svg-mathml.rnc | 2 - .../html5-schema/html5/applications.rnc | 12 +++- .../src/resources/html5-schema/html5/aria.rnc | 10 +-- .../resources/html5-schema/html5/block.rnc | 1 + .../resources/html5-schema/html5/common.rnc | 15 ++-- .../html5-schema/html5/core-scripting.rnc | 2 + .../resources/html5-schema/html5/embed.rnc | 71 ++++++++++++++++++- .../resources/html5-schema/html5/legacy.rnc | 6 ++ .../resources/html5-schema/html5/media.rnc | 6 +- .../src/resources/html5-schema/html5/meta.rnc | 1 + .../html5-schema/html5/microdata.rnc | 3 +- .../src/resources/html5-schema/html5/rdfa.rnc | 30 ++++---- .../resources/html5-schema/html5/tables.rnc | 33 +++------ .../resources/html5-schema/legacy/legacy.rnc | 6 ++ .../html5-schema/svg11/svg-basic-font.rnc | 4 +- .../html5-schema/svg11/svg-conditional.rnc | 3 +- .../html5-schema/svg11/svg-extensibility.rnc | 11 +++ 17 files changed, 147 insertions(+), 69 deletions(-) diff --git a/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc b/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc index fadc971d2bb4..fe154b8f57bf 100644 --- a/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc @@ -10,8 +10,6 @@ common.elem.phrasing |= math SVG.foreignObject.content |= ( math - | html.elem - | body.elem | common.inner.flow ) diff --git a/xml/relaxng/src/resources/html5-schema/html5/applications.rnc b/xml/relaxng/src/resources/html5-schema/html5/applications.rnc index ac07294db29c..2a592fbbd781 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/applications.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/applications.rnc @@ -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 + ) diff --git a/xml/relaxng/src/resources/html5-schema/html5/aria.rnc b/xml/relaxng/src/resources/html5-schema/html5/aria.rnc index b1035a0fa2a6..cf412e5f4ace 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/aria.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/aria.rnc @@ -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? diff --git a/xml/relaxng/src/resources/html5-schema/html5/block.rnc b/xml/relaxng/src/resources/html5-schema/html5/block.rnc index 2fd2d233c71b..de3b5a54ee2d 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/block.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/block.rnc @@ -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 diff --git a/xml/relaxng/src/resources/html5-schema/html5/common.rnc b/xml/relaxng/src/resources/html5-schema/html5/common.rnc index 9f1e65673bd2..09afb1454233 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/common.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/common.rnc @@ -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 ) diff --git a/xml/relaxng/src/resources/html5-schema/html5/core-scripting.rnc b/xml/relaxng/src/resources/html5-schema/html5/core-scripting.rnc index bef6bf107423..eb08c2ed5bb7 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/core-scripting.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/core-scripting.rnc @@ -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 )? diff --git a/xml/relaxng/src/resources/html5-schema/html5/embed.rnc b/xml/relaxng/src/resources/html5-schema/html5/embed.rnc index 51a2f0acb7a6..be4204914fa8 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/embed.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/embed.rnc @@ -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.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.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.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 diff --git a/xml/relaxng/src/resources/html5-schema/html5/legacy.rnc b/xml/relaxng/src/resources/html5-schema/html5/legacy.rnc index e64f77068455..3d6f1c1930ef 100644 --- a/xml/relaxng/src/resources/html5-schema/html5/legacy.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/legacy.rnc @@ -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 = diff --git a/xml/relaxng/src/resources/html5-schema/html5/media.rnc b/xml/relaxng/src/resources/html5-schema/html5/media.rnc index 04072ecc1036..28cbb630bb39 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/media.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/media.rnc @@ -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 ) diff --git a/xml/relaxng/src/resources/html5-schema/html5/meta.rnc b/xml/relaxng/src/resources/html5-schema/html5/meta.rnc index b5e810a0d46f..898a130ec6ed 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/meta.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/meta.rnc @@ -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 diff --git a/xml/relaxng/src/resources/html5-schema/html5/microdata.rnc b/xml/relaxng/src/resources/html5-schema/html5/microdata.rnc index 076a4ded1dad..91616c846147 100644 --- a/xml/relaxng/src/resources/html5-schema/html5/microdata.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/microdata.rnc @@ -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 diff --git a/xml/relaxng/src/resources/html5-schema/html5/rdfa.rnc b/xml/relaxng/src/resources/html5-schema/html5/rdfa.rnc index b8513d716093..3c849d98a954 100644 --- a/xml/relaxng/src/resources/html5-schema/html5/rdfa.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/rdfa.rnc @@ -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 diff --git a/xml/relaxng/src/resources/html5-schema/html5/tables.rnc b/xml/relaxng/src/resources/html5-schema/html5/tables.rnc index 2aecbcfc7a4e..b6021dac22dd 100755 --- a/xml/relaxng/src/resources/html5-schema/html5/tables.rnc +++ b/xml/relaxng/src/resources/html5-schema/html5/tables.rnc @@ -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 ) diff --git a/xml/relaxng/src/resources/html5-schema/legacy/legacy.rnc b/xml/relaxng/src/resources/html5-schema/legacy/legacy.rnc index e64f77068455..3d6f1c1930ef 100644 --- a/xml/relaxng/src/resources/html5-schema/legacy/legacy.rnc +++ b/xml/relaxng/src/resources/html5-schema/legacy/legacy.rnc @@ -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 = diff --git a/xml/relaxng/src/resources/html5-schema/svg11/svg-basic-font.rnc b/xml/relaxng/src/resources/html5-schema/svg11/svg-basic-font.rnc index 32eb1460f564..94f5b7fa3121 100644 --- a/xml/relaxng/src/resources/html5-schema/svg11/svg-basic-font.rnc +++ b/xml/relaxng/src/resources/html5-schema/svg11/svg-basic-font.rnc @@ -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 diff --git a/xml/relaxng/src/resources/html5-schema/svg11/svg-conditional.rnc b/xml/relaxng/src/resources/html5-schema/svg11/svg-conditional.rnc index 22f3cc23b1d9..ecb3e154aded 100644 --- a/xml/relaxng/src/resources/html5-schema/svg11/svg-conditional.rnc +++ b/xml/relaxng/src/resources/html5-schema/svg11/svg-conditional.rnc @@ -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, diff --git a/xml/relaxng/src/resources/html5-schema/svg11/svg-extensibility.rnc b/xml/relaxng/src/resources/html5-schema/svg11/svg-extensibility.rnc index 2f075b4c2cec..ba3316ad160b 100644 --- a/xml/relaxng/src/resources/html5-schema/svg11/svg-extensibility.rnc +++ b/xml/relaxng/src/resources/html5-schema/svg11/svg-extensibility.rnc @@ -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* From 9e394bebe78253f640f88f953745ce5bf6a26d6a Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Mon, 18 Aug 2014 19:00:43 +0400 Subject: [PATCH 21/27] Remove usages of deprecated CodeStyleSettings.RIGHT_MARGIN field --- .../com/intellij/codeInsight/OverrideImplementTest.java | 4 ++-- .../plugins/groovy/lang/formatter/WrappingTest.groovy | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/OverrideImplementTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/OverrideImplementTest.java index f9f70d655310..f35df4d389f9 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/OverrideImplementTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/OverrideImplementTest.java @@ -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; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/WrappingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/WrappingTest.groovy index 79d79edc42de..4d585dbf7f6f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/WrappingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/WrappingTest.groovy @@ -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() { From 30a280fb267cd2361a831a85ba092e6f17df3054 Mon Sep 17 00:00:00 2001 From: medvector Date: Mon, 18 Aug 2014 19:19:13 +0400 Subject: [PATCH 22/27] when navigating file with task windows is opened as active --- .../python/edu/actions/StudyTaskNavigationAction.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java index 2ce200bfc641..b781e7da8849 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java @@ -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 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); From be3ba0754a157128a31cd44aaf00384349f469ee Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Mon, 18 Aug 2014 18:57:18 +0400 Subject: [PATCH 23/27] style, rename --- .../com/intellij/dvcs/push/OutgoingResult.java | 4 ---- .../src/com/intellij/dvcs/push/PushSource.java | 3 +++ .../com/intellij/dvcs/push/PushController.java | 5 +++-- .../push/{HgSource.java => HgPushSource.java} | 17 ++++++++++++----- .../org/zmlx/hg4idea/push/HgPushSupport.java | 4 ++-- .../src/org/zmlx/hg4idea/push/HgPusher.java | 11 ++++++----- 6 files changed, 26 insertions(+), 18 deletions(-) rename plugins/hg4idea/src/org/zmlx/hg4idea/push/{HgSource.java => HgPushSource.java} (68%) diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/OutgoingResult.java b/platform/dvcs-api/src/com/intellij/dvcs/push/OutgoingResult.java index 5cc5a26abec8..7b4b0a7b4a81 100644 --- a/platform/dvcs-api/src/com/intellij/dvcs/push/OutgoingResult.java +++ b/platform/dvcs-api/src/com/intellij/dvcs/push/OutgoingResult.java @@ -38,8 +38,4 @@ public class OutgoingResult { public List getCommits() { return myCommits; } - - public boolean hasErrors() { - return !myErrors.isEmpty(); - } } diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/PushSource.java b/platform/dvcs-api/src/com/intellij/dvcs/push/PushSource.java index 8e756d8fe76a..7ae7a33dd6e2 100644 --- a/platform/dvcs-api/src/com/intellij/dvcs/push/PushSource.java +++ b/platform/dvcs-api/src/com/intellij/dvcs/push/PushSource.java @@ -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(); } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java index 5d6b839e5912..4ee8e504b295 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java @@ -198,14 +198,15 @@ public class PushController implements Disposable { @Override public void onSuccess() { OutgoingResult outgoing = result.get(); - if (outgoing.hasErrors()) { + List 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() { + myPushLog.setChildren(node, ContainerUtil.map(errors, new Function() { @Override public DefaultMutableTreeNode fun(final VcsError error) { VcsLinkedText errorLinkText = new VcsLinkedText(error.getText(), new VcsLinkListener() { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgSource.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSource.java similarity index 68% rename from plugins/hg4idea/src/org/zmlx/hg4idea/push/HgSource.java rename to plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSource.java index 292e2df7244c..babd49c9b31d 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgSource.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSource.java @@ -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 } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java index d2a320297c2f..4bfa134a5e26 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java @@ -80,9 +80,9 @@ public class HgPushSupport extends PushSupport { @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 diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java index e09a09d9d3f1..f019035a373f 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java @@ -57,21 +57,22 @@ 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); } push(project, pushCommand); } From e3062c90c828a2bc095837cad379e505ed0581f1 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Mon, 18 Aug 2014 18:58:00 +0400 Subject: [PATCH 24/27] typo fixed --- .../src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java index 00977ee31cb0..70055cafe1a1 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java @@ -71,7 +71,7 @@ public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider { if (HgErrorUtil.isAbortLine(error)) { if (HgErrorUtil.isAuthorizationError(error)) { VcsError authorizationError = - new VcsError(error + "" + LOGIN_AND_REFRESH_LINK + "", new VcsErrorHandler() { + new VcsError(error + "" + LOGIN_AND_REFRESH_LINK + "", new VcsErrorHandler() { public void handleError(@NotNull CommitLoader commitLoader) { commitLoader.reloadCommits(); } From a347027e74a694088cc56c99816fff12727b0d73 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Mon, 18 Aug 2014 19:00:16 +0400 Subject: [PATCH 25/27] style: optimize --- .../src/com/intellij/dvcs/push/PushController.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java index 4ee8e504b295..044dadc81272 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java @@ -199,7 +199,7 @@ public class PushController implements Disposable { public void onSuccess() { OutgoingResult outgoing = result.get(); List errors = outgoing.getErrors(); - if (errors.isEmpty()) { + if (!errors.isEmpty()) { final CommitLoader loader = new CommitLoader() { @Override public void reloadCommits() { @@ -348,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() { + @Override + public boolean value(MyRepoModel model) { + return support.equals(model.getSupport()); } - } - return false; + }); } private static class MyRepoModel { From b4208e624ff3d92edeaec9948c277efadd301c8e Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 18 Aug 2014 19:21:22 +0400 Subject: [PATCH 26/27] New tree implementation for Settings. --- .../options/newEditor/OptionsEditor.java | 105 ++- .../options/newEditor/SettingsTreeView.java | 864 ++++++++++++++++++ .../util/resources/misc/registry.properties | 1 + 3 files changed, 950 insertions(+), 20 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java index 07e5a93670e6..271539f038a0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java @@ -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 findConfigurable(Class 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 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); + } } }); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java new file mode 100644 index 000000000000..9269da7ab967 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java @@ -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 myConfigurableToNodeMap = new IdentityHashMap(); + 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 path = new ArrayDeque(); + 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 findConfigurable(@NotNull Class 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 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 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 toRestore = new ArrayList(); + 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 toRestore) { + TreePath[] selected = myTree.getSelectionPaths(); + if (selected == null) { + selected = new TreePath[0]; + } + + List toCollapse = new ArrayList(); + + 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); + } + } + } +} diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 6d85b6498843..e9802f2321ae 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -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 From 59457e668b4e383bffb8618eeabe01aac446dc1e Mon Sep 17 00:00:00 2001 From: medvector Date: Mon, 18 Aug 2014 19:23:28 +0400 Subject: [PATCH 27/27] course description window fixed and checker updated --- .../python/edu/actions/StudyCheckAction.java | 102 +++++++++++++----- .../edu/actions/StudyRefreshTaskAction.java | 9 +- .../jetbrains/python/edu/course/Lesson.java | 4 +- .../python/edu/course/LessonInfo.java | 17 +++ .../jetbrains/python/edu/course/Stateful.java | 2 +- .../com/jetbrains/python/edu/course/Task.java | 19 ++-- .../jetbrains/python/edu/course/TaskFile.java | 4 +- .../python/edu/course/TaskWindow.java | 2 +- 8 files changed, 106 insertions(+), 53 deletions(-) diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java index ad3df265ccda..f8e10c9c4521 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java @@ -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 filesToDelete = new ArrayList(); 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 taskFiles = selectedTaskFile.getTask().getTaskFiles(); + for (Map.Entry 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 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) { diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskAction.java index b245b46f90ef..f8abb0b63365 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskAction.java @@ -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(); diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/Lesson.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/Lesson.java index 84396ea404d4..3879d519957e 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/Lesson.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/Lesson.java @@ -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); } } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/LessonInfo.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/LessonInfo.java index 9431632c2edd..85e2eb8be1a9 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/LessonInfo.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/LessonInfo.java @@ -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; + } + } + } } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/Stateful.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/Stateful.java index 10374bd94d9a..3a163622f56d 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/Stateful.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/Stateful.java @@ -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); } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/Task.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/Task.java index a493b0ebfe8e..2323412f4374 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/Task.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/Task.java @@ -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); } } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java index 06d5736bd81a..4f17fc0d27f3 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java @@ -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); } } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java index 04e65c3abb59..6a5a01c7b9c8 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskWindow.java @@ -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; }