Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2014-08-21 10:47:17 +02:00
14 changed files with 171 additions and 66 deletions
@@ -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<PsiFile> NULL_LIST = new ArrayList<PsiFile>(0);
@NotNull
private final ConcurrentMap<VirtualFile, List<PsiFile>> myExternalAnnotations = new ConcurrentSoftValueHashMap<VirtualFile, List<PsiFile>>(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
@@ -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();
@@ -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();
@@ -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);
@@ -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));
}
}
@@ -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,11 +62,19 @@ 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);
}
}
@Override
public Object getUserObject() {
return myRepositoryPanel;
}
@Override
@NotNull
public String getValue() {
@@ -73,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
@@ -94,4 +108,8 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode
public ProgressIndicator startLoading() {
return myCurrentIndicator = new EmptyProgressIndicator();
}
public void markTargetValid(boolean isValid) {
myTargetIsValid = isValid;
}
}
@@ -48,6 +48,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
private final JLabel myRepositoryLabel;
private final ColoredTreeCellRenderer myTextRenderer;
@NotNull private final List<RepositoryNodeListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private String myOldDestination;
public RepositoryWithBranchPanel(Project project, @NotNull String repoName,
@NotNull String sourceName, String targetName, @NotNull Collection<String> 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<String> provider =
new TextFieldWithAutoCompletion.StringsCompletionProvider(targetVariants, null);
myDestBranchTextField = new TextFieldWithAutoCompletion<String>(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);
}
}
@@ -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<SemKey, SemKey> cacheKeyHierarchy(Collection<SemKey> allKeys) {
@@ -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() {
@@ -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.*;
* <code>java.lang.reflect.Proxy</code>, 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<Method, MethodInfo> methodInfoMap = new HashMap<Method, MethodInfo>();
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<Method> actualMethods, final Method method, final Map<Method, Method> covariantMethods) {
if ((method.getModifiers() & Constants.ACC_SYNTHETIC) != 0) {
return;
@@ -71,14 +71,6 @@ public class RootIndex {
private final TObjectIntHashMap<JpsModuleSourceRootType<?>> myRootTypeId = new TObjectIntHashMap<JpsModuleSourceRootType<?>>();
@NotNull private final Project myProject;
private volatile Map<VirtualFile, OrderEntry[]> 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
@@ -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<LowMemoryWatcher> 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);
@@ -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<Document, StudyDocumentListener> myDocumentListeners = new HashMap<Document, StudyDocumentListener>();
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);
}
@@ -107,6 +107,8 @@ public class ProxyTest extends TestCase {
public abstract String getBar();
@Override
public abstract String foo();
}
public void testAddInterfaces() throws Throwable {