From 192157a001d2864bec8407f6add57a1063ddb647 Mon Sep 17 00:00:00 2001 From: Liana Bakradze Date: Thu, 21 Aug 2014 12:33:58 +0400 Subject: [PATCH 1/5] EDU-124 added opportunity to copy from task text --- .../python/edu/editor/StudyEditor.java | 74 ++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java index c48395543c8e..083cc4a91f25 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java @@ -4,6 +4,7 @@ import com.intellij.codeHighlighting.BackgroundEditorHighlighter; import com.intellij.icons.AllIcons; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; @@ -18,10 +19,15 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.pom.Navigatable; import com.intellij.ui.BrowserHyperlinkListener; import com.intellij.ui.HideableTitledPanel; import com.intellij.ui.JBColor; +import com.intellij.util.ui.EmptyClipboardOwner; import com.intellij.util.ui.UIUtil; import com.jetbrains.python.edu.StudyDocumentListener; import com.jetbrains.python.edu.StudyTaskManager; @@ -38,8 +44,8 @@ import javax.swing.text.MutableAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.datatransfer.StringSelection; +import java.awt.event.*; import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.Map; @@ -58,7 +64,7 @@ public class StudyEditor implements TextEditor { private JButton myPrevTaskButton; private JButton myRefreshButton; private static final Map myDocumentListeners = new HashMap(); - private Project myProject; + private final Project myProject; public JButton getCheckButton() { return myCheckButton; @@ -111,8 +117,53 @@ public class StudyEditor implements TextEditor { } } - private static void initializeTaskText(JPanel studyPanel, @Nullable String taskText) { + class CopyListener extends MouseAdapter { + final JTextPane myTextPane; + + public CopyListener(JTextPane textPane) { + myTextPane = textPane; + } + + @Override + public void mouseReleased(MouseEvent e) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ToolWindow projectView = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PROJECT_VIEW); + if (projectView == null) { + return; + } + final Component focusComponent = projectView.getComponent(); + IdeFocusManager.getInstance(myProject).requestFocus(focusComponent, true); + final String text = myTextPane.getSelectedText(); + if (text == null) { + return; + } + KeyAdapter keyAdapter = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent ev) { + if (ev.getKeyCode() == KeyEvent.VK_C + && ev.getModifiers() == InputEvent.CTRL_MASK) { + StringSelection selection = new StringSelection(text); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, EmptyClipboardOwner.INSTANCE); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + IdeFocusManager.getInstance(myProject).requestFocus(myDefaultEditor.getComponent(), true); + } + }); + } + } + }; + focusComponent.addKeyListener(keyAdapter); + } + }); + } + } + + private void initializeTaskText(JPanel studyPanel, @Nullable String taskText) { JTextPane taskTextPane = new JTextPane(); + taskTextPane.addMouseListener(new CopyListener(taskTextPane)); taskTextPane.setContentType("text/html"); taskTextPane.setEditable(false); taskTextPane.setText(taskText); @@ -157,7 +208,8 @@ public class StudyEditor implements TextEditor { watchInputButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - StudyEditInputAction studyEditInputAction = (StudyEditInputAction)ActionManager.getInstance().getAction("WatchInputAction"); + StudyEditInputAction studyEditInputAction = + (StudyEditInputAction)ActionManager.getInstance().getAction("WatchInputAction"); studyEditInputAction.showInput(myProject); } }); @@ -173,7 +225,8 @@ public class StudyEditor implements TextEditor { myNextTaskButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - StudyNextStudyTaskAction studyNextTaskAction = (StudyNextStudyTaskAction)ActionManager.getInstance().getAction("NextTaskAction"); + StudyNextStudyTaskAction studyNextTaskAction = + (StudyNextStudyTaskAction)ActionManager.getInstance().getAction("NextTaskAction"); studyNextTaskAction.navigateTask(myProject); } }); @@ -188,7 +241,8 @@ public class StudyEditor implements TextEditor { myRefreshButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - StudyRefreshTaskAction studyRefreshTaskAction = (StudyRefreshTaskAction)ActionManager.getInstance().getAction("RefreshTaskAction"); + StudyRefreshTaskAction studyRefreshTaskAction = + (StudyRefreshTaskAction)ActionManager.getInstance().getAction("RefreshTaskAction"); studyRefreshTaskAction.refresh(myProject); } }); @@ -308,7 +362,8 @@ public class StudyEditor implements TextEditor { if (fileEditor instanceof StudyEditor) { return (StudyEditor)fileEditor; } - } catch (Exception e) { + } + catch (Exception e) { return null; } return null; @@ -333,8 +388,9 @@ public class StudyEditor implements TextEditor { @NotNull @Override public Editor getEditor() { - if (myDefaultEditor instanceof TextEditor) + if (myDefaultEditor instanceof TextEditor) { return ((TextEditor)myDefaultEditor).getEditor(); + } return EditorFactory.getInstance().createViewer(new DocumentImpl(""), myProject); } From a76066a96a9c50598830514401311fc96a60c69f Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Wed, 20 Aug 2014 20:27:43 +0400 Subject: [PATCH 2/5] validation changed: invalid target rendered as error_text --- .../src/com/intellij/dvcs/push/PushController.java | 8 +++----- .../src/com/intellij/dvcs/push/ui/RepositoryNode.java | 8 ++++++++ 2 files changed, 11 insertions(+), 5 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 2a409e12c854..c34864a2044f 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java @@ -38,7 +38,6 @@ import com.intellij.vcs.log.VcsFullCommitDetails; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -82,13 +81,10 @@ public class PushController implements Disposable { if (model.isSelected()) { //has one or more selected roots validInfo = null; - RepositoryNode node = entry.getKey(); PushTarget target = model.getSpec().getTarget(); //todo add validation for model -> hasErrors, too if (target == null) { - JComponent editingComponent = myPushLog.startEditNode(node); - return new ValidationInfo("Invalid remote for repository " + DvcsUtil.getShortRepositoryName(model.getRepository()), - editingComponent); + return new ValidationInfo("Invalid remote for repository " + DvcsUtil.getShortRepositoryName(model.getRepository())); } } } @@ -160,11 +156,13 @@ public class PushController implements Disposable { public void onTargetChanged(String newValue) { VcsError validationError = support.validate(model.getRepository(), newValue); if (validationError == null) { + repoNode.markTargetValid(true); myView2Model.get(repoNode).setSpec(new PushSpec(model.getSpec().getSource(), support.createTarget(repository, newValue))); loadCommits(model, repoNode, false); } else { //todo may be should store validation errors in model and get errors during dialog validation + repoNode.markTargetValid(false); myView2Model.get(repoNode).setSpec(new PushSpec(model.getSpec().getSource(), null)); } myDialog.updateButtons(); diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java index 24a26ece96d9..b62eda6ec07a 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java @@ -33,6 +33,7 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode @NotNull private final RepositoryWithBranchPanel myRepositoryPanel; private ProgressIndicator myCurrentIndicator; + protected boolean myTargetIsValid = true; public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel) { super(repositoryPanel); @@ -61,6 +62,9 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode if (StringUtil.isEmptyOrSpaces(targetName)) { renderer.append(ENTER_REMOTE, SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES, textField); } + else if (!myTargetIsValid) { + renderer.append(targetName, SimpleTextAttributes.ERROR_ATTRIBUTES, textField); + } else { renderer.append(targetName, SimpleTextAttributes.SYNTHETIC_ATTRIBUTES, textField); } @@ -94,4 +98,8 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode public ProgressIndicator startLoading() { return myCurrentIndicator = new EmptyProgressIndicator(); } + + public void markTargetValid(boolean isValid) { + myTargetIsValid = isValid; + } } From f1d4ca661ad31c6921d8db1ade68a989b56265f1 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Thu, 21 Aug 2014 12:34:30 +0400 Subject: [PATCH 3/5] Provide cancel editing for repository targets. * target changed successfully only whe editing stopped and reverted to previous value if editing cancelled; * targetChanged event handling simplified: unnecessary parameter 'value' removed --- .../dvcs/push/ui/EditableTreeNode.java | 4 +++- .../com/intellij/dvcs/push/ui/PushLog.java | 19 +++++++++++-------- .../intellij/dvcs/push/ui/RepositoryNode.java | 14 ++++++++++++-- .../push/ui/RepositoryWithBranchPanel.java | 11 +++++++++-- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java index 5d0d20cdc4c0..b5747de91bf7 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java @@ -20,7 +20,9 @@ import org.jetbrains.annotations.NotNull; public interface EditableTreeNode extends CustomRenderedTreeNode { - void fireOnChange(@NotNull String value); + void fireOnChange(); + + void fireOnCancel(); void fireOnSelectionChange(boolean isSelected); diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index b07bf9243f8a..0b35702c9220 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -31,7 +31,6 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ui.tree.TreeUtil; import com.intellij.vcs.log.VcsFullCommitDetails; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.CellEditorListener; @@ -56,6 +55,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { private final ChangesBrowser myChangesBrowser; private final CheckboxTree myTree; private final MyTreeCellRenderer myTreeCellRenderer; + //private final AtomicBoolean myIgnoreStopEditing = new AtomicBoolean(false); public PushLog(Project project, CheckedTreeNode root) { DefaultTreeModel treeModel = new DefaultTreeModel(root); @@ -96,14 +96,17 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { treeCellEditor.addCellEditorListener(new CellEditorListener() { @Override public void editingStopped(ChangeEvent e) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent(); + if (node != null && node instanceof EditableTreeNode) { + ((EditableTreeNode)node).fireOnChange(); + } } @Override public void editingCanceled(ChangeEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent(); if (node != null && node instanceof EditableTreeNode) { - //todo restore from appropriate editor - ((EditableTreeNode)node).fireOnChange(((EditableTreeNode)node).getValue()); + ((EditableTreeNode)node).fireOnCancel(); } } }); @@ -173,7 +176,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { @Override protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { if (e.getKeyCode() == KeyEvent.VK_ENTER && myTree.isEditing()) { - myTree.cancelEditing(); + myTree.stopEditing(); return true; } return super.processKeyBinding(ks, e, condition, pressed); @@ -265,6 +268,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { final DefaultTreeModel model = ((DefaultTreeModel)myTree.getModel()); model.nodeStructureChanged(parentNode); TreePath path = TreeUtil.getPathFromRoot(parentNode); + //myIgnoreStopEditing.set(true); if (shouldExpand) { myTree.expandPath(path); } @@ -274,16 +278,15 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { } finally { TREE_CONSTRUCTION_LOCK.writeLock().unlock(); + //myIgnoreStopEditing.set(false); } } - @Nullable - public JComponent startEditNode(@NotNull TreeNode node) { + public void startEditNode(@NotNull TreeNode node) { TreePath path = TreeUtil.getPathFromRoot(node); if (!myTree.isEditing()) { + myTree.setSelectionPath(path); myTree.startEditingAtPath(path); } - return (JComponent)myTree.getCellEditor() - .getTreeCellEditorComponent(myTree, node, false, false, false, myTree.getRowForPath(path)); } } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java index b62eda6ec07a..d2fa0e249f07 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java @@ -70,6 +70,11 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode } } + @Override + public Object getUserObject() { + return myRepositoryPanel; + } + @Override @NotNull public String getValue() { @@ -77,8 +82,13 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode } @Override - public void fireOnChange(@NotNull String value) { - myRepositoryPanel.fireOnChange(value); + public void fireOnChange() { + myRepositoryPanel.fireOnChange(); + } + + @Override + public void fireOnCancel() { + myRepositoryPanel.fireOnCancel(); } @Override diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java index 131c8e2a19a8..5532568c9cf9 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java @@ -48,6 +48,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel private final JLabel myRepositoryLabel; private final ColoredTreeCellRenderer myTextRenderer; @NotNull private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); + private String myOldDestination; public RepositoryWithBranchPanel(Project project, @NotNull String repoName, @NotNull String sourceName, String targetName, @NotNull Collection targetVariants) { @@ -65,6 +66,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel myRepositoryLabel = new JLabel(repoName); myLocalBranch = new JBLabel(sourceName); myArrowLabel = new JLabel(" -> "); + myOldDestination = targetName; TextFieldWithAutoCompletionListProvider provider = new TextFieldWithAutoCompletion.StringsCompletionProvider(targetVariants, null); myDestBranchTextField = new TextFieldWithAutoCompletion(project, provider, true, targetName) { @@ -172,9 +174,10 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel myListeners.add(listener); } - public void fireOnChange(@NotNull String newValue) { + public void fireOnChange() { + myOldDestination = myDestBranchTextField.getText(); for (RepositoryNodeListener listener : myListeners) { - listener.onTargetChanged(newValue); + listener.onTargetChanged(myOldDestination); } } @@ -183,6 +186,10 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel listener.onSelectionChanged(isSelected); } } + + public void fireOnCancel() { + myDestBranchTextField.setText(myOldDestination); + } } From 786a88f583f6f0c8b264e1eb2f2d4b4fce91bd5f Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 20 Aug 2014 15:37:20 +0200 Subject: [PATCH 4/5] highlight unused LowMemoryWatcher.register call results and create a less error-prone overload with parentDisposable --- .../BaseExternalAnnotationsManager.java | 15 +++++++------- .../psi/impl/file/impl/FileManagerImpl.java | 13 ++++++------ .../com/intellij/semantic/SemServiceImpl.java | 12 ++--------- .../newvfs/persistent/PersistentFSImpl.java | 13 ++++++------ .../openapi/roots/impl/RootIndex.java | 14 ++++++------- .../openapi/util/LowMemoryWatcher.java | 20 +++++++++++++++++++ 6 files changed, 48 insertions(+), 39 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java b/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java index 05b516e47ee5..966504719826 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java @@ -49,21 +49,20 @@ import java.util.concurrent.ConcurrentMap; public abstract class BaseExternalAnnotationsManager extends ExternalAnnotationsManager { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.BaseExternalAnnotationsManager"); + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @NotNull private static final List NULL_LIST = new ArrayList(0); @NotNull private final ConcurrentMap> myExternalAnnotations = new ConcurrentSoftValueHashMap>(10, 0.75f, 2); protected final PsiManager myPsiManager; - @SuppressWarnings("UnusedDeclaration") - private final LowMemoryWatcher myLowMemoryWatcher = LowMemoryWatcher.register(new Runnable() { - @Override - public void run() { - dropCache(); - } - }); - public BaseExternalAnnotationsManager(final PsiManager psiManager) { myPsiManager = psiManager; + LowMemoryWatcher.register(new Runnable() { + @Override + public void run() { + dropCache(); + } + }, psiManager.getProject()); } @Nullable diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java index 7b4e9ec210ac..80d10dd2c1b3 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java @@ -71,13 +71,6 @@ public class FileManagerImpl implements FileManager { private final FileDocumentManager myFileDocumentManager; private final MessageBusConnection myConnection; - @SuppressWarnings("UnusedDeclaration") - private final LowMemoryWatcher myLowMemoryWatcher = LowMemoryWatcher.register(new Runnable() { - @Override - public void run() { - processQueue(); - } - }); public FileManagerImpl(PsiManagerImpl manager, FileDocumentManager fileDocumentManager, FileIndexFacade fileIndex) { myManager = manager; @@ -98,6 +91,12 @@ public class FileManagerImpl implements FileManager { } }); Disposer.register(manager.getProject(), this); + LowMemoryWatcher.register(new Runnable() { + @Override + public void run() { + processQueue(); + } + }, this); } private static final VirtualFile NULL = new LightVirtualFile(); diff --git a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java index 102a439e11f8..1624c48f2ae5 100644 --- a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java @@ -17,8 +17,6 @@ package com.intellij.semantic; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.project.ProjectManagerAdapter; import com.intellij.openapi.util.LowMemoryWatcher; import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.RecursionManager; @@ -83,7 +81,7 @@ public class SemServiceImpl extends SemService{ }); - final LowMemoryWatcher watcher = LowMemoryWatcher.register(new Runnable() { + LowMemoryWatcher.register(new Runnable() { @Override public void run() { if (myCreatingSem.get() == 0) { @@ -91,13 +89,7 @@ public class SemServiceImpl extends SemService{ } //System.out.println("SemService cache flushed"); } - }); - ProjectManager.getInstance().addProjectManagerListener(project, new ProjectManagerAdapter() { - @Override - public void projectClosing(Project project) { - watcher.stop(); - } - }); + }, project); } private static MultiMap cacheKeyHierarchy(Collection allKeys) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index d7b90178e7e8..db5de4258d41 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -67,15 +67,16 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone private final Object myInputLock = new Object(); private final AtomicBoolean myShutDown = new AtomicBoolean(false); + @SuppressWarnings("FieldCanBeLocal") + private final LowMemoryWatcher myWatcher = LowMemoryWatcher.register(new Runnable() { + @Override + public void run() { + clearIdCache(); + } + }); public PersistentFSImpl(@NotNull MessageBus bus) { myEventBus = bus; - LowMemoryWatcher.register(new Runnable() { - @Override - public void run() { - clearIdCache(); - } - }); ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { @Override public void run() { diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java index bc85dabc9aec..bd9531a2d888 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java @@ -71,14 +71,6 @@ public class RootIndex { private final TObjectIntHashMap> myRootTypeId = new TObjectIntHashMap>(); @NotNull private final Project myProject; private volatile Map myOrderEntries; - @SuppressWarnings("UnusedDeclaration") - private final LowMemoryWatcher myLowMemoryWatcher = LowMemoryWatcher.register(new Runnable() { - @Override - public void run() { - myNonExistentPackages.clear(); - } - }); - // made public for Upsource public RootIndex(@NotNull Project project, @NotNull InfoCache cache) { @@ -98,6 +90,12 @@ public class RootIndex { myProjectExcludedRoots.add(root); } } + LowMemoryWatcher.register(new Runnable() { + @Override + public void run() { + myNonExistentPackages.clear(); + } + }, project); } @NotNull diff --git a/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java b/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java index 33bd953d422f..f6c7b924590a 100644 --- a/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java +++ b/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.util; +import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.containers.WeakList; @@ -93,10 +94,29 @@ public class LowMemoryWatcher { }, null, null); } + /** + * Registers a runnable to run on low memory events + * @return a LowMemoryWatcher instance holding the runnable. This instance should be kept in memory while the + * low memory notification functionality is needed. As soon as it's garbage-collected, the runnable won't receive any further notifications. + */ public static LowMemoryWatcher register(Runnable runnable) { return new LowMemoryWatcher(runnable); } + /** + * Registers a runnable to run on low memory events. The notifications will be issued until parentDisposable is disposed. + */ + public static void register(Runnable runnable, Disposable parentDisposable) { + final Ref watcher = Ref.create(new LowMemoryWatcher(runnable)); + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + watcher.get().stop(); + watcher.set(null); + } + }); + } + private LowMemoryWatcher(Runnable runnable) { myRunnable = runnable; ourInstances.add(this); From d6ff9b7629d3da2df16b3c5cef00cbee09b64caa Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 21 Aug 2014 10:40:48 +0200 Subject: [PATCH 5/5] cglib: don't override jdk 8 default methods as it causes jre to go crazy --- .../src/net/sf/cglib/proxy/AdvancedEnhancer.java | 10 ++++++++++ .../tests/com/intellij/util/xml/ProxyTest.java | 2 ++ 2 files changed, 12 insertions(+) diff --git a/platform/platform-impl/src/net/sf/cglib/proxy/AdvancedEnhancer.java b/platform/platform-impl/src/net/sf/cglib/proxy/AdvancedEnhancer.java index 5b22e706508a..92d98a708036 100644 --- a/platform/platform-impl/src/net/sf/cglib/proxy/AdvancedEnhancer.java +++ b/platform/platform-impl/src/net/sf/cglib/proxy/AdvancedEnhancer.java @@ -26,6 +26,7 @@ import org.objectweb.asm.Type; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.*; /** @@ -61,6 +62,7 @@ import java.util.*; * java.lang.reflect.Proxy, see the {@link Proxy} class. */ +@SuppressWarnings("StaticFieldReferencedViaSubclass") public class AdvancedEnhancer extends AbstractClassGenerator { private static final CallbackFilter ALL_ZERO = new CallbackFilter(){ @@ -520,6 +522,9 @@ public class AdvancedEnhancer extends AbstractClassGenerator } final Map methodInfoMap = new HashMap(); for (Method method : actualMethods) { + if (isJdk8DefaultMethod(method)) { + continue; + } int modifiers = Constants.ACC_FINAL | (method.getModifiers() & ~Constants.ACC_ABSTRACT & ~Constants.ACC_NATIVE & ~Constants.ACC_SYNCHRONIZED); if (forcePublic.contains(MethodWrapper.create(method))) { @@ -551,6 +556,11 @@ public class AdvancedEnhancer extends AbstractClassGenerator e.end_class(); } + private static boolean isJdk8DefaultMethod(Method method) { + return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == + Modifier.PUBLIC) && method.getDeclaringClass().isInterface(); + } + private static void removeAllCovariantMethods(final List actualMethods, final Method method, final Map covariantMethods) { if ((method.getModifiers() & Constants.ACC_SYNTHETIC) != 0) { return; diff --git a/xml/dom-tests/tests/com/intellij/util/xml/ProxyTest.java b/xml/dom-tests/tests/com/intellij/util/xml/ProxyTest.java index 3db1009c15de..c44d9e74eb45 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/ProxyTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/ProxyTest.java @@ -107,6 +107,8 @@ public class ProxyTest extends TestCase { public abstract String getBar(); + @Override + public abstract String foo(); } public void testAddInterfaces() throws Throwable {