Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2014-08-21 14:09:35 +04:00
50 changed files with 837 additions and 647 deletions
@@ -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;
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

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("<", "&lt;").replaceAll(">", "&gt;");
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 == '<' ? "&lt;" : "&gt;");
}
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("", "", "");
+1 -1
View File
@@ -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

+1 -1
View File
@@ -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;
}
}