Merge remote-tracking branch 'origin/master'
@@ -34,7 +34,9 @@ import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.compiler.CompilationStatusListener;
|
||||
import com.intellij.openapi.compiler.CompileContext;
|
||||
import com.intellij.openapi.compiler.CompilerTopics;
|
||||
import com.intellij.openapi.components.ApplicationComponent;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
@@ -64,16 +66,14 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.FileNameCache;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.concurrency.SequentialTaskExecutor;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
@@ -1117,6 +1117,44 @@ public class BuildManager implements ApplicationComponent{
|
||||
scheduleAutoMake();
|
||||
}
|
||||
});
|
||||
conn.subscribe(CompilerTopics.COMPILATION_STATUS, new CompilationStatusListener() {
|
||||
private final Set<String> myRootsToRefresh = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
|
||||
@Override
|
||||
public void compilationFinished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
|
||||
final String[] roots;
|
||||
synchronized (myRootsToRefresh) {
|
||||
roots = ArrayUtil.toStringArray(myRootsToRefresh);
|
||||
myRootsToRefresh.clear();
|
||||
}
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (project.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
final Set<VirtualFile> filesToRefresh = new HashSet<VirtualFile>();
|
||||
for (String root : roots) {
|
||||
final VirtualFile rootFile = lfs.refreshAndFindFileByPath(root);
|
||||
if (rootFile != null && fileIndex.isInSourceContent(rootFile)) {
|
||||
filesToRefresh.add(rootFile);
|
||||
}
|
||||
}
|
||||
if (!filesToRefresh.isEmpty()) {
|
||||
lfs.refreshFiles(filesToRefresh, true, true, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileGenerated(String outputRoot, String relativePath) {
|
||||
synchronized (myRootsToRefresh) {
|
||||
myRootsToRefresh.add(outputRoot);
|
||||
}
|
||||
}
|
||||
});
|
||||
final String projectPath = getProjectPath(project);
|
||||
Disposer.register(project, new Disposable() {
|
||||
@Override
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -69,13 +69,13 @@ public class LibraryTest extends ModuleRootManagerTestCase {
|
||||
LibraryTable table = LibraryTablesRegistrar.getInstance().getLibraryTable(myProject);
|
||||
Library library = table.createLibrary("native");
|
||||
Library.ModifiableModel model = library.getModifiableModel();
|
||||
model.addRoot("file://native", NativeLibraryOrderRootType.getInstance());
|
||||
model.addRoot("file://native-lib-root", NativeLibraryOrderRootType.getInstance());
|
||||
commit(model);
|
||||
|
||||
Element element = serialize(library);
|
||||
PlatformTestUtil.assertElementEquals(
|
||||
"<root><library name=\"native\"><CLASSES /><JAVADOC />" +
|
||||
"<NATIVE><root url=\"file://native\" /></NATIVE>" +
|
||||
"<NATIVE><root url=\"file://native-lib-root\" /></NATIVE>" +
|
||||
"<SOURCES /></library></root>",
|
||||
element);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -226,4 +226,9 @@ public class FontPreferences {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Effective font families: " + myEffectiveFontFamilies;
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 366 B |
|
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 176 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 122 B |
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 224 B |
@@ -16,6 +16,7 @@ import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.StringInterner;
|
||||
import com.intellij.util.containers.WeakStringInterner;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -33,7 +34,7 @@ public class RunConfigurationExtensionsManager<U extends RunConfigurationBase, T
|
||||
private static final String EXT_ID_ATTR = "ID";
|
||||
private static final String EXTENSION_ROOT_ATTR = "EXTENSION";
|
||||
protected final ExtensionPointName<T> myExtensionPointName;
|
||||
private final StringInterner myInterner = new StringInterner();
|
||||
private final StringInterner myInterner = new WeakStringInterner();
|
||||
|
||||
public RunConfigurationExtensionsManager(ExtensionPointName<T> extensionPointName) {
|
||||
myExtensionPointName = extensionPointName;
|
||||
|
||||
@@ -634,15 +634,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
|
||||
|
||||
private class EditDocumentationSourceAction extends BaseNavigateToSourceAction {
|
||||
|
||||
protected EditDocumentationSourceAction() {
|
||||
EditDocumentationSourceAction() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent event) {
|
||||
super.update(event);
|
||||
event.getPresentation().setIcon(AllIcons.Actions.EditSource);
|
||||
event.getPresentation().setText("Edit Source");
|
||||
getTemplatePresentation().setIcon(AllIcons.Actions.EditSource);
|
||||
getTemplatePresentation().setText("Edit Source");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,11 +30,15 @@ import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.ElementManipulators;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.impl.source.tree.injected.Place;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -93,14 +97,17 @@ public class QuickEditAction implements IntentionAction, LowPriorityAction {
|
||||
}
|
||||
|
||||
public QuickEditHandler invokeImpl(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final Pair<PsiElement, TextRange> pair = getRangePair(file, editor);
|
||||
assert pair != null;
|
||||
final PsiFile injectedFile = (PsiFile)pair.first;
|
||||
final int injectedOffset = ((DocumentWindow)PsiDocumentManager.getInstance(project).getDocument(injectedFile)).hostToInjected(offset);
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
Pair<PsiElement, TextRange> pair = ObjectUtils.assertNotNull(getRangePair(file, editor));
|
||||
|
||||
PsiFile injectedFile = (PsiFile)pair.first;
|
||||
QuickEditHandler handler = getHandler(project, injectedFile, editor, file);
|
||||
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
handler.navigate(injectedOffset);
|
||||
DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injectedFile);
|
||||
if (documentWindow != null) {
|
||||
handler.navigate(documentWindow.hostToInjected(offset));
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
@@ -124,12 +131,15 @@ public class QuickEditAction implements IntentionAction, LowPriorityAction {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public static QuickEditHandler getExistingHandler(PsiFile injectedFile) {
|
||||
public static QuickEditHandler getExistingHandler(@NotNull PsiFile injectedFile) {
|
||||
Place shreds = InjectedLanguageUtil.getShreds(injectedFile);
|
||||
if (shreds == null) return null;
|
||||
DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injectedFile);
|
||||
if (shreds == null || documentWindow == null) return null;
|
||||
|
||||
TextRange hostRange = TextRange.create(shreds.get(0).getHostRangeMarker().getStartOffset(),
|
||||
shreds.get(shreds.size() - 1).getHostRangeMarker().getEndOffset());
|
||||
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
|
||||
if (editor.getDocument() != documentWindow.getDelegate()) continue;
|
||||
QuickEditHandler handler = editor.getUserData(QUICK_EDIT_HANDLER);
|
||||
if (handler != null && handler.changesRange(hostRange)) return handler;
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
|
||||
|
||||
private void commitToOriginal() {
|
||||
if (!isValid()) return;
|
||||
VirtualFile origVirtualFile = PsiUtilCore.getVirtualFile(ObjectUtils.assertNotNull(myNewFile.getContext()));
|
||||
VirtualFile origVirtualFile = PsiUtilCore.getVirtualFile(myNewFile.getContext());
|
||||
myCommittingToOriginal = true;
|
||||
try {
|
||||
if (origVirtualFile == null || !ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(origVirtualFile).hasReadonlyFiles()) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -344,8 +344,21 @@ public class IdeEventQueue extends EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean ourAppIsLoaded = false;
|
||||
|
||||
private static boolean appIsLoaded() {
|
||||
if (ourAppIsLoaded) return true;
|
||||
boolean loaded = IdeaApplication.isLoaded();
|
||||
if (loaded) ourAppIsLoaded = true;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchEvent(AWTEvent e) {
|
||||
if (!appIsLoaded()) {
|
||||
super.dispatchEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
fixNonEnglishKeyboardLayouts(e);
|
||||
|
||||
@@ -760,7 +773,7 @@ public class IdeEventQueue extends EventQueue {
|
||||
}
|
||||
|
||||
private static boolean typeAheadDispatchToFocusManager(AWTEvent e) {
|
||||
if (e instanceof KeyEvent && appIsLoaded()) {
|
||||
if (e instanceof KeyEvent) {
|
||||
final KeyEvent event = (KeyEvent)e;
|
||||
if (!event.isConsumed()) {
|
||||
final IdeFocusManager focusManager = IdeFocusManager.findInstanceByComponent(event.getComponent());
|
||||
@@ -771,15 +784,6 @@ public class IdeEventQueue extends EventQueue {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean ourAppIsLoaded = false;
|
||||
|
||||
private static boolean appIsLoaded() {
|
||||
if (ourAppIsLoaded) return true;
|
||||
boolean loaded = IdeaApplication.isLoaded();
|
||||
if (loaded) ourAppIsLoaded = true;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
public void flushQueue() {
|
||||
while (true) {
|
||||
AWTEvent event = peekEvent();
|
||||
|
||||
@@ -17,9 +17,12 @@ package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.pom.NavigatableWithText;
|
||||
import com.intellij.pom.PomTargetPsiElement;
|
||||
import com.intellij.util.OpenSourceUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class BaseNavigateToSourceAction extends AnAction implements DumbAware {
|
||||
@@ -37,7 +40,7 @@ public abstract class BaseNavigateToSourceAction extends AnAction implements Dum
|
||||
|
||||
public void update(AnActionEvent event) {
|
||||
DataContext dataContext = event.getDataContext();
|
||||
final Navigatable target = getTarget(dataContext);
|
||||
final Navigatable target = findTargetForUpdate(dataContext);
|
||||
boolean enabled = target != null;
|
||||
if (ActionPlaces.isPopupPlace(event.getPlace())) {
|
||||
event.getPresentation().setVisible(enabled);
|
||||
@@ -49,36 +52,21 @@ public abstract class BaseNavigateToSourceAction extends AnAction implements Dum
|
||||
else {
|
||||
event.getPresentation().setEnabled(enabled);
|
||||
}
|
||||
if (target != null && target instanceof NavigatableWithText) {
|
||||
//as myFocusEditor is always ignored - Main Menu|View always contains 2 actions with the same name and actually same behaviour
|
||||
if (!myFocusEditor) {
|
||||
event.getPresentation().setVisible(false);
|
||||
return;
|
||||
}
|
||||
final String navigateActionText = ((NavigatableWithText)target).getNavigateActionText(myFocusEditor);
|
||||
if (navigateActionText != null) {
|
||||
event.getPresentation().setText(navigateActionText);
|
||||
}
|
||||
else {
|
||||
event.getPresentation().setText(getTemplatePresentation().getText());
|
||||
}
|
||||
}
|
||||
else {
|
||||
event.getPresentation().setText(getTemplatePresentation().getText());
|
||||
}
|
||||
//as myFocusEditor is always ignored - Main Menu|View always contains 2 actions with the same name and actually same behaviour
|
||||
event.getPresentation().setVisible(target == null || myFocusEditor);
|
||||
String navigateActionText = myFocusEditor && target instanceof NavigatableWithText?
|
||||
((NavigatableWithText)target).getNavigateActionText(true) : null;
|
||||
event.getPresentation().setText(StringUtil.notNullize(navigateActionText, getTemplatePresentation().getText()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Navigatable getTarget(final DataContext dataContext) {
|
||||
if (!myFocusEditor && CommonDataKeys.EDITOR.getData(dataContext) != null) {
|
||||
// makes no sense in editor and conflicts with another action there (ctrl+enter)
|
||||
return null;
|
||||
}
|
||||
|
||||
private Navigatable findTargetForUpdate(@NotNull DataContext dataContext) {
|
||||
Navigatable[] navigatables = getNavigatables(dataContext);
|
||||
if (navigatables != null) {
|
||||
for (Navigatable navigatable : navigatables) {
|
||||
if (navigatable.canNavigate()) return navigatable;
|
||||
if (navigatables == null) return null;
|
||||
|
||||
for (Navigatable navigatable : navigatables) {
|
||||
if (navigatable.canNavigate()) {
|
||||
return navigatable instanceof PomTargetPsiElement ? ((PomTargetPsiElement)navigatable).getTarget() : navigatable;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -17,9 +17,21 @@
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
|
||||
public class ViewSourceAction extends BaseNavigateToSourceAction {
|
||||
public ViewSourceAction() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
if (CommonDataKeys.EDITOR.getData(e.getDataContext()) != null) {
|
||||
e.getPresentation().setEnabledAndVisible(false);
|
||||
}
|
||||
else {
|
||||
super.update(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.ide.passwordSafe.impl.providers.masterKey;
|
||||
|
||||
import com.intellij.concurrency.AsyncFutureFactory;
|
||||
import com.intellij.concurrency.AsyncFutureResult;
|
||||
import com.intellij.ide.passwordSafe.MasterPasswordUnavailableException;
|
||||
import com.intellij.ide.passwordSafe.PasswordSafeException;
|
||||
import com.intellij.ide.passwordSafe.impl.PasswordSafeTimed;
|
||||
@@ -23,14 +25,11 @@ import com.intellij.ide.passwordSafe.impl.providers.ByteArrayWrapper;
|
||||
import com.intellij.ide.passwordSafe.impl.providers.EncryptionUtil;
|
||||
import com.intellij.ide.passwordSafe.impl.providers.masterKey.windows.WindowsCryptUtils;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -38,6 +37,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* The password safe that stores information in configuration file encrypted by master password
|
||||
@@ -200,35 +200,41 @@ public class MasterKeyPasswordSafe extends BasePasswordSafeProvider {
|
||||
}
|
||||
|
||||
private static final Object ourEDTLock = new Object();
|
||||
public <T, E extends Throwable> T invokeAndWait(@NotNull final ThrowableComputable<T, E> computable, @NotNull final Condition expired) throws E {
|
||||
public <T, E extends Throwable> T invokeAndWait(@NotNull final ThrowableComputable<T, E> computable, @NotNull final Condition<?> expired) throws E {
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
return computable.compute();
|
||||
}
|
||||
final Ref<Throwable> exRef = Ref.create();
|
||||
final Ref<T> ref = Ref.create();
|
||||
|
||||
final AsyncFutureResult<Object> future = AsyncFutureFactory.getInstance().createAsyncFutureResult();
|
||||
synchronized (ourEDTLock) {
|
||||
if (expired.value(null)) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
|
||||
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(new ExpirableRunnable() {
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
boolean b = expired.value(null);
|
||||
if (b) future.setException(new ProcessCanceledException());
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (expired.value(null)) {
|
||||
exRef.set(new ProcessCanceledException());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ref.set(computable.compute());
|
||||
future.set(computable.compute());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
exRef.set(e);
|
||||
future.setException(e);
|
||||
}
|
||||
}
|
||||
}, ModalityState.any());
|
||||
});
|
||||
}
|
||||
try {
|
||||
return (T)future.get();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new ProcessCanceledException(e);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
throw (E) e.getCause();
|
||||
}
|
||||
if (!exRef.isNull()) throw (E)exRef.get();
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -407,7 +407,7 @@ public final class EditorUtil {
|
||||
IterationState state = new IterationState(editorImpl, start, end, false);
|
||||
int fontType = state.getMergedAttributes().getFontType();
|
||||
int column = currentColumn[0];
|
||||
int spaceSize = getSpaceWidth(fontType, editorImpl);
|
||||
int plainSpaceSize = getSpaceWidth(Font.PLAIN, editorImpl);
|
||||
for (; column < columnNumber && offset < end; offset++) {
|
||||
if (offset >= state.getEndOffset()) {
|
||||
state.advance();
|
||||
@@ -417,7 +417,7 @@ public final class EditorUtil {
|
||||
char c = text.charAt(offset);
|
||||
if (c == '\t') {
|
||||
final int newX = nextTabStop(x, editorImpl);
|
||||
final int columns = columnsNumber(newX - x, spaceSize);
|
||||
final int columns = columnsNumber(newX - x, plainSpaceSize);
|
||||
if (debugBuffer != null) {
|
||||
debugBuffer.append(String.format(
|
||||
"Processing tabulation at the offset %d. Current X: %d, new X: %d, current column: %d, new column: %d%n",
|
||||
@@ -556,11 +556,11 @@ public final class EditorUtil {
|
||||
return nextTabStop(x, getSpaceWidth(Font.PLAIN, editor), tabSize);
|
||||
}
|
||||
|
||||
public static int nextTabStop(int x, int spaceWidth, int tabSize) {
|
||||
public static int nextTabStop(int x, int plainSpaceWidth, int tabSize) {
|
||||
if (tabSize <= 0) {
|
||||
return x + spaceWidth;
|
||||
return x + plainSpaceWidth;
|
||||
}
|
||||
tabSize *= spaceWidth;
|
||||
tabSize *= plainSpaceWidth;
|
||||
|
||||
int nTabs = x / tabSize;
|
||||
return (nTabs + 1) * tabSize;
|
||||
@@ -617,15 +617,15 @@ public final class EditorUtil {
|
||||
* @param c target char
|
||||
* @param x <code>'x'</code> coordinate of the line where given char is represented that indicates char end location
|
||||
* @param prevX <code>'x'</code> coordinate of the line where given char is represented that indicates char start location
|
||||
* @param spaceSize <code>'space'</code> symbol width
|
||||
* @param plainSpaceSize <code>'space'</code> symbol width (in plain font style)
|
||||
* @return number of columns necessary for representation of the given char on a screen.
|
||||
*/
|
||||
public static int columnsNumber(char c, int x, int prevX, int spaceSize) {
|
||||
public static int columnsNumber(char c, int x, int prevX, int plainSpaceSize) {
|
||||
if (c != '\t') {
|
||||
return 1;
|
||||
}
|
||||
int result = (x - prevX) / spaceSize;
|
||||
if ((x - prevX) % spaceSize > 0) {
|
||||
int result = (x - prevX) / plainSpaceSize;
|
||||
if ((x - prevX) % plainSpaceSize > 0) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
@@ -635,12 +635,12 @@ public final class EditorUtil {
|
||||
* Allows to answer how many visual columns are occupied by the given width.
|
||||
*
|
||||
* @param width target width
|
||||
* @param spaceSize width of the single space symbol within the target editor
|
||||
* @param plainSpaceSize width of the single space symbol within the target editor (in plain font style)
|
||||
* @return number of visual columns are occupied by the given width
|
||||
*/
|
||||
public static int columnsNumber(int width, int spaceSize) {
|
||||
int result = width / spaceSize;
|
||||
if (width % spaceSize > 0) {
|
||||
public static int columnsNumber(int width, int plainSpaceSize) {
|
||||
int result = width / plainSpaceSize;
|
||||
if (width % plainSpaceSize > 0) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -1153,8 +1153,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
int textLength = myDocument.getTextLength();
|
||||
LogicalPosition logicalPosition = visualToLogicalPosition(new VisualPosition(line, 0));
|
||||
int offset = logicalPositionToOffset(logicalPosition);
|
||||
int plainSpaceSize = EditorUtil.getSpaceWidth(Font.PLAIN, this);
|
||||
|
||||
if (offset >= textLength) return new VisualPosition(line, EditorUtil.columnsNumber(p.x, EditorUtil.getSpaceWidth(Font.PLAIN, this)));
|
||||
if (offset >= textLength) return new VisualPosition(line, EditorUtil.columnsNumber(p.x, plainSpaceSize));
|
||||
|
||||
// There is a possible case that starting logical line is split by soft-wraps and it's part after the split should be drawn.
|
||||
// We mark that we're under such circumstances then.
|
||||
@@ -1172,12 +1173,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
+ "to offset %d (end offset). State: %s",
|
||||
p, line, line, 0, logicalPosition, offset, line + 1, 0, endLogicalPosition, endOffset, dumpState()
|
||||
));
|
||||
return new VisualPosition(line, EditorUtil.columnsNumber(p.x, EditorUtil.getSpaceWidth(Font.PLAIN, this)));
|
||||
return new VisualPosition(line, EditorUtil.columnsNumber(p.x, plainSpaceSize));
|
||||
}
|
||||
IterationState state = new IterationState(this, offset, endOffset, false);
|
||||
|
||||
int fontType = state.getMergedAttributes().getFontType();
|
||||
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
|
||||
|
||||
int x = 0;
|
||||
int charWidth;
|
||||
@@ -1221,7 +1221,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
if (x >= px) {
|
||||
break outer;
|
||||
}
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, plainSpaceSize);
|
||||
}
|
||||
|
||||
// Process 'after soft wrap' sign.
|
||||
@@ -1261,7 +1261,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
if (x >= px) {
|
||||
break;
|
||||
}
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, plainSpaceSize);
|
||||
|
||||
offset++;
|
||||
}
|
||||
@@ -1272,16 +1272,16 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
}
|
||||
|
||||
if (charWidth < 0) {
|
||||
charWidth = spaceSize;
|
||||
charWidth = plainSpaceSize;
|
||||
}
|
||||
|
||||
if (x >= px && c == '\t' && !onSoftWrapDrawing) {
|
||||
if (mySettings.isCaretInsideTabs()) {
|
||||
column += (px - prevX) / spaceSize;
|
||||
if ((px - prevX) % spaceSize > spaceSize / 2) column++;
|
||||
column += (px - prevX) / plainSpaceSize;
|
||||
if ((px - prevX) % plainSpaceSize > plainSpaceSize / 2) column++;
|
||||
}
|
||||
else if ((x - px) * 2 < x - prevX) {
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, plainSpaceSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1290,8 +1290,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
}
|
||||
else {
|
||||
int diff = px - x;
|
||||
column += diff / spaceSize;
|
||||
if (diff % spaceSize * 2 >= spaceSize) {
|
||||
column += diff / plainSpaceSize;
|
||||
if (diff % plainSpaceSize * 2 >= plainSpaceSize) {
|
||||
column++;
|
||||
}
|
||||
}
|
||||
@@ -1549,7 +1549,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
// so, we can't just use 'startOffset + targetColumn' as a max end offset.
|
||||
IterationState state = new IterationState(this, startOffset, calcEndOffset(startOffset, targetColumn), false);
|
||||
int fontType = state.getMergedAttributes().getFontType();
|
||||
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
|
||||
int plainSpaceSize = EditorUtil.getSpaceWidth(Font.PLAIN, this);
|
||||
|
||||
int column = 0;
|
||||
outer:
|
||||
@@ -1588,8 +1588,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
if (c == '\t') {
|
||||
int prevX = x;
|
||||
x = EditorUtil.nextTabStop(x, this);
|
||||
int columnDiff = (x - prevX) / spaceSize;
|
||||
if ((x - prevX) % spaceSize > 0) {
|
||||
int columnDiff = (x - prevX) / plainSpaceSize;
|
||||
if ((x - prevX) % plainSpaceSize > 0) {
|
||||
// There is a possible case that tabulation symbol takes more than one visual column to represent and it's shown at
|
||||
// soft-wrapped line. Soft wrap sign width may be not divisible by space size, hence, part of tabulation symbol represented
|
||||
// as a separate visual column may take less space than space width.
|
||||
@@ -2895,7 +2895,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
+ ", soft wraps: " + (mySoftWrapModel.isSoftWrappingEnabled() ? "on" : "off")
|
||||
+ ", soft wraps data: " + getSoftWrapModel().dumpState()
|
||||
+ "\n\nfolding data: " + getFoldingModel().dumpState()
|
||||
+ (myDocument instanceof DocumentImpl ? "\n\ndocument info: " + ((DocumentImpl)myDocument).dumpState() : "");
|
||||
+ (myDocument instanceof DocumentImpl ? "\n\ndocument info: " + ((DocumentImpl)myDocument).dumpState() : "")
|
||||
+ "\nfont preferences: " + myScheme.getFontPreferences();
|
||||
}
|
||||
|
||||
private class CachedFontContent {
|
||||
@@ -6623,7 +6624,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
int fontType = state.getMergedAttributes().getFontType();
|
||||
int column = 0;
|
||||
int x = 0;
|
||||
int spaceSize = EditorUtil.getSpaceWidth(fontType, this);
|
||||
int plainSpaceSize = EditorUtil.getSpaceWidth(Font.PLAIN, this);
|
||||
for (int i = start; i < offset; i++) {
|
||||
if (i >= state.getEndOffset()) {
|
||||
state.advance();
|
||||
@@ -6639,7 +6640,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
if (c == '\t') {
|
||||
int prevX = x;
|
||||
x = EditorUtil.nextTabStop(x, this);
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, spaceSize);
|
||||
column += EditorUtil.columnsNumber(c, x, prevX, plainSpaceSize);
|
||||
}
|
||||
else {
|
||||
x += EditorUtil.charWidth(c, fontType, this);
|
||||
|
||||
@@ -270,8 +270,9 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
EditorPosition position = new EditorPosition(logical, start, myEditor);
|
||||
position.x = point.x;
|
||||
int spaceWidth = EditorUtil.getSpaceWidth(myContext.fontType, myEditor);
|
||||
int plainSpaceWidth = EditorUtil.getSpaceWidth(Font.PLAIN, myEditor);
|
||||
|
||||
myContext.logicalLineData.update(logical.line, spaceWidth, myEditor);
|
||||
myContext.logicalLineData.update(logical.line, spaceWidth, plainSpaceWidth);
|
||||
|
||||
myContext.currentPosition = position;
|
||||
myContext.lineStartPosition = position.clone();
|
||||
@@ -363,8 +364,7 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
revertListeners(softWrap.getStart(), myContext.currentPosition.visualLine);
|
||||
for (int j = foldRegion.getStartOffset() - 1; j >= softWrap.getStart(); j--) {
|
||||
int pixelsDiff = myOffset2widthInPixels.data[j - myOffset2widthInPixels.anchor];
|
||||
int tmpFontType = myOffset2fontType.get(j);
|
||||
int columnsDiff = calculateWidthInColumns(myContext.text.charAt(j), pixelsDiff, myContext.getSpaceWidth(tmpFontType));
|
||||
int columnsDiff = calculateWidthInColumns(myContext.text.charAt(j), pixelsDiff, myContext.getPlainSpaceWidth());
|
||||
myContext.currentPosition.offset--;
|
||||
myContext.currentPosition.logicalColumn -= columnsDiff;
|
||||
myContext.currentPosition.visualColumn -= columnsDiff;
|
||||
@@ -582,8 +582,7 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
revertListeners(actualSoftWrapOffset, myContext.currentPosition.visualLine);
|
||||
for (int j = offset - 1; j >= actualSoftWrapOffset; j--) {
|
||||
int pixelsDiff = myOffset2widthInPixels.data[j - myOffset2widthInPixels.anchor];
|
||||
int tmpFontType = myOffset2fontType.get(j);
|
||||
int columnsDiff = calculateWidthInColumns(myContext.text.charAt(j), pixelsDiff, myContext.getSpaceWidth(tmpFontType));
|
||||
int columnsDiff = calculateWidthInColumns(myContext.text.charAt(j), pixelsDiff, myContext.getPlainSpaceWidth());
|
||||
myContext.currentPosition.offset--;
|
||||
myContext.currentPosition.logicalColumn -= columnsDiff;
|
||||
myContext.currentPosition.visualColumn -= columnsDiff;
|
||||
@@ -630,12 +629,12 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
return Math.max(start, end);
|
||||
}
|
||||
|
||||
private static int calculateWidthInColumns(char c, int widthInPixels, int spaceWithInPixels) {
|
||||
private static int calculateWidthInColumns(char c, int widthInPixels, int plainSpaceWithInPixels) {
|
||||
if (c != '\t') {
|
||||
return 1;
|
||||
}
|
||||
int result = widthInPixels / spaceWithInPixels;
|
||||
if (widthInPixels % spaceWithInPixels > 0) {
|
||||
int result = widthInPixels / plainSpaceWithInPixels;
|
||||
if (widthInPixels % plainSpaceWithInPixels > 0) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
@@ -869,7 +868,7 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
}
|
||||
}
|
||||
updateLastTopLeftCornerOffset();
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateLastTopLeftCornerOffset() {
|
||||
@@ -1035,7 +1034,7 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
public int endLineOffset;
|
||||
public int nonWhiteSpaceSymbolOffset;
|
||||
|
||||
public void update(int logicalLine, int spaceWidth, Editor editor) {
|
||||
public void update(int logicalLine, int spaceWidth, int plainSpaceWidth) {
|
||||
Document document = myEditor.getDocument();
|
||||
int startLineOffset;
|
||||
if (logicalLine >= document.getLineCount()) {
|
||||
@@ -1055,8 +1054,8 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
switch (c) {
|
||||
case ' ': indentInColumns += 1; indentInPixels += spaceWidth; break;
|
||||
case '\t':
|
||||
int x = EditorUtil.nextTabStop(indentInPixels, editor);
|
||||
indentInColumns += calculateWidthInColumns(c, x - indentInPixels, spaceWidth);
|
||||
int x = EditorUtil.nextTabStop(indentInPixels, myEditor);
|
||||
indentInColumns += calculateWidthInColumns(c, x - indentInPixels, plainSpaceWidth);
|
||||
indentInPixels = x;
|
||||
break;
|
||||
default: nonWhiteSpaceSymbolOffset = i; return;
|
||||
@@ -1270,8 +1269,12 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
public int getSpaceWidth() {
|
||||
return getSpaceWidth(fontType);
|
||||
}
|
||||
|
||||
public int getSpaceWidth(@JdkConstants.FontStyle int fontType) {
|
||||
|
||||
public int getPlainSpaceWidth() {
|
||||
return getSpaceWidth(Font.PLAIN);
|
||||
}
|
||||
|
||||
private int getSpaceWidth(@JdkConstants.FontStyle int fontType) {
|
||||
int result = fontType2spaceWidth.get(fontType);
|
||||
if (result <= 0) {
|
||||
result = EditorUtil.getSpaceWidth(fontType, myEditor);
|
||||
@@ -1280,7 +1283,7 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
assert result > 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Asks current context to update its state assuming that it begins to point to the line next to its current position.
|
||||
*/
|
||||
@@ -1293,7 +1296,7 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
lastFoldEndPosition = null;
|
||||
lastFold = null;
|
||||
lineStartPosition.from(currentPosition);
|
||||
logicalLineData.update(currentPosition.logicalLine, getSpaceWidth(), myEditor);
|
||||
logicalLineData.update(currentPosition.logicalLine, getSpaceWidth(), getPlainSpaceWidth());
|
||||
fontType = myOffset2fontType.get(currentPosition.offset);
|
||||
|
||||
myOffset2fontType.clear();
|
||||
@@ -1330,7 +1333,7 @@ public class SoftWrapApplianceManager implements DocumentListener, Dumpable {
|
||||
myOffset2widthInPixels.data[currentPosition.offset - myOffset2widthInPixels.anchor] = widthInPixels;
|
||||
myOffset2widthInPixels.end++;
|
||||
|
||||
int widthInColumns = calculateWidthInColumns(c, widthInPixels, myContext.getSpaceWidth());
|
||||
int widthInColumns = calculateWidthInColumns(c, widthInPixels, myContext.getPlainSpaceWidth());
|
||||
if (c == '\t') {
|
||||
notifyListenersOnVisualLineStart(myContext.lineStartPosition);
|
||||
notifyListenersOnTabulation(widthInColumns);
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
package com.intellij.openapi.options.newEditor;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.ui.search.ConfigurableHit;
|
||||
import com.intellij.ide.ui.search.SearchUtil;
|
||||
import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.internal.statistic.UsageTrigger;
|
||||
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
|
||||
@@ -38,9 +36,7 @@ import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.EdtRunnable;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.IdeGlassPaneUtil;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.LightColors;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.SearchTextField;
|
||||
@@ -49,7 +45,6 @@ import com.intellij.ui.components.panels.NonOpaquePanel;
|
||||
import com.intellij.ui.components.panels.Wrapper;
|
||||
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;
|
||||
@@ -63,7 +58,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
@@ -79,23 +73,18 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
@NonNls private static final String MAIN_SPLITTER_PROPORTION = "options.splitter.main.proportions";
|
||||
@NonNls private static final String DETAILS_SPLITTER_PROPORTION = "options.splitter.details.proportions";
|
||||
|
||||
@NonNls private static final String SEARCH_VISIBLE = "options.searchVisible";
|
||||
|
||||
@NonNls private static final String NOT_A_NEW_COMPONENT = "component.was.already.instantiated";
|
||||
|
||||
private final Project myProject;
|
||||
|
||||
private final OptionsEditorContext myContext;
|
||||
|
||||
private final History myHistory = new History(this);
|
||||
|
||||
private final OptionsTree myTree;
|
||||
private final SettingsTreeView myTreeView;
|
||||
private final MySearchField mySearch;
|
||||
private final SearchTextField mySearch;
|
||||
private final Splitter myMainSplitter;
|
||||
//[back/forward] JComponent myToolbarComponent;
|
||||
|
||||
private final DetailsComponent myOwnDetails = new DetailsComponent().setEmptyContentText("Select configuration element in the tree to edit its settings");
|
||||
private final DetailsComponent myOwnDetails =
|
||||
new DetailsComponent().setEmptyContentText("Select configuration element in the tree to edit its settings");
|
||||
private final ContentWrapper myContentWrapper = new ContentWrapper();
|
||||
|
||||
|
||||
@@ -103,29 +92,53 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
private final Map<Configurable, ActionCallback> myConfigurable2LoadCallback = new HashMap<Configurable, ActionCallback>();
|
||||
|
||||
private final MergingUpdateQueue myModificationChecker;
|
||||
private final ConfigurableGroup[] myGroups;
|
||||
|
||||
private final SpotlightPainter mySpotlightPainter = new SpotlightPainter();
|
||||
private final MergingUpdateQueue mySpotlightUpdate;
|
||||
private final LoadingDecorator myLoadingDecorator;
|
||||
private final Filter myFilter;
|
||||
private final SettingsFilter myFilter;
|
||||
|
||||
private final Wrapper mySearchWrapper = new Wrapper();
|
||||
private final JPanel myLeftSide;
|
||||
|
||||
private boolean myFilterDocumentWasChanged;
|
||||
//[back/forward] private ActionToolbar myToolbar;
|
||||
private Window myWindow;
|
||||
private final PropertiesComponent myProperties;
|
||||
private volatile boolean myDisposed;
|
||||
|
||||
public OptionsEditor(Project project, ConfigurableGroup[] groups, Configurable preselectedConfigurable) {
|
||||
myProject = project;
|
||||
myGroups = groups;
|
||||
myProperties = PropertiesComponent.getInstance(project);
|
||||
private final KeyListener myTreeKeyListener = new KeyListener() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent event) {
|
||||
keyTyped(event);
|
||||
}
|
||||
|
||||
myFilter = new Filter();
|
||||
myContext = new OptionsEditorContext(myFilter);
|
||||
@Override
|
||||
public void keyReleased(KeyEvent event) {
|
||||
keyTyped(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent event) {
|
||||
Object source = event.getSource();
|
||||
if (source instanceof JTree) {
|
||||
JTree tree = (JTree)source;
|
||||
if (tree.getInputMap().get(KeyStroke.getKeyStrokeForEvent(event)) == null) {
|
||||
myFilter.myDocumentWasChanged = false;
|
||||
try {
|
||||
mySearch.keyEventToTextField(event);
|
||||
}
|
||||
finally {
|
||||
if (myFilter.myDocumentWasChanged && !isFilterFieldVisible()) {
|
||||
setFilterFieldVisible(true, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public OptionsEditor(Project project, ConfigurableGroup[] groups, Configurable preselectedConfigurable) {
|
||||
myProperties = PropertiesComponent.getInstance(project);
|
||||
|
||||
mySearch = new MySearchField() {
|
||||
@Override
|
||||
@@ -139,67 +152,53 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
}
|
||||
};
|
||||
|
||||
mySearch.getTextEditor().addMouseListener(new MouseAdapter() {
|
||||
myFilter = new SettingsFilter(project, groups, mySearch) {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
boolean hasText = mySearch.getText().length() > 0;
|
||||
if (!myContext.isHoldingFilter() && hasText) {
|
||||
myFilter.reenable();
|
||||
}
|
||||
|
||||
if (!isSearchFieldFocused() && hasText) {
|
||||
mySearch.selectText();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final KeyListener listener = new KeyListener() {
|
||||
@Override
|
||||
public void keyTyped(KeyEvent event) {
|
||||
myFilterDocumentWasChanged = false;
|
||||
try {
|
||||
mySearch.keyEventToTextField(event);
|
||||
}
|
||||
finally {
|
||||
if (myFilterDocumentWasChanged && !isFilterFieldVisible()) {
|
||||
setFilterFieldVisible(true, false, false);
|
||||
}
|
||||
Configurable getConfigurable(SimpleNode node) {
|
||||
if (node instanceof OptionsTree.EditorNode) {
|
||||
return ((OptionsTree.EditorNode)node).getConfigurable();
|
||||
}
|
||||
return SettingsTreeView.getConfigurable(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent event) {
|
||||
keyTyped(event);
|
||||
SimpleNode findNode(Configurable configurable) {
|
||||
return myTreeView != null
|
||||
? myTreeView.findNode(configurable)
|
||||
: myTree.findNodeFor(configurable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent event) {
|
||||
keyTyped(event);
|
||||
void updateSpotlight(boolean now) {
|
||||
if (!now) {
|
||||
mySpotlightUpdate.queue(new Update(this) {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!mySpotlightPainter.updateForCurrentConfigurable()) {
|
||||
updateSpotlight(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (!mySpotlightPainter.updateForCurrentConfigurable()) {
|
||||
updateSpotlight(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Registry.is("ide.file.settings.tree.new")) {
|
||||
myTreeView = new SettingsTreeView(listener, getContext(), groups);
|
||||
|
||||
if (Registry.is("ide.new.settings.dialog")) {
|
||||
myTreeView = new SettingsTreeView(myFilter, groups);
|
||||
myTreeView.myTree.addKeyListener(myTreeKeyListener);
|
||||
myTree = null;
|
||||
}
|
||||
else {
|
||||
myTreeView = null;
|
||||
myTree = new OptionsTree(myProject, groups, getContext()) {
|
||||
@Override
|
||||
protected void onTreeKeyEvent(final KeyEvent e) {
|
||||
listener.keyTyped(e);
|
||||
}
|
||||
};
|
||||
myTree = new OptionsTree(myFilter, groups);
|
||||
myTree.addKeyListener(myTreeKeyListener);
|
||||
}
|
||||
|
||||
getContext().addColleague(myTreeView != null ? myTreeView : myTree);
|
||||
Disposer.register(this, myTreeView != null ? myTreeView : myTree);
|
||||
mySearch.addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
myFilter.update(e.getType(), true, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* [back/forward]
|
||||
final DefaultActionGroup toolbarActions = new DefaultActionGroup();
|
||||
@@ -266,13 +265,9 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
mySpotlightUpdate = new MergingUpdateQueue("OptionsSpotlight", 200, false, this, this, this);
|
||||
|
||||
if (preselectedConfigurable != null) {
|
||||
if (myTreeView != null) {
|
||||
myTreeView.select(preselectedConfigurable);
|
||||
}
|
||||
else {
|
||||
myTree.select(preselectedConfigurable);
|
||||
}
|
||||
} else {
|
||||
selectInTree(preselectedConfigurable);
|
||||
}
|
||||
else {
|
||||
if (myTreeView != null) {
|
||||
myTreeView.selectFirst();
|
||||
}
|
||||
@@ -324,6 +319,12 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
});
|
||||
}
|
||||
|
||||
private ActionCallback selectInTree(Configurable configurable) {
|
||||
return myTreeView != null
|
||||
? myTreeView.select(configurable)
|
||||
: myTree.select(configurable);
|
||||
}
|
||||
|
||||
/** @see #select(com.intellij.openapi.options.Configurable) */
|
||||
@Deprecated
|
||||
public ActionCallback select(Class<? extends Configurable> configurableClass) {
|
||||
@@ -356,18 +357,17 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
}
|
||||
|
||||
public ActionCallback select(Configurable configurable) {
|
||||
if (StringUtil.isEmpty(mySearch.getText())) {
|
||||
if (myFilter.getFilterText().isEmpty()) {
|
||||
return select(configurable, "");
|
||||
} else {
|
||||
return myFilter.refilterFor(mySearch.getText(), true, true);
|
||||
}
|
||||
else {
|
||||
return myFilter.update(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public ActionCallback select(Configurable configurable, final String text) {
|
||||
myFilter.refilterFor(text, false, true);
|
||||
return myTreeView != null
|
||||
? myTreeView.select(configurable)
|
||||
: myTree.select(configurable);
|
||||
myFilter.update(text, false, true);
|
||||
return selectInTree(configurable);
|
||||
}
|
||||
|
||||
private float readProportion(final float defaultValue, final String propertyName) {
|
||||
@@ -392,7 +392,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
if (configurable == null) {
|
||||
myOwnDetails.setContent(null);
|
||||
|
||||
updateSpotlight(true);
|
||||
myFilter.updateSpotlight(true);
|
||||
checkModified(oldConfigurable);
|
||||
|
||||
result.setDone();
|
||||
@@ -432,7 +432,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
|
||||
myLoadingDecorator.stopLoading();
|
||||
|
||||
updateSpotlight(false);
|
||||
myFilter.updateSpotlight(false);
|
||||
|
||||
checkModified(oldConfigurable);
|
||||
checkModified(configurable);
|
||||
@@ -482,7 +482,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
((ApplicationEx)app).runEdtSafeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myProject.isDisposed()) {
|
||||
if (myFilter.myProject.isDisposed()) {
|
||||
result.setRejected();
|
||||
}
|
||||
else {
|
||||
@@ -539,26 +539,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private void updateSpotlight(boolean now) {
|
||||
if (now) {
|
||||
final boolean success = mySpotlightPainter.updateForCurrentConfigurable();
|
||||
if (!success) {
|
||||
updateSpotlight(false);
|
||||
}
|
||||
} else {
|
||||
mySpotlightUpdate.queue(new Update(this) {
|
||||
@Override
|
||||
public void run() {
|
||||
final boolean success = mySpotlightPainter.updateForCurrentConfigurable();
|
||||
if (!success) {
|
||||
updateSpotlight(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getBannerText(Configurable configurable) {
|
||||
if (myTreeView != null) {
|
||||
return myTreeView.getPathNames(configurable);
|
||||
@@ -714,7 +694,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return myContext.isModified(myConfigurable) || getContext().getErrors().containsKey(myConfigurable);
|
||||
return myFilter.myContext.isModified(myConfigurable) || getContext().getErrors().containsKey(myConfigurable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -851,12 +831,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
getContext().fireErrorsChanged(errors, null);
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
if (myTreeView != null) {
|
||||
myTreeView.select(errors.keySet().iterator().next());
|
||||
}
|
||||
else {
|
||||
myTree.select(errors.keySet().iterator().next());
|
||||
}
|
||||
selectInTree(errors.keySet().iterator().next());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,145 +853,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
return new Dimension(1200, 768);
|
||||
}
|
||||
|
||||
private class Filter extends ElementFilter.Active.Impl<SimpleNode> {
|
||||
|
||||
SearchableOptionsRegistrar myIndex = SearchableOptionsRegistrar.getInstance();
|
||||
Set<Configurable> myFiltered = null;
|
||||
ConfigurableHit myHits;
|
||||
|
||||
boolean myUpdateEnabled = true;
|
||||
private Configurable myLastSelected;
|
||||
|
||||
@Override
|
||||
public boolean shouldBeShowing(final SimpleNode value) {
|
||||
if (myFiltered == null) return true;
|
||||
|
||||
if (value instanceof OptionsTree.EditorNode) {
|
||||
final OptionsTree.EditorNode node = (OptionsTree.EditorNode)value;
|
||||
return myFiltered.contains(node.getConfigurable()) || isChildOfNameHit(node);
|
||||
}
|
||||
|
||||
return SettingsTreeView.isFiltered(myFiltered, myHits, value);
|
||||
}
|
||||
|
||||
private boolean isChildOfNameHit(OptionsTree.EditorNode node) {
|
||||
if (myHits != null) {
|
||||
OptionsTree.Base eachParent = node;
|
||||
while (eachParent != null) {
|
||||
if (eachParent instanceof OptionsTree.EditorNode) {
|
||||
final OptionsTree.EditorNode eachEditorNode = (OptionsTree.EditorNode)eachParent;
|
||||
if (myHits.getNameFullHits().contains(eachEditorNode.myConfigurable)) return true;
|
||||
}
|
||||
eachParent = (OptionsTree.Base)eachParent.getParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ActionCallback refilterFor(String text, boolean adjustSelection, final boolean now) {
|
||||
try {
|
||||
myUpdateEnabled = false;
|
||||
mySearch.setText(text);
|
||||
}
|
||||
finally {
|
||||
myUpdateEnabled = true;
|
||||
}
|
||||
|
||||
return update(DocumentEvent.EventType.CHANGE, adjustSelection, now);
|
||||
}
|
||||
|
||||
public void clearTemporary() {
|
||||
myContext.setHoldingFilter(false);
|
||||
updateSpotlight(false);
|
||||
}
|
||||
|
||||
public void reenable() {
|
||||
myContext.setHoldingFilter(true);
|
||||
updateSpotlight(false);
|
||||
}
|
||||
|
||||
public ActionCallback update(DocumentEvent.EventType type, boolean adjustSelection, boolean now) {
|
||||
if (!myUpdateEnabled) return new ActionCallback.Rejected();
|
||||
|
||||
final String text = mySearch.getText();
|
||||
if (getFilterText().length() == 0) {
|
||||
myContext.setHoldingFilter(false);
|
||||
myFiltered = null;
|
||||
} else {
|
||||
myContext.setHoldingFilter(true);
|
||||
myHits = myIndex.getConfigurables(myGroups, type, myFiltered, text, myProject);
|
||||
myFiltered = myHits.getAll();
|
||||
}
|
||||
|
||||
if (myFiltered != null && myFiltered.isEmpty()) {
|
||||
mySearch.getTextEditor().setBackground(LightColors.RED);
|
||||
} else {
|
||||
mySearch.getTextEditor().setBackground(UIUtil.getTextFieldBackground());
|
||||
}
|
||||
|
||||
|
||||
final Configurable current = getContext().getCurrentConfigurable();
|
||||
|
||||
boolean shouldMoveSelection = true;
|
||||
|
||||
if (myHits != null && (myHits.getNameFullHits().contains(current) || myHits.getContentHits().contains(current))) {
|
||||
shouldMoveSelection = false;
|
||||
}
|
||||
|
||||
if (shouldMoveSelection && type != DocumentEvent.EventType.INSERT && (myFiltered == null || myFiltered.contains(current))) {
|
||||
shouldMoveSelection = false;
|
||||
}
|
||||
|
||||
Configurable toSelect = adjustSelection ? current : null;
|
||||
if (shouldMoveSelection && myHits != null) {
|
||||
if (!myHits.getNameHits().isEmpty()) {
|
||||
toSelect = suggestToSelect(myHits.getNameHits(), myHits.getNameFullHits());
|
||||
} else if (!myHits.getContentHits().isEmpty()) {
|
||||
toSelect = suggestToSelect(myHits.getContentHits(), null);
|
||||
}
|
||||
}
|
||||
|
||||
updateSpotlight(false);
|
||||
|
||||
if ((myFiltered == null || !myFiltered.isEmpty()) && toSelect == null && myLastSelected != null) {
|
||||
toSelect = myLastSelected;
|
||||
myLastSelected = null;
|
||||
}
|
||||
|
||||
if (toSelect == null && current != null) {
|
||||
myLastSelected = current;
|
||||
}
|
||||
|
||||
SimpleNode node = !adjustSelection ? null : myTreeView != null ? myTreeView.findNode(toSelect) : myTree.findNodeFor(toSelect);
|
||||
final ActionCallback callback = fireUpdate(node, adjustSelection, now);
|
||||
|
||||
myFilterDocumentWasChanged = true;
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
private boolean isEmptyParent(Configurable configurable) {
|
||||
return configurable instanceof SearchableConfigurable.Parent && !((SearchableConfigurable.Parent)configurable).hasOwnContent();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Configurable suggestToSelect(Set<Configurable> set, Set<Configurable> fullHits) {
|
||||
Configurable candidate = null;
|
||||
for (Configurable each : set) {
|
||||
if (fullHits != null && fullHits.contains(each)) return each;
|
||||
if (!isEmptyParent(each) && candidate == null) {
|
||||
candidate = each;
|
||||
}
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionCallback navigateTo(@Nullable final Place place, final boolean requestFocus) {
|
||||
final Configurable config = (Configurable)place.getPath("configurable");
|
||||
@@ -1024,15 +860,10 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
|
||||
final ActionCallback result = new ActionCallback();
|
||||
|
||||
myFilter.refilterFor(filter, false, true).doWhenDone(new Runnable() {
|
||||
myFilter.update(filter, false, true).doWhenDone(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myTreeView != null) {
|
||||
myTreeView.select(config).notifyWhenDone(result);
|
||||
}
|
||||
else {
|
||||
myTree.select(config).notifyWhenDone(result);
|
||||
}
|
||||
selectInTree(config).notifyWhenDone(result);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1043,7 +874,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
public void queryPlace(@NotNull final Place place) {
|
||||
final Configurable current = getContext().getCurrentConfigurable();
|
||||
place.putPath("configurable", current);
|
||||
place.putPath("filter", getFilterText());
|
||||
place.putPath("filter", myFilter.getFilterText());
|
||||
|
||||
if (current instanceof Place.Navigator) {
|
||||
((Place.Navigator)current).queryPlace(place);
|
||||
@@ -1062,7 +893,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
|
||||
myProperties.setValue(MAIN_SPLITTER_PROPORTION, String.valueOf(myMainSplitter.getProportion()));
|
||||
myProperties.setValue(DETAILS_SPLITTER_PROPORTION, String.valueOf(myContentWrapper.myLastSplitterProportion));
|
||||
myProperties.setValue(SEARCH_VISIBLE, Boolean.valueOf(isFilterFieldVisible()).toString());
|
||||
|
||||
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
|
||||
|
||||
@@ -1089,7 +919,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
}
|
||||
|
||||
public OptionsEditorContext getContext() {
|
||||
return myContext;
|
||||
return myFilter.myContext;
|
||||
}
|
||||
|
||||
private class MyColleague extends OptionsEditorColleague.Adapter {
|
||||
@@ -1139,7 +969,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
final MouseEvent me = (MouseEvent)event;
|
||||
if (SwingUtilities.isDescendingFrom(me.getComponent(), SwingUtilities.getWindowAncestor(myContentWrapper)) || isPopupOverEditor(me.getComponent())) {
|
||||
queueModificationCheck();
|
||||
myFilter.clearTemporary();
|
||||
myFilter.setHoldingFilter(false);
|
||||
}
|
||||
}
|
||||
else if (event.getID() == KeyEvent.KEY_PRESSED || event.getID() == KeyEvent.KEY_RELEASED) {
|
||||
@@ -1238,7 +1068,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
return ApplicationManager.getApplication().isUnitTestMode();
|
||||
}
|
||||
|
||||
String text = getFilterText();
|
||||
String text = myFilter.getFilterText();
|
||||
|
||||
try {
|
||||
final boolean sameText =
|
||||
@@ -1265,14 +1095,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
myVisible = true;//myContext.isHoldingFilter();
|
||||
runnable.run();
|
||||
|
||||
boolean pushFilteringFurther = true;
|
||||
if (sameText) {
|
||||
pushFilteringFurther = false;
|
||||
} else {
|
||||
if (myFilter.myHits != null) {
|
||||
pushFilteringFurther = !myFilter.myHits.getNameHits().contains(current);
|
||||
}
|
||||
}
|
||||
boolean pushFilteringFurther = !sameText && !myFilter.contains(current);
|
||||
|
||||
final Runnable ownSearch = searchable.enableSearch(text);
|
||||
if (pushFilteringFurther && ownSearch != null) {
|
||||
@@ -1297,10 +1120,6 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
|
||||
}
|
||||
}
|
||||
|
||||
private String getFilterText() {
|
||||
return mySearch.getText() != null ? mySearch.getText().trim() : "";
|
||||
}
|
||||
|
||||
private static class SearachableWrappper implements SearchableConfigurable {
|
||||
private final Configurable myConfigurable;
|
||||
|
||||
|
||||
@@ -59,23 +59,20 @@ import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public class OptionsTree extends JPanel implements Disposable, OptionsEditorColleague {
|
||||
Project myProject;
|
||||
private final SettingsFilter myFilter;
|
||||
final SimpleTree myTree;
|
||||
List<ConfigurableGroup> myGroups;
|
||||
FilteringTreeBuilder myBuilder;
|
||||
Root myRoot;
|
||||
OptionsEditorContext myContext;
|
||||
|
||||
Map<Configurable, EditorNode> myConfigurable2Node = new HashMap<Configurable, EditorNode>();
|
||||
|
||||
MergingUpdateQueue mySelection;
|
||||
private final OptionsTree.Renderer myRenderer;
|
||||
|
||||
public OptionsTree(Project project, ConfigurableGroup[] groups, OptionsEditorContext context) {
|
||||
myProject = project;
|
||||
public OptionsTree(SettingsFilter filter, ConfigurableGroup... groups) {
|
||||
myFilter = filter;
|
||||
myGroups = Arrays.asList(groups);
|
||||
myContext = context;
|
||||
|
||||
|
||||
myRoot = new Root();
|
||||
final SimpleTreeStructure structure = new SimpleTreeStructure() {
|
||||
@@ -132,35 +129,8 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
}
|
||||
}
|
||||
});
|
||||
myTree.addKeyListener(new KeyListener() {
|
||||
public void keyTyped(final KeyEvent e) {
|
||||
_onTreeKeyEvent(e);
|
||||
}
|
||||
|
||||
public void keyPressed(final KeyEvent e) {
|
||||
_onTreeKeyEvent(e);
|
||||
}
|
||||
|
||||
public void keyReleased(final KeyEvent e) {
|
||||
_onTreeKeyEvent(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void _onTreeKeyEvent(KeyEvent e) {
|
||||
final KeyStroke stroke = KeyStroke.getKeyStrokeForEvent(e);
|
||||
|
||||
final Object action = myTree.getInputMap().get(stroke);
|
||||
if (action == null) {
|
||||
onTreeKeyEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onTreeKeyEvent(KeyEvent e) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
ActionCallback select(@Nullable Configurable configurable) {
|
||||
return queueSelection(configurable);
|
||||
}
|
||||
@@ -191,7 +161,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
|
||||
if (configurable == null) {
|
||||
myTree.getSelectionModel().clearSelection();
|
||||
myContext.fireSelected(null, OptionsTree.this);
|
||||
myFilter.myContext.fireSelected(null, OptionsTree.this);
|
||||
}
|
||||
else {
|
||||
myBuilder.getReady(this).doWhenDone(new Runnable() {
|
||||
@@ -232,7 +202,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
}
|
||||
|
||||
private void fireSelected(Configurable configurable, final ActionCallback callback) {
|
||||
myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
|
||||
myFilter.myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
|
||||
}
|
||||
|
||||
|
||||
@@ -538,7 +508,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
final List<EditorNode> result = new ArrayList<EditorNode>(kids.length);
|
||||
for (Configurable child : kids) {
|
||||
result.add(new EditorNode(parent, child, group));
|
||||
myContext.registerKid(configurable, child);
|
||||
myFilter.myContext.registerKid(configurable, child);
|
||||
}
|
||||
return result; // TODO: DECIDE IF INNERS SHOULD BE SORTED: sort(result);
|
||||
}
|
||||
@@ -602,12 +572,12 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
|
||||
@Override
|
||||
boolean isModified() {
|
||||
return myContext.getModified().contains(myConfigurable);
|
||||
return myFilter.myContext.getModified().contains(myConfigurable);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isError() {
|
||||
return myContext.getErrors().containsKey(myConfigurable);
|
||||
return myFilter.myContext.getErrors().containsKey(myConfigurable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,7 +780,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
boolean myWasHoldingFilter;
|
||||
|
||||
public MyBuilder(SimpleTreeStructure structure) {
|
||||
super(OptionsTree.this.myTree, myContext.getFilter(), structure, new WeightBasedComparator(false));
|
||||
super(myTree, myFilter, structure, new WeightBasedComparator(false));
|
||||
myTree.addTreeExpansionListener(new TreeExpansionListener() {
|
||||
public void treeExpanded(TreeExpansionEvent event) {
|
||||
invalidateExpansions();
|
||||
@@ -835,7 +805,7 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
|
||||
@Override
|
||||
public boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor) {
|
||||
return myContext.isHoldingFilter();
|
||||
return myFilter.myContext.isHoldingFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -846,21 +816,21 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
|
||||
@Override
|
||||
protected ActionCallback refilterNow(Object preferredSelection, boolean adjustSelection) {
|
||||
final List<Object> toRestore = new ArrayList<Object>();
|
||||
if (myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
|
||||
if (myFilter.myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
|
||||
myToExpandOnResetFilter = myBuilder.getUi().getExpandedElements();
|
||||
} else if (!myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
|
||||
} else if (!myFilter.myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
|
||||
toRestore.addAll(myToExpandOnResetFilter);
|
||||
myToExpandOnResetFilter = null;
|
||||
}
|
||||
|
||||
myWasHoldingFilter = myContext.isHoldingFilter();
|
||||
myWasHoldingFilter = myFilter.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()) {
|
||||
if (!myFilter.myContext.isHoldingFilter() && getSelectedElements().isEmpty()) {
|
||||
restoreExpandedState(toRestore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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.ide.ui.search.ConfigurableHit;
|
||||
import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurableGroup;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.LightColors;
|
||||
import com.intellij.ui.SearchTextField;
|
||||
import com.intellij.ui.speedSearch.ElementFilter;
|
||||
import com.intellij.ui.treeStructure.SimpleNode;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Set;
|
||||
|
||||
abstract class SettingsFilter extends ElementFilter.Active.Impl<SimpleNode> {
|
||||
final OptionsEditorContext myContext = new OptionsEditorContext(this);
|
||||
final Project myProject;
|
||||
|
||||
boolean myDocumentWasChanged;
|
||||
|
||||
private final SearchTextField mySearch;
|
||||
private final ConfigurableGroup[] myGroups;
|
||||
|
||||
private SearchableOptionsRegistrar myRegistrar = SearchableOptionsRegistrar.getInstance();
|
||||
private Set<Configurable> myFiltered;
|
||||
private ConfigurableHit myHits;
|
||||
|
||||
private boolean myUpdateRejected;
|
||||
private Configurable myLastSelected;
|
||||
|
||||
SettingsFilter(Project project, ConfigurableGroup[] groups, SearchTextField search) {
|
||||
myProject = project;
|
||||
myGroups = groups;
|
||||
mySearch = search;
|
||||
mySearch.addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent event) {
|
||||
update(event.getType(), true, false);
|
||||
}
|
||||
});
|
||||
mySearch.getTextEditor().addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent event) {
|
||||
if (!mySearch.getText().isEmpty()) {
|
||||
if (!myContext.isHoldingFilter()) {
|
||||
setHoldingFilter(true);
|
||||
}
|
||||
if (!mySearch.getTextEditor().isFocusOwner()) {
|
||||
mySearch.selectText();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
abstract Configurable getConfigurable(SimpleNode node);
|
||||
|
||||
abstract SimpleNode findNode(Configurable configurable);
|
||||
|
||||
abstract void updateSpotlight(boolean now);
|
||||
|
||||
@Override
|
||||
public boolean shouldBeShowing(SimpleNode node) {
|
||||
if (myFiltered != null) {
|
||||
Configurable configurable = getConfigurable(node);
|
||||
if (configurable != null) {
|
||||
if (!myFiltered.contains(configurable)) {
|
||||
if (myHits != null) {
|
||||
Set<Configurable> configurables = myHits.getNameFullHits();
|
||||
while (node != null) {
|
||||
if (configurable != null) {
|
||||
if (configurables.contains(configurable)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
node = node.getParent();
|
||||
configurable = getConfigurable(node);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
String getFilterText() {
|
||||
String text = mySearch.getText();
|
||||
return text == null ? "" : text.trim();
|
||||
}
|
||||
|
||||
void setHoldingFilter(boolean holding) {
|
||||
myContext.setHoldingFilter(holding);
|
||||
updateSpotlight(false);
|
||||
}
|
||||
|
||||
boolean contains(Configurable configurable) {
|
||||
return myHits != null && myHits.getNameHits().contains(configurable);
|
||||
}
|
||||
|
||||
ActionCallback update(boolean adjustSelection, boolean now) {
|
||||
return update(DocumentEvent.EventType.CHANGE, adjustSelection, now);
|
||||
}
|
||||
|
||||
ActionCallback update(String text, boolean adjustSelection, boolean now) {
|
||||
try {
|
||||
myUpdateRejected = true;
|
||||
mySearch.setText(text);
|
||||
}
|
||||
finally {
|
||||
myUpdateRejected = false;
|
||||
}
|
||||
return update(adjustSelection, now);
|
||||
}
|
||||
|
||||
private ActionCallback update(DocumentEvent.EventType type, boolean adjustSelection, boolean now) {
|
||||
if (myUpdateRejected) {
|
||||
return new ActionCallback.Rejected();
|
||||
}
|
||||
String text = getFilterText();
|
||||
if (text.isEmpty()) {
|
||||
myContext.setHoldingFilter(false);
|
||||
myFiltered = null;
|
||||
}
|
||||
else {
|
||||
myContext.setHoldingFilter(true);
|
||||
myHits = myRegistrar.getConfigurables(myGroups, type, myFiltered, text, myProject);
|
||||
myFiltered = myHits.getAll();
|
||||
}
|
||||
mySearch.getTextEditor().setBackground(myFiltered != null && myFiltered.isEmpty()
|
||||
? LightColors.RED
|
||||
: UIUtil.getTextFieldBackground());
|
||||
|
||||
|
||||
Configurable current = myContext.getCurrentConfigurable();
|
||||
|
||||
boolean shouldMoveSelection = myHits == null || (
|
||||
!myHits.getNameFullHits().contains(current) &&
|
||||
!myHits.getContentHits().contains(current));
|
||||
|
||||
if (shouldMoveSelection && type != DocumentEvent.EventType.INSERT && (myFiltered == null || myFiltered.contains(current))) {
|
||||
shouldMoveSelection = false;
|
||||
}
|
||||
|
||||
Configurable candidate = adjustSelection ? current : null;
|
||||
if (shouldMoveSelection && myHits != null) {
|
||||
if (!myHits.getNameHits().isEmpty()) {
|
||||
candidate = findConfigurable(myHits.getNameHits(), myHits.getNameFullHits());
|
||||
}
|
||||
else if (!myHits.getContentHits().isEmpty()) {
|
||||
candidate = findConfigurable(myHits.getContentHits(), null);
|
||||
}
|
||||
}
|
||||
updateSpotlight(false);
|
||||
|
||||
if ((myFiltered == null || !myFiltered.isEmpty()) && candidate == null && myLastSelected != null) {
|
||||
candidate = myLastSelected;
|
||||
myLastSelected = null;
|
||||
}
|
||||
if (candidate == null && current != null) {
|
||||
myLastSelected = current;
|
||||
}
|
||||
SimpleNode node = !adjustSelection ? null : findNode(candidate);
|
||||
ActionCallback callback = fireUpdate(node, adjustSelection, now);
|
||||
myDocumentWasChanged = true;
|
||||
return callback;
|
||||
}
|
||||
|
||||
private static Configurable findConfigurable(Set<Configurable> configurables, Set<Configurable> hits) {
|
||||
Configurable candidate = null;
|
||||
for (Configurable configurable : configurables) {
|
||||
if (hits != null && hits.contains(configurable)) {
|
||||
return configurable;
|
||||
}
|
||||
if (candidate == null && !isEmptyParent(configurable)) {
|
||||
candidate = configurable;
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private static boolean isEmptyParent(Configurable configurable) {
|
||||
if (configurable instanceof SearchableConfigurable.Parent) {
|
||||
SearchableConfigurable.Parent parent = (SearchableConfigurable.Parent)configurable;
|
||||
return !parent.hasOwnContent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
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.*;
|
||||
@@ -60,18 +59,19 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
final SimpleTree myTree;
|
||||
final FilteringTreeBuilder myBuilder;
|
||||
|
||||
private final OptionsEditorContext myContext;
|
||||
private final SettingsFilter myFilter;
|
||||
private final MyRoot myRoot;
|
||||
private final JScrollPane myScroller;
|
||||
private JLabel mySeparator;
|
||||
private final MyRenderer myRenderer = new MyRenderer();
|
||||
private final IdentityHashMap<Configurable, MyNode> myConfigurableToNodeMap = new IdentityHashMap<Configurable, MyNode>();
|
||||
private final MergingUpdateQueue myQueue = new MergingUpdateQueue("OptionsTree", 150, false, this, this, this).setRestartTimerOnAdd(true);
|
||||
private final MergingUpdateQueue myQueue = new MergingUpdateQueue("SettingsTreeView", 150, false, this, this, this)
|
||||
.setRestartTimerOnAdd(true);
|
||||
|
||||
private Configurable myQueuedConfigurable;
|
||||
|
||||
SettingsTreeView(final KeyListener listener, OptionsEditorContext context, ConfigurableGroup... groups) {
|
||||
myContext = context;
|
||||
SettingsTreeView(SettingsFilter filter, ConfigurableGroup... groups) {
|
||||
myFilter = filter;
|
||||
myRoot = new MyRoot(groups);
|
||||
|
||||
myTree = new MyTree();
|
||||
@@ -116,29 +116,6 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
@@ -158,9 +135,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
return ArrayUtil.toStringArray(path);
|
||||
}
|
||||
|
||||
static Configurable getConfigurable(SimpleNode node) {
|
||||
return node instanceof MyNode
|
||||
? ((MyNode)node).myConfigurable
|
||||
: null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
SimpleNode findNode(Configurable toSelect) {
|
||||
return myConfigurableToNodeMap.get(toSelect);
|
||||
SimpleNode findNode(Configurable configurable) {
|
||||
return myConfigurableToNodeMap.get(configurable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -250,24 +233,6 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
: null;
|
||||
}
|
||||
|
||||
static boolean isFiltered(Set<Configurable> configurables, ConfigurableHit hits, SimpleNode value) {
|
||||
if (value instanceof MyNode && !configurables.contains(((MyNode)value).myConfigurable)) {
|
||||
if (hits != null) {
|
||||
configurables = hits.getNameFullHits();
|
||||
while (value != null) {
|
||||
if (value instanceof MyNode) {
|
||||
if (configurables.contains(((MyNode)value).myConfigurable)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
value = value.getParent();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout() {
|
||||
myScroller.setBounds(0, 0, getWidth(), getHeight());
|
||||
@@ -375,7 +340,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
}
|
||||
|
||||
private void fireSelected(Configurable configurable, ActionCallback callback) {
|
||||
myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
|
||||
myFilter.myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -463,7 +428,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
for (int i = 0; i < configurables.length; i++) {
|
||||
result[i] = new MyNode(this, configurables[i]);
|
||||
if (myConfigurable != null) {
|
||||
myContext.registerKid(myConfigurable, configurables[i]);
|
||||
myFilter.myContext.registerKid(myConfigurable, configurables[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -553,10 +518,10 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
if (!selected && node != null) {
|
||||
Configurable configurable = node.myConfigurable;
|
||||
if (configurable != null) {
|
||||
if (myContext.getErrors().containsKey(configurable)) {
|
||||
if (myFilter.myContext.getErrors().containsKey(configurable)) {
|
||||
myTextLabel.setForeground(JBColor.RED);
|
||||
}
|
||||
else if (myContext.getModified().contains(configurable)) {
|
||||
else if (myFilter.myContext.getModified().contains(configurable)) {
|
||||
myTextLabel.setForeground(JBColor.BLUE);
|
||||
}
|
||||
}
|
||||
@@ -608,7 +573,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
}
|
||||
|
||||
int getSeparatorHeight() {
|
||||
return mySeparatorComponent.getPreferredSize().height;
|
||||
return mySeparatorComponent.getParent() == null ? 0 : mySeparatorComponent.getPreferredSize().height;
|
||||
}
|
||||
|
||||
public boolean isUnderHandle(Point point) {
|
||||
@@ -779,7 +744,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
boolean myWasHoldingFilter;
|
||||
|
||||
public MyBuilder(SimpleTreeStructure structure) {
|
||||
super(myTree, myContext.getFilter(), structure, new WeightBasedComparator(false));
|
||||
super(myTree, myFilter, structure, new WeightBasedComparator(false));
|
||||
myTree.addTreeExpansionListener(new TreeExpansionListener() {
|
||||
public void treeExpanded(TreeExpansionEvent event) {
|
||||
invalidateExpansions();
|
||||
@@ -804,7 +769,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
|
||||
@Override
|
||||
public boolean isAutoExpandNode(NodeDescriptor nodeDescriptor) {
|
||||
return myContext.isHoldingFilter();
|
||||
return myFilter.myContext.isHoldingFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -815,22 +780,22 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
|
||||
@Override
|
||||
protected ActionCallback refilterNow(Object preferredSelection, boolean adjustSelection) {
|
||||
final List<Object> toRestore = new ArrayList<Object>();
|
||||
if (myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
|
||||
if (myFilter.myContext.isHoldingFilter() && !myWasHoldingFilter && myToExpandOnResetFilter == null) {
|
||||
myToExpandOnResetFilter = myBuilder.getUi().getExpandedElements();
|
||||
}
|
||||
else if (!myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
|
||||
else if (!myFilter.myContext.isHoldingFilter() && myWasHoldingFilter && myToExpandOnResetFilter != null) {
|
||||
toRestore.addAll(myToExpandOnResetFilter);
|
||||
myToExpandOnResetFilter = null;
|
||||
}
|
||||
|
||||
myWasHoldingFilter = myContext.isHoldingFilter();
|
||||
myWasHoldingFilter = myFilter.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()) {
|
||||
if (!myFilter.myContext.isHoldingFilter() && getSelectedElements().isEmpty()) {
|
||||
restoreExpandedState(toRestore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -368,6 +368,7 @@ public abstract class AbstractExpandableItemsHandler<KeyType, ComponentType exte
|
||||
if (!(renderer instanceof JComponent)) return null;
|
||||
|
||||
myKeyItemBounds = rendererAndBounds.second;
|
||||
myKeyItemBounds.width = Math.min(myKeyItemBounds.width, myComponent.getToolkit().getScreenSize().width);
|
||||
|
||||
Rectangle cellBounds = myKeyItemBounds;
|
||||
Rectangle visibleRect = getVisibleRect(key);
|
||||
|
||||
@@ -50,6 +50,8 @@ class LibNotifyWrapper implements SystemNotificationsImpl.Notifier {
|
||||
|
||||
private final LibNotify myLibNotify;
|
||||
private final String myIcon;
|
||||
private final Object myLock = new Object();
|
||||
private boolean myDisposed = false;
|
||||
|
||||
private LibNotifyWrapper() {
|
||||
myLibNotify = (LibNotify)Native.loadLibrary("libnotify.so.4", LibNotify.class);
|
||||
@@ -66,14 +68,21 @@ class LibNotifyWrapper implements SystemNotificationsImpl.Notifier {
|
||||
connection.subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() {
|
||||
@Override
|
||||
public void appClosing() {
|
||||
myLibNotify.notify_uninit();
|
||||
synchronized (myLock) {
|
||||
myDisposed = true;
|
||||
myLibNotify.notify_uninit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(@NotNull Set<String> allNames, @NotNull String name, @NotNull String title, @NotNull String description) {
|
||||
Pointer notification = myLibNotify.notify_notification_new(title, description, myIcon);
|
||||
myLibNotify.notify_notification_show(notification, null);
|
||||
synchronized (myLock) {
|
||||
if (!myDisposed) {
|
||||
Pointer notification = myLibNotify.notify_notification_new(title, description, myIcon);
|
||||
myLibNotify.notify_notification_show(notification, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,6 +34,14 @@ public class Conditions {
|
||||
return (Condition<T>)FALSE;
|
||||
}
|
||||
|
||||
public static <T> Condition<T> instanceOf(final Class<?> clazz) {
|
||||
return new Condition<T>() {
|
||||
public boolean value(T t) {
|
||||
return clazz.isInstance(t);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> Condition<T> is(final T option) {
|
||||
return new Condition<T>() {
|
||||
public boolean value(T t) {
|
||||
|
||||
@@ -395,7 +395,6 @@ console.too.much.text.buffer.ratio.description=Used for disabling of console pro
|
||||
The ratio is used against the console cycle buffer size (idea.cycle.buffer.size/theRatio=maxTextLength).
|
||||
ide.new.settings.dialog=false
|
||||
ide.new.settings.dialog.description=New settings dialog
|
||||
ide.file.settings.tree.new=false
|
||||
ide.new.project.settings=true
|
||||
ide.new.project.settings.description=Temporary key for new project settings dialog UI
|
||||
|
||||
|
||||
@@ -204,34 +204,28 @@ public class JDOMUtil {
|
||||
|
||||
@NotNull
|
||||
private static String intern(@NotNull final StringInterner interner, @NotNull final String s) {
|
||||
synchronized (interner) {
|
||||
return interner.intern(s);
|
||||
}
|
||||
return interner.intern(s);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String legalizeText(@NotNull final String str) {
|
||||
StringReader reader = new StringReader(str);
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
while(true) {
|
||||
try {
|
||||
int each = reader.read();
|
||||
if (each == -1) break;
|
||||
|
||||
if (Verifier.isXMLCharacter(each)) {
|
||||
result.append((char)each);
|
||||
} else {
|
||||
result.append("0x").append(StringUtil.toUpperCase(Long.toHexString(each)));
|
||||
}
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
StringBuilder result = new StringBuilder(str.length());
|
||||
for (int i = 0, len = str.length(); i < len; i ++) {
|
||||
result.append(str.charAt(i));
|
||||
legalizeChar(result, result.length() - 1);
|
||||
}
|
||||
|
||||
return result.toString().replaceAll("<", "<").replaceAll(">", ">");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static void legalizeChar(@NotNull StringBuilder sb, int pos) {
|
||||
char each = sb.charAt(pos);
|
||||
if (each == '<' || each == '>') {
|
||||
sb.replace(pos, pos + 1, each == '<' ? "<" : ">");
|
||||
}
|
||||
else if (!Verifier.isXMLCharacter(each)) {
|
||||
sb.replace(pos, pos + 1, "0x").insert(pos + 2, StringUtil.toUpperCase(Long.toHexString(each)));
|
||||
}
|
||||
}
|
||||
|
||||
private static class EmptyTextFilter implements Filter {
|
||||
@Override
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1073,7 +1073,8 @@ public class ContainerUtil extends ContainerUtilRt {
|
||||
}
|
||||
|
||||
public static <T, U extends T> U findInstance(@NotNull Iterator<T> iterator, @NotNull Class<U> aClass) {
|
||||
@SuppressWarnings("unchecked") U u = (U)find(iterator, new FilteringIterator.InstanceOf<U>(aClass));
|
||||
//noinspection unchecked
|
||||
U u = (U)find(iterator, FilteringIterator.instanceOf(aClass));
|
||||
return u;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.intellij.util.containers;
|
||||
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
@@ -30,7 +29,7 @@ import java.util.NoSuchElementException;
|
||||
*/
|
||||
public class FilteringIterator<Dom, E extends Dom> implements Iterator<E> {
|
||||
private final Iterator<Dom> myBaseIterator;
|
||||
private final Condition<Dom> myFilter;
|
||||
private final Condition<? super Dom> myFilter;
|
||||
private boolean myNextObtained = false;
|
||||
private boolean myCurrentIsValid = false;
|
||||
private Dom myCurrent;
|
||||
@@ -42,7 +41,7 @@ public class FilteringIterator<Dom, E extends Dom> implements Iterator<E> {
|
||||
}
|
||||
};
|
||||
|
||||
public FilteringIterator(@NotNull Iterator<Dom> baseIterator, @NotNull Condition<Dom> filter) {
|
||||
public FilteringIterator(@NotNull Iterator<Dom> baseIterator, @NotNull Condition<? super Dom> filter) {
|
||||
myBaseIterator = baseIterator;
|
||||
myFilter = filter;
|
||||
}
|
||||
@@ -103,7 +102,7 @@ public class FilteringIterator<Dom, E extends Dom> implements Iterator<E> {
|
||||
return create(iterator, NOT_NULL);
|
||||
}
|
||||
|
||||
public static <Dom, T extends Dom> Iterator<T> create(Iterator<Dom> iterator, Condition<Dom> condition) {
|
||||
public static <Dom, T extends Dom> Iterator<T> create(Iterator<Dom> iterator, Condition<? super Dom> condition) {
|
||||
return new FilteringIterator<Dom, T>(iterator, condition);
|
||||
}
|
||||
|
||||
@@ -119,7 +118,7 @@ public class FilteringIterator<Dom, E extends Dom> implements Iterator<E> {
|
||||
return create((Iterator<T>)iterator, instanceOf(aClass));
|
||||
}
|
||||
|
||||
public static class InstanceOf<T> implements Condition {
|
||||
public static class InstanceOf<T> implements Condition<Object> {
|
||||
private final Class<T> myInstancesClass;
|
||||
|
||||
public InstanceOf(Class<T> instancesClass) {
|
||||
@@ -130,13 +129,5 @@ public class FilteringIterator<Dom, E extends Dom> implements Iterator<E> {
|
||||
public boolean value(Object object) {
|
||||
return myInstancesClass.isInstance(object);
|
||||
}
|
||||
|
||||
public boolean isClassAcceptable(Class hintClass) {
|
||||
return ReflectionUtil.isAssignable(myInstancesClass, hintClass);
|
||||
}
|
||||
|
||||
public T cast(Object object) {
|
||||
return (T)object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ public interface InternalIterator<T>{
|
||||
}
|
||||
|
||||
class Filtering<T> implements InternalIterator<T> {
|
||||
private final Condition<T> myFilter;
|
||||
private final Condition<? super T> myFilter;
|
||||
private final InternalIterator<T> myIterator;
|
||||
|
||||
public Filtering(InternalIterator<T> iterator, Condition<T> filter) {
|
||||
public Filtering(InternalIterator<T> iterator, Condition<? super T> filter) {
|
||||
myIterator = iterator;
|
||||
myFilter = filter;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
@@ -60,12 +61,16 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
|
||||
XValueTextRendererImpl renderer = new XValueTextRendererImpl(text);
|
||||
final XValuePresentation presentation = value.getValuePresentation();
|
||||
if (presentation == null) continue;
|
||||
if (presentation instanceof XValueCompactPresentation) {
|
||||
((XValueCompactPresentation)presentation).renderValue(renderer, value);
|
||||
} else {
|
||||
presentation.renderValue(renderer);
|
||||
try {
|
||||
if (presentation instanceof XValueCompactPresentation) {
|
||||
((XValueCompactPresentation)presentation).renderValue(renderer, value);
|
||||
} else {
|
||||
presentation.renderValue(renderer);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
final Color color = new JBColor(new Color(61, 128, 101), new Color(61, 128, 101));
|
||||
final Color color = getForeground();
|
||||
final String name = value.getName();
|
||||
result.add(new LineExtensionInfo(" " + name + ": ", color, null, null, Font.PLAIN));
|
||||
|
||||
@@ -86,9 +91,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
|
||||
result.add(new LineExtensionInfo(s, color, null, null, Font.PLAIN));
|
||||
}
|
||||
} else {
|
||||
for (String s : text.getTexts()) {
|
||||
result.add(new LineExtensionInfo(s, new JBColor(new Color(202, 128, 33), new Color(116, 114, 4)), null, null, Font.BOLD));
|
||||
}
|
||||
variableValue.produceChangedParts(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -98,6 +101,14 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JBColor getForeground() {
|
||||
return new JBColor(new Color(61, 128, 101), new Color(61, 128, 101));
|
||||
}
|
||||
|
||||
public static JBColor getChangedForeground() {
|
||||
return new JBColor(new Color(202, 128, 33), new Color(161, 131, 10));
|
||||
}
|
||||
|
||||
static class Variable {
|
||||
private int lineNumber;
|
||||
private String name;
|
||||
@@ -142,5 +153,35 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
|
||||
public boolean isChanged() {
|
||||
return old != null && !StringUtil.equals(actual, old);
|
||||
}
|
||||
|
||||
public void produceChangedParts(List<LineExtensionInfo> result) {
|
||||
if (isArray(actual) && isArray(old)) {
|
||||
List<String> actualParts = getArrayParts(actual);
|
||||
List<String> oldParts = getArrayParts(old);
|
||||
result.add(new LineExtensionInfo("{", getForeground(), null, null, Font.PLAIN));
|
||||
for (int i = 0; i < actualParts.size(); i++) {
|
||||
if (i < oldParts.size() && StringUtil.equals(actualParts.get(i), oldParts.get(i))) {
|
||||
result.add(new LineExtensionInfo(actualParts.get(i), getForeground(), null, null, Font.PLAIN));
|
||||
} else {
|
||||
result.add(new LineExtensionInfo(actualParts.get(i), getChangedForeground(), null, null, Font.BOLD));
|
||||
}
|
||||
if (i != actualParts.size() - 1) {
|
||||
result.add(new LineExtensionInfo(", ", getForeground(), null, null, Font.PLAIN));
|
||||
}
|
||||
}
|
||||
result.add(new LineExtensionInfo("}", getForeground(), null, null, Font.PLAIN));
|
||||
return;
|
||||
}
|
||||
|
||||
result.add(new LineExtensionInfo(actual, getChangedForeground(), null, null, Font.BOLD));
|
||||
}
|
||||
|
||||
private static boolean isArray(String s) {
|
||||
return s != null && s.startsWith("{") && s.endsWith("}");
|
||||
}
|
||||
|
||||
private static List<String> getArrayParts(String array) {
|
||||
return StringUtil.split(array.substring(1, array.length() - 1), ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.intellij.lang.properties;
|
||||
|
||||
import com.intellij.lang.properties.CustomResourceBundle;
|
||||
import com.intellij.lang.properties.PropertiesImplUtil;
|
||||
import com.intellij.lang.properties.psi.PropertiesFile;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.*;
|
||||
@@ -39,7 +37,10 @@ import java.util.regex.Matcher;
|
||||
*/
|
||||
@State(
|
||||
name = "ResourceBundleManager",
|
||||
storages = {@Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/resourceBundles.xml")})
|
||||
storages = {
|
||||
@Storage(file = StoragePathMacros.PROJECT_FILE),
|
||||
@Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/resourceBundles.xml", scheme = StorageScheme.DIRECTORY_BASED)
|
||||
})
|
||||
public class ResourceBundleManager implements PersistentStateComponent<ResourceBundleManagerState> {
|
||||
private final static Logger LOG = Logger.getInstance(ResourceBundleManager.class);
|
||||
private final static Locale DEFAULT_LOCALE = new Locale("", "", "");
|
||||
|
||||
@@ -198,7 +198,7 @@ public layoutEducational(String classesPath, Set usedJars) {
|
||||
|
||||
buildNSIS([paths.distAll, paths.distWin],
|
||||
"$pythonEduHome/build/strings.nsi", "$pythonEduHome/build/paths.nsi",
|
||||
"pycharmPE-", false, true, ".py", system_selector)
|
||||
"pycharmEDU-", false, true, ".py", system_selector)
|
||||
|
||||
String tarRoot = isEap() ? "pycharm-edu-$buildNumber" : "pycharm-edu-${p("component.version.major")}.${p("component.version.minor")}"
|
||||
buildTarGz(tarRoot, "$paths.artifacts/pycharm${buildName}.tar", [paths.distAll, paths.distUnix])
|
||||
|
||||
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
@@ -4,7 +4,7 @@
|
||||
!define PRODUCT_EXE_FILE "pycharm.exe"
|
||||
!define PRODUCT_ICON_FILE "PC_instCom.ico"
|
||||
!define PRODUCT_UNINST_ICON_FILE "PC_uninstCom.ico"
|
||||
!define PRODUCT_LOGO_FILE "logo.bmp"
|
||||
!define PRODUCT_LOGO_FILE "edulogo.bmp"
|
||||
!define PRODUCT_HEADER_FILE "headerlogo.bmp"
|
||||
|
||||
; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered PyCharm build has been installed
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -16,18 +16,19 @@
|
||||
package com.intellij.lang.xml;
|
||||
|
||||
import com.intellij.codeInsight.unwrap.Unwrapper;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.xml.XmlChildRole;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.xml.XmlBundle;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
|
||||
import com.intellij.psi.xml.XmlChildRole;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.xml.XmlBundle;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class XmlEnclosingTagUnwrapper implements Unwrapper {
|
||||
@Override
|
||||
@@ -45,23 +46,34 @@ public class XmlEnclosingTagUnwrapper implements Unwrapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement collectAffectedElements(PsiElement e, List<PsiElement> toExtract) {
|
||||
return e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PsiElement> unwrap(Editor editor, PsiElement element) throws IncorrectOperationException {
|
||||
public PsiElement collectAffectedElements(PsiElement element, List<PsiElement> toExtract) {
|
||||
final TextRange range = element.getTextRange();
|
||||
final ASTNode startTagNameEnd = XmlChildRole.START_TAG_END_FINDER.findChild(element.getNode());
|
||||
final ASTNode endTagNameStart = XmlChildRole.CLOSING_TAG_START_FINDER.findChild(element.getNode());
|
||||
|
||||
if (endTagNameStart != null) {
|
||||
editor.getDocument().replaceString(endTagNameStart.getTextRange().getStartOffset(), range.getEndOffset(), "");
|
||||
editor.getDocument().replaceString(range.getStartOffset(), startTagNameEnd.getTextRange().getEndOffset(), "");
|
||||
int start = startTagNameEnd != null ? startTagNameEnd.getTextRange().getEndOffset() : range.getStartOffset();
|
||||
int end = endTagNameStart != null ? endTagNameStart.getTextRange().getStartOffset() : range.getEndOffset();
|
||||
|
||||
for (PsiElement child : element.getChildren()) {
|
||||
final TextRange childRange = child.getTextRange();
|
||||
if (childRange.getStartOffset() >= start && childRange.getEndOffset() <= end) {
|
||||
toExtract.add(child);
|
||||
}
|
||||
}
|
||||
else {
|
||||
editor.getDocument().replaceString(range.getStartOffset(), range.getEndOffset(), "");
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PsiElement> unwrap(Editor editor, PsiElement element) throws IncorrectOperationException {
|
||||
final ArrayList<PsiElement> toExtract = new ArrayList<PsiElement>();
|
||||
collectAffectedElements(element, toExtract);
|
||||
for (int i = 0; i < toExtract.size(); i++) {
|
||||
PsiElement psiElement = toExtract.get(i);
|
||||
psiElement = element.getParent().addBefore(psiElement, element);
|
||||
CodeEditUtil.markToReformat(psiElement.getNode(), true);
|
||||
toExtract.set(i, psiElement);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
element.delete();
|
||||
return toExtract;
|
||||
}
|
||||
}
|
||||
|
||||