diff --git a/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java b/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java index 45595b7c0d3b..43d5640de6bf 100644 --- a/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java +++ b/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java @@ -217,7 +217,7 @@ public class GlobalSearchScopesCore { myDirectory = psiDirectory.getVirtualFile(); } - private DirectoryScope(@NotNull Project project, @NotNull VirtualFile directory, final boolean withSubdirectories) { + public DirectoryScope(@NotNull Project project, @NotNull VirtualFile directory, final boolean withSubdirectories) { super(project); myWithSubdirectories = withSubdirectories; myDirectory = directory; diff --git a/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java b/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java index d4ff908bfa09..7bade6c2fe10 100644 --- a/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java +++ b/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java @@ -121,6 +121,7 @@ public class PsiInvalidElementAccessException extends RuntimeException implement @Nullable Object trace) { String reason = "Element: " + element.getClass(); if (!recursiveInvocation) { + reason += " #" + element.getLanguage() + " "; String traceText = !isTrackingInvalidation() ? "disabled" : trace != null ? "see attachment" : "no info"; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 68aa3a3cbdf1..f8a2dba4874d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -488,9 +488,25 @@ public class CodeCompletionHandlerBase { if (context.shouldAddCompletionChar()) { WriteAction.run(() -> addCompletionChar(context, item, editor, completionChar)); } + checkPsiTextConcistency(indicator); + return context; } + private static void checkPsiTextConcistency(CompletionProcessEx indicator) { + PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(InjectedLanguageUtil.getTopLevelEditor(indicator.getEditor()), indicator.getProject()); + if (psiFile != null) { + if (Registry.is("ide.check.stub.text.consistency") || + ApplicationManager.getApplication().isUnitTestMode() && !ApplicationInfoImpl.isInStressTest()) { + StubTextInconsistencyException.checkStubTextConsistency(psiFile); + if (PsiDocumentManager.getInstance(psiFile.getProject()).hasUncommitedDocuments()) { + PsiDocumentManager.getInstance(psiFile.getProject()).commitAllDocuments(); + StubTextInconsistencyException.checkStubTextConsistency(psiFile); + } + } + } + } + public static void afterItemInsertion(final CompletionProgressIndicator indicator, final Runnable laterRunnable) { if (laterRunnable != null) { ActionTracker tracker = new ActionTracker(indicator.getEditor(), indicator); @@ -551,13 +567,6 @@ public class CodeCompletionHandlerBase { context.stopWatching(); } - if (psiFile.isValid()) { - if (Registry.is("ide.check.stub.text.consistency") || - ApplicationManager.getApplication().isUnitTestMode() && !ApplicationInfoImpl.isInStressTest()) { - StubTextInconsistencyException.checkStubTextConsistency(psiFile); - } - } - EditorModificationUtil.scrollToCaret(editor); }); if (lookup != null) { diff --git a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java index 3bed6e731870..6592b622856a 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2012 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.execution.ui; import com.intellij.execution.CommonProgramRunConfigurationParameters; @@ -95,23 +81,8 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc ExecutionBundle.message("run.configuration.program.parameters")); ExpandableTextField expandableTextField = (ExpandableTextField)myProgramParametersComponent.getComponent().getTextField(); if (Registry.is("allow.macros.for.run.configurations")) { - expandableTextField.addExtension(new ExtendableTextComponent.Extension() { - @Override - public Icon getIcon(boolean hovered) { - return AllIcons.General.Add; - } - - @Override - public String getTooltip() { - return "Insert Macros"; - } - - @Override - public Runnable getActionOnClick() { - return () -> MacrosDialog.show(expandableTextField, - macro -> !(macro instanceof PromptingMacro) && !(macro instanceof EditorMacro)); - } - }); + expandableTextField.addExtension(ExtendableTextComponent.Extension.create(AllIcons.General.Add, "Insert Macros", () + -> MacrosDialog.show(expandableTextField, macro -> !(macro instanceof PromptingMacro) && !(macro instanceof EditorMacro)))); } FileChooserDescriptor fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); diff --git a/platform/platform-api/src/com/intellij/ide/RemoteDesktopService.java b/platform/platform-api/src/com/intellij/ide/RemoteDesktopService.java index 8f81602139ca..bec931ef6a9b 100644 --- a/platform/platform-api/src/com/intellij/ide/RemoteDesktopService.java +++ b/platform/platform-api/src/com/intellij/ide/RemoteDesktopService.java @@ -1,6 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; public abstract class RemoteDesktopService { @@ -9,7 +10,7 @@ public abstract class RemoteDesktopService { } public static boolean isRemoteSession() { - return getInstance().isRemoteDesktopConnected(); + return ApplicationManager.getApplication() != null && getInstance().isRemoteDesktopConnected(); } public abstract boolean isRemoteDesktopConnected(); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java b/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java index 5aa601f03d0b..e5fe4ed32c8d 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java @@ -52,31 +52,14 @@ public class ComponentWithBrowseButton extends JPanel i setFocusable(false); boolean inlineBrowseButton = myComponent instanceof ExtendableTextComponent && Experiments.isFeatureEnabled("inline.browse.button"); if (inlineBrowseButton) { - ExtendableTextComponent.Extension action = new ExtendableTextComponent.Extension() { - @Override - public Icon getIcon(boolean hovered) { - return hovered ? AllIcons.General.OpenDiskHover : AllIcons.General.OpenDisk; - } - - @Override - public String getTooltip() { - return UIBundle.message("component.with.browse.button.browse.button.tooltip.text"); - } - - @Override - public Runnable getActionOnClick() { - return () -> { - for (ActionListener listener : myBrowseButton.getActionListeners()) { - listener.actionPerformed(new ActionEvent(myComponent, ActionEvent.ACTION_PERFORMED, "action")); - } - }; - } - }; - ((ExtendableTextComponent)myComponent).addExtension(action); + ((ExtendableTextComponent)myComponent).addExtension(ExtendableTextComponent.Extension.create( + AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, + UIBundle.message("component.with.browse.button.browse.button.tooltip.text"), + this::notifyActionListeners)); new DumbAwareAction() { @Override public void actionPerformed(AnActionEvent e) { - action.getActionOnClick().run(); + notifyActionListeners(); } }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK)), myComponent); } @@ -101,6 +84,11 @@ public class ComponentWithBrowseButton extends JPanel i } } + private void notifyActionListeners() { + ActionEvent event = new ActionEvent(myComponent, ActionEvent.ACTION_PERFORMED, "action"); + for (ActionListener listener: myBrowseButton.getActionListeners()) listener.actionPerformed(event); + } + @NotNull public final Comp getChildComponent() { return myComponent; diff --git a/platform/platform-api/src/com/intellij/ui/AbstractFieldPanel.java b/platform/platform-api/src/com/intellij/ui/AbstractFieldPanel.java index acd2bd9df3f7..13fad343265c 100644 --- a/platform/platform-api/src/com/intellij/ui/AbstractFieldPanel.java +++ b/platform/platform-api/src/com/intellij/ui/AbstractFieldPanel.java @@ -111,27 +111,14 @@ public abstract class AbstractFieldPanel extends JPanel { if (myBrowseButtonActionListener != null) { if (Experiments.isFeatureEnabled("inline.browse.button") && myComponent instanceof ExtendableTextComponent) { - ExtendableTextComponent.Extension action = new ExtendableTextComponent.Extension() { - @Override - public Icon getIcon(boolean hovered) { - return hovered ? AllIcons.General.OpenDiskHover : AllIcons.General.OpenDisk; - } - - @Override - public String getTooltip() { - return UIBundle.message("component.with.browse.button.browse.button.tooltip.text"); - } - - @Override - public Runnable getActionOnClick() { - return () -> myBrowseButtonActionListener.actionPerformed(new ActionEvent(myComponent, ActionEvent.ACTION_PERFORMED, "action")); - } - }; - ((ExtendableTextComponent)myComponent).addExtension(action); + ((ExtendableTextComponent)myComponent).addExtension(ExtendableTextComponent.Extension.create( + AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, + UIBundle.message("component.with.browse.button.browse.button.tooltip.text"), + this::notifyActionListener)); new DumbAwareAction() { @Override public void actionPerformed(AnActionEvent e) { - action.getActionOnClick().run(); + notifyActionListener(); } }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK)), myComponent); @@ -164,6 +151,11 @@ public abstract class AbstractFieldPanel extends JPanel { } } + private void notifyActionListener() { + ActionEvent event = new ActionEvent(myComponent, ActionEvent.ACTION_PERFORMED, "action"); + if (myBrowseButtonActionListener != null) myBrowseButtonActionListener.actionPerformed(event); + } + public void setBrowseButtonActionListener(ActionListener browseButtonActionListener) { myBrowseButtonActionListener = browseButtonActionListener; } diff --git a/platform/platform-api/src/com/intellij/ui/CellRendererPanel.java b/platform/platform-api/src/com/intellij/ui/CellRendererPanel.java index fc75ec970fad..554a43cac878 100644 --- a/platform/platform-api/src/com/intellij/ui/CellRendererPanel.java +++ b/platform/platform-api/src/com/intellij/ui/CellRendererPanel.java @@ -74,21 +74,17 @@ public class CellRendererPanel extends JPanel { if (count == 1) { Rectangle bounds = new Rectangle(getWidth(), getHeight()); JBInsets.removeFrom(bounds, getInsets()); - Component child = getComponent(0); - child.setBounds(bounds); - if (child instanceof CellRendererPanel) { - ((CellRendererPanel)child).invalidateLayout(); - child.doLayout(); - } + JComponent child = (JComponent)getComponent(0); + reshapeImpl(child, bounds.x, bounds.y, bounds.width, bounds.height); + invalidateLayout(child); + child.doLayout(); } else { - invalidateLayout(); + invalidateLayout(this); super.doLayout(); for (int i = 0; i < count; i++) { Component c = getComponent(i); - if (c instanceof CellRendererPanel) { - c.doLayout(); - } + c.doLayout(); } } } @@ -108,10 +104,14 @@ public class CellRendererPanel extends JPanel { @Override public void reshape(int x, int y, int w, int h) { + reshapeImpl(this, x, y, w, h); + } + + static void reshapeImpl(JComponent component, int x, int y, int w, int h) { // suppress per-cell "moved" and "resized" events on paint // see Component#setBounds, Component#notifyNewBounds - AWTAccessor.getComponentAccessor().setLocation(this, x, y); - AWTAccessor.getComponentAccessor().setSize(this, w, h); + AWTAccessor.getComponentAccessor().setLocation(component, x, y); + AWTAccessor.getComponentAccessor().setSize(component, w, h); } public void invalidate() { @@ -121,10 +121,10 @@ public class CellRendererPanel extends JPanel { super.invalidate(); } - private void invalidateLayout() { - LayoutManager layout = getLayout(); + private static void invalidateLayout(JComponent component) { + LayoutManager layout = component.getLayout(); if (layout instanceof LayoutManager2) { - ((LayoutManager2)layout).invalidateLayout(this); + ((LayoutManager2)layout).invalidateLayout(component); } } diff --git a/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableSupport.java b/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableSupport.java new file mode 100644 index 000000000000..f726b44c11eb --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableSupport.java @@ -0,0 +1,286 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ui.components.fields; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Pair; +import com.intellij.ui.Expandable; +import com.intellij.ui.ScreenUtil; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.JBScrollBar; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.components.fields.ExtendableTextComponent.Extension; +import com.intellij.util.Function; +import com.intellij.util.ui.JBInsets; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.ApiStatus.Experimental; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.event.AncestorListener; +import javax.swing.text.JTextComponent; +import java.awt.*; +import java.awt.event.ComponentListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import static com.intellij.openapi.keymap.KeymapUtil.createTooltipText; +import static java.awt.event.InputEvent.CTRL_MASK; +import static java.beans.EventHandler.create; +import static java.util.Collections.singletonList; +import static javax.swing.KeyStroke.getKeyStroke; +import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS; + +@Experimental +public abstract class ExpandableSupport implements Expandable { + private static final int MINIMAL_WIDTH = 50; + private final Source source; + private final Function onShow; + private final Function onHide; + private JBPopup popup; + private String title; + private String comment; + + public ExpandableSupport(@NotNull Source source, Function onShow, Function onHide) { + this.source = source; + this.onShow = onShow != null ? onShow : Function.ID; + this.onHide = onHide != null ? onHide : Function.ID; + source.putClientProperty(Expandable.class, this); + source.addAncestorListener(create(AncestorListener.class, this, "collapse")); + source.addComponentListener(create(ComponentListener.class, this, "collapse")); + } + + protected abstract boolean isEditable(@NotNull Source source); + + protected abstract int getCaretPosition(@NotNull Source source); + + protected abstract String getText(@NotNull Source source); + + protected abstract void setText(@NotNull Source source, String text, int caret); + + protected abstract Insets getInsets(@NotNull Source source); + + public final String getTitle() { + return title; + } + + public final void setTitle(String title) { + this.title = title; + } + + public final String getComment() { + return comment; + } + + public final void setComment(String comment) { + this.comment = comment; + } + + @Override + public final boolean isExpanded() { + return popup != null; + } + + @Override + public final void collapse() { + if (popup != null) popup.cancel(); + } + + @Override + public final void expand() { + if (popup != null || !source.isEnabled()) return; + + Font font = source.getFont(); + FontMetrics metrics = font == null ? null : source.getFontMetrics(font); + int height = metrics == null ? 16 : metrics.getHeight(); + Dimension size = new Dimension(height * 32, height * 16); + + JTextArea area = new JTextArea(onShow.fun(getText(source))); + area.putClientProperty(Expandable.class, this); + area.setEditable(isEditable(source)); + area.setBackground(source.getBackground()); + area.setForeground(source.getForeground()); + area.setFont(font); + area.setWrapStyleWord(true); + area.setLineWrap(true); + setCaretPositionSafely(area, getCaretPosition(source)); + UIUtil.addUndoRedoActions(area); + + JBScrollPane pane = new JBScrollPane(area); + addExtension(pane, createCollapseExtension(this)); + + Insets insets = getInsets(source); + //TODO: support scroll pane + + JBInsets.addTo(size, insets); + JBInsets.addTo(size, pane.getInsets()); + if (size.width - MINIMAL_WIDTH < source.getWidth()) size.width = source.getWidth(); + + Point location = new Point(0, 0); + SwingUtilities.convertPointToScreen(location, source); + Rectangle screen = ScreenUtil.getScreenRectangle(source); + int bottom = screen.y - location.y + screen.height; + if (bottom < size.height) { + int top = location.y - screen.y + source.getHeight(); + if (top < bottom) { + size.height = bottom; + } + else { + if (size.height > top) size.height = top; + location.y -= size.height - source.getHeight(); + } + } + pane.setPreferredSize(size); + pane.setViewportBorder(BorderFactory.createEmptyBorder(insets.top, insets.left, insets.bottom, insets.right)); + + popup = JBPopupFactory + .getInstance() + .createComponentPopupBuilder(pane, area) + .setMayBeParent(true) // this creates a popup as a dialog with alwaysOnTop=false + .setFocusable(true) + .setRequestFocus(true) + .setTitle(title) + .setAdText(comment) + .setLocateByContent(true) + .setCancelOnWindowDeactivation(false) + .setKeyboardActions(singletonList(Pair.create(event -> { + collapse(); + Window window = UIUtil.getWindow(source); + if (window != null) { + window.dispatchEvent( + new KeyEvent(source, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), CTRL_MASK, KeyEvent.VK_ENTER, '\r')); + } + }, getKeyStroke(KeyEvent.VK_ENTER, CTRL_MASK)))) + .setCancelCallback(() -> { + try { + if (isEditable(source)) { + setText(source, onHide.fun(area.getText()), area.getCaretPosition()); + } + popup = null; + return true; + } + catch (Exception ignore) { + return false; + } + }).createPopup(); + popup.show(new RelativePoint(location)); + } + + private static void setCaretPositionSafely(JTextComponent component, int caret) { + try { + component.setCaretPosition(caret); + } + catch (Exception ignored) { + } + } + + public static Extension createCollapseExtension(@NotNull Expandable expandable) { + return Extension.create(AllIcons.General.CollapseComponent, + AllIcons.General.CollapseComponentHover, + createTooltipText("Collapse", "CollapseExpandableComponent"), + expandable::collapse); + } + + public static Extension createExpandExtension(@NotNull Expandable expandable) { + return Extension.create(AllIcons.General.ExpandComponent, + AllIcons.General.ExpandComponentHover, + createTooltipText("Expand", "ExpandExpandableComponent"), + expandable::collapse); + } + + private static void addExtension(@NotNull JScrollPane pane, @NotNull Extension extension) { + pane.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS); + JScrollBar vsb = pane.getVerticalScrollBar(); + if (vsb != null) { + vsb.add(JBScrollBar.LEADING, new JLabel(extension.getIcon(false)) {{ + setToolTipText(extension.getTooltip()); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + setBorder(JBUI.Borders.empty(5, 0, 5, 5)); + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent event) { + setIcon(extension.getIcon(true)); + } + + @Override + public void mouseExited(MouseEvent event) { + setIcon(extension.getIcon(false)); + } + + @Override + public void mousePressed(MouseEvent event) { + Runnable action = extension.getActionOnClick(); + if (action != null) action.run(); + } + }); + }}); + JViewport viewport = pane.getViewport(); + if (viewport != null) { + Component view = viewport.getView(); + if (view != null) vsb.setBackground(view.getBackground()); + } + } + } + + + static class TextComponent extends ExpandableSupport { + TextComponent(@NotNull Source source, Function onShow, Function onHide) { + super(source, onShow, onHide); + } + + @Override + protected boolean isEditable(@NotNull Source source) { + return source.isEditable(); + } + + @Override + protected int getCaretPosition(@NotNull Source source) { + return source.getCaretPosition(); + } + + @Override + protected String getText(@NotNull Source source) { + return source.getText(); + } + + @Override + protected void setText(@NotNull Source source, String text, int caret) { + source.setText(text); + setCaretPositionSafely(source, caret); + } + + @Override + protected Insets getInsets(@NotNull Source source) { + Insets insets = source.getInsets(); + Insets margin = source.getMargin(); + if (margin != null) { + insets.top += margin.top; + insets.left += margin.left; + insets.right += margin.right; + insets.bottom += margin.bottom; + } + return insets; + } + } + + static final class Area extends TextComponent { + Area(@NotNull JTextArea area, Function onShow, Function onHide) { + super(area, onShow, onHide); + } + + @Override + protected void setText(@NotNull JTextArea source, String text, int caret) { + super.setText(source, text, 0); + } + + @Override + protected Insets getInsets(@NotNull JTextArea source) { + //noinspection UnnecessaryLocalVariable //TODO: support scroll pane + Insets insets = super.getInsets(source); + return insets; + } + } +} diff --git a/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableTextField.java b/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableTextField.java index c8c130aed097..f0e0abb2701a 100644 --- a/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableTextField.java +++ b/platform/platform-api/src/com/intellij/ui/components/fields/ExpandableTextField.java @@ -1,50 +1,22 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ui.components.fields; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.Expandable; -import com.intellij.ui.ScreenUtil; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.components.JBScrollBar; -import com.intellij.ui.components.JBScrollPane; import com.intellij.util.Function; import com.intellij.util.execution.ParametersListUtil; -import com.intellij.util.ui.JBInsets; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import javax.swing.event.AncestorListener; -import javax.swing.text.JTextComponent; -import java.awt.*; -import java.awt.event.ComponentListener; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.Arrays; import java.util.List; -import static com.intellij.openapi.keymap.KeymapUtil.createTooltipText; -import static java.awt.event.InputEvent.CTRL_MASK; -import static java.beans.EventHandler.create; +import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static javax.swing.KeyStroke.getKeyStroke; -import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS; /** * @author Sergey Malenkov */ public class ExpandableTextField extends ExtendableTextField implements Expandable { - private static final int MINIMAL_WIDTH = 50; - private final Function parser; - private final Function joiner; - private JBPopup popup; - private String title; + private final ExpandableSupport support; /** * Creates an expandable text field with the default line parser/joiner, @@ -60,39 +32,23 @@ public class ExpandableTextField extends ExtendableTextField implements Expandab * @see ParametersListUtil */ public ExpandableTextField(@NotNull Function> parser, @NotNull Function, String> joiner) { - this.parser = text -> StringUtil.join(parser.fun(text), "\n"); - this.joiner = text -> joiner.fun(Arrays.asList(StringUtil.splitByLines(text))); - addAncestorListener(create(AncestorListener.class, this, "collapse")); - addComponentListener(create(ComponentListener.class, this, "collapse")); + Function onShow = text -> StringUtil.join(parser.fun(text), "\n"); + Function onHide = text -> joiner.fun(asList(StringUtil.splitByLines(text))); + support = new ExpandableSupport.TextComponent<>(this, onShow, onHide); putClientProperty("monospaced", true); setExtensions(createExtensions()); } protected List createExtensions() { - return singletonList(new ExtendableTextComponent.Extension() { - @Override - public Icon getIcon(boolean hovered) { - return hovered ? AllIcons.General.ExpandComponentHover : AllIcons.General.ExpandComponent; - } - - @Override - public Runnable getActionOnClick() { - return ExpandableTextField.this::expand; - } - - @Override - public String getTooltip() { - return createTooltipText("Expand", "ExpandExpandableComponent"); - } - }); + return singletonList(ExpandableSupport.createExpandExtension(support)); } public String getTitle() { - return title; + return support.getTitle(); } public void setTitle(String title) { - this.title = title; + support.setTitle(title); } @Override @@ -103,123 +59,16 @@ public class ExpandableTextField extends ExtendableTextField implements Expandab @Override public void collapse() { - if (popup != null) popup.cancel(); + support.collapse(); } @Override public boolean isExpanded() { - return popup != null; + return support.isExpanded(); } @Override public void expand() { - if (popup != null || !isEnabled()) return; - - Font font = getFont(); - FontMetrics metrics = font == null ? null : getFontMetrics(font); - int height = metrics == null ? 16 : metrics.getHeight(); - Dimension size = new Dimension(height * 32, height * 16); - - JTextArea area = new JTextArea(parser.fun(getText())); - area.setEditable(isEditable()); - area.setBackground(getBackground()); - area.setForeground(getForeground()); - area.setFont(font); - area.setWrapStyleWord(true); - area.setLineWrap(true); - area.putClientProperty(Expandable.class, this); - copyCaretPosition(this, area); - UIUtil.addUndoRedoActions(area); - - JBScrollPane pane = new JBScrollPane(area); - pane.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS); - pane.getVerticalScrollBar().setBackground(area.getBackground()); - pane.getVerticalScrollBar().add(JBScrollBar.LEADING, new JLabel(AllIcons.General.CollapseComponent) {{ - setToolTipText(createTooltipText("Collapse", "CollapseExpandableComponent")); - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - setBorder(JBUI.Borders.empty(5, 0, 5, 5)); - addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent event) { - setIcon(AllIcons.General.CollapseComponentHover); - } - - @Override - public void mouseExited(MouseEvent event) { - setIcon(AllIcons.General.CollapseComponent); - } - - @Override - public void mousePressed(MouseEvent event) { - collapse(); - } - }); - }}); - - Insets insets = getInsets(); - Insets margins = getMargin(); - - JBInsets.addTo(size, insets); - JBInsets.addTo(size, margins); - JBInsets.addTo(size, pane.getInsets()); - if (size.width - MINIMAL_WIDTH < getWidth()) size.width = getWidth(); - - Point location = new Point(0, 0); - SwingUtilities.convertPointToScreen(location, this); - Rectangle screen = ScreenUtil.getScreenRectangle(this); - int bottom = screen.y - location.y + screen.height; - if (bottom < size.height) { - int top = location.y - screen.y + getHeight(); - if (top < bottom) { - size.height = bottom; - } - else { - if (size.height > top) size.height = top; - location.y -= size.height - getHeight(); - } - } - pane.setPreferredSize(size); - pane.setViewportBorder(BorderFactory.createEmptyBorder(insets.top + margins.top, - insets.left + margins.left, - insets.bottom + margins.bottom, - insets.right + margins.right)); - - popup = JBPopupFactory.getInstance() - .createComponentPopupBuilder(pane, area) - .setMayBeParent(true) // this creates a popup as a dialog with alwaysOnTop=false - .setFocusable(true) - .setRequestFocus(true) - .setTitle(title) - .setLocateByContent(true) - .setCancelOnWindowDeactivation(false) - .setKeyboardActions(singletonList(Pair.create(event -> { - collapse(); - Window window = UIUtil.getWindow(this); - if (window != null) { - window.dispatchEvent(new KeyEvent(this, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), CTRL_MASK, KeyEvent.VK_ENTER, '\r')); - } - }, getKeyStroke(KeyEvent.VK_ENTER, CTRL_MASK)))) - .setCancelCallback(() -> { - try { - if (isEditable()) { - setText(joiner.fun(area.getText())); - copyCaretPosition(area, this); - } - popup = null; - return true; - } - catch (Exception ignore) { - return false; - } - }).createPopup(); - popup.show(new RelativePoint(location)); - } - - private static void copyCaretPosition(JTextComponent source, JTextComponent destination) { - try { - destination.setCaretPosition(source.getCaretPosition()); - } - catch (Exception ignored) { - } + support.expand(); } } diff --git a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextComponent.java b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextComponent.java index 6ce7f130a5e9..1fc86ae3a1fe 100644 --- a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextComponent.java +++ b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextComponent.java @@ -3,7 +3,7 @@ package com.intellij.ui.components.fields; import org.jetbrains.annotations.NotNull; -import javax.swing.*; +import javax.swing.Icon; import java.util.Collection; import java.util.List; @@ -58,5 +58,28 @@ public interface ExtendableTextComponent { default String getTooltip() { return null; } + + static Extension create(@NotNull Icon icon, String tooltip, Runnable action) { + return create(icon, icon, tooltip, action); + } + + static Extension create(@NotNull Icon defaultIcon, @NotNull Icon hoveredIcon, String tooltip, Runnable action) { + return new Extension() { + @Override + public Icon getIcon(boolean hovered) { + return hovered ? hoveredIcon : defaultIcon; + } + + @Override + public String getTooltip() { + return tooltip; + } + + @Override + public Runnable getActionOnClick() { + return action; + } + }; + } } } diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index 536be03308f9..e72cc0f2d89d 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -153,6 +153,7 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, EditorEx editor = (EditorEx)ObjectUtils.assertNotNull(field.getEditor()); editor.setRendererMode(true); + editor.getSettings().setAnimatedScrolling(false); editor.setColorsScheme(editor.createBoundColorSchemeDelegate(null)); editor.getSettings().setCaretRowShown(false); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java index 47cfbfe2535e..f7374756f9f3 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java @@ -3,6 +3,7 @@ package com.intellij.structuralsearch; import com.intellij.lang.Language; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.psi.search.SearchScope; import com.intellij.structuralsearch.impl.matcher.compiler.StringToConstraintsTransformer; @@ -23,8 +24,9 @@ public class MatchOptions implements JDOMExternalizable { private boolean caseSensitiveMatch; private FileType myFileType; private Language myDialect; - private SearchScope scope; + private Scopes.Type scopeType; + private String scopeDescriptor; private String pattern; private String myPatternContext; @@ -36,6 +38,9 @@ public class MatchOptions implements JDOMExternalizable { @NonNls private static final String CONSTRAINT_TAG_NAME = "constraint"; @NonNls private static final String FILE_TYPE_ATTR_NAME = "type"; @NonNls private static final String DIALECT_ATTR_NAME = "dialect"; + @NonNls private static final String SCOPE_TYPE = "scope_type"; + @NonNls private static final String SCOPE_DESCRIPTOR = "scope_descriptor"; + @NonNls public static final String INSTANCE_MODIFIER_NAME = "Instance"; @NonNls public static final String MODIFIER_ANNOTATION_NAME = "Modifier"; @@ -56,6 +61,8 @@ public class MatchOptions implements JDOMExternalizable { myFileType = options.myFileType; myDialect = options.myDialect; scope = options.scope; + scopeType = options.scopeType; + scopeDescriptor = options.scopeDescriptor; pattern = options.pattern; myPatternContext = options.myPatternContext; } @@ -64,6 +71,12 @@ public class MatchOptions implements JDOMExternalizable { return new MatchOptions(this); } + public void initScope(Project project) { + if (scope == null && scopeType != null && scopeDescriptor != null) { + scope = Scopes.createScope(project, scopeDescriptor, scopeType); + } + } + public void addVariableConstraint(@NotNull MatchVariableConstraint constraint) { variableConstraints.put(constraint.getName(), constraint); } @@ -153,8 +166,6 @@ public class MatchOptions implements JDOMExternalizable { element.setAttribute(RECURSIVE_ATTRIBUTE_NAME,String.valueOf(recursiveSearch)); element.setAttribute(CASESENSITIVE_ATTRIBUTE_NAME,String.valueOf(caseSensitiveMatch)); - //@TODO serialize scope! - if (myFileType != null) { element.setAttribute(FILE_TYPE_ATTR_NAME, myFileType.getName()); } @@ -163,6 +174,10 @@ public class MatchOptions implements JDOMExternalizable { element.setAttribute(DIALECT_ATTR_NAME, myDialect.getID()); } + if (scope != null) { + element.setAttribute(SCOPE_TYPE, Scopes.getType(scope).toString()).setAttribute(SCOPE_DESCRIPTOR, Scopes.getDescriptor(scope)); + } + for (final MatchVariableConstraint matchVariableConstraint : variableConstraints.values()) { if (matchVariableConstraint.isArtificial()) continue; final Element infoElement = new Element(CONSTRAINT_TAG_NAME); @@ -208,7 +223,14 @@ public class MatchOptions implements JDOMExternalizable { myDialect = Language.findLanguageByID(attr.getValue()); } - // @TODO deserialize scope + attr = element.getAttribute(SCOPE_TYPE); + if (attr != null) { + scopeType = Scopes.Type.valueOf(attr.getValue()); + } + attr = element.getAttribute(SCOPE_DESCRIPTOR); + if (attr != null) { + scopeDescriptor = attr.getValue(); + } for (final Element element1 : element.getChildren(CONSTRAINT_TAG_NAME)) { final MatchVariableConstraint constraint = new MatchVariableConstraint(); @@ -236,11 +258,9 @@ public class MatchOptions implements JDOMExternalizable { final MatchOptions matchOptions = (MatchOptions)o; if (caseSensitiveMatch != matchOptions.caseSensitiveMatch) return false; - //if (enableAutoIdentifySearchTarget != matchOptions.enableAutoIdentifySearchTarget) return false; if (looseMatching != matchOptions.looseMatching) return false; if (recursiveSearch != matchOptions.recursiveSearch) return false; - // @TODO support scope - + if (scope != null ? !scope.equals(matchOptions.scope) : matchOptions.scope != null) return false; if (!pattern.equals(matchOptions.pattern)) return false; if (!variableConstraints.equals(matchOptions.variableConstraints)) return false; if (myFileType != matchOptions.myFileType) return false; @@ -254,9 +274,9 @@ public class MatchOptions implements JDOMExternalizable { int result = (looseMatching ? 1 : 0); result = 29 * result + (recursiveSearch ? 1 : 0); result = 29 * result + (caseSensitiveMatch ? 1 : 0); - // @TODO support scope result = 29 * result + pattern.hashCode(); result = 29 * result + variableConstraints.hashCode(); + if (scope != null) result = 29 * result + scope.hashCode(); if (myFileType != null) result = 29 * result + myFileType.hashCode(); if (myDialect != null) result = 29 * result + myDialect.hashCode(); return result; diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/Scopes.java b/platform/structuralsearch/source/com/intellij/structuralsearch/Scopes.java new file mode 100644 index 000000000000..69b7ed53b887 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/Scopes.java @@ -0,0 +1,92 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.structuralsearch; + +import com.intellij.ide.util.scopeChooser.ScopeChooserUtils; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.impl.scopes.ModuleWithDependenciesScope; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.GlobalSearchScopesCore; +import com.intellij.psi.search.ProjectScopeImpl; +import com.intellij.psi.search.SearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public final class Scopes { + + private Scopes() {} + + public static Type getType(@Nullable SearchScope scope) { + if (scope instanceof ProjectScopeImpl || scope == null) { + return Type.PROJECT; + } + else if (scope instanceof ModuleWithDependenciesScope) { + return Type.MODULE; + } + else if (scope instanceof GlobalSearchScopesCore.DirectoryScope) { + return Type.DIRECTORY; + } + else { + return Type.NAMED; + } + } + + public static String getDescriptor(SearchScope scope) { + if (scope instanceof ProjectScopeImpl || scope == null) { + return ""; + } + else if (scope instanceof ModuleWithDependenciesScope) { + return ((ModuleWithDependenciesScope)scope).getModule().getName(); + } + else if (scope instanceof GlobalSearchScopesCore.DirectoryScope) { + final GlobalSearchScopesCore.DirectoryScope directoryScope = (GlobalSearchScopesCore.DirectoryScope)scope; + final String url = directoryScope.getDirectory().getPresentableUrl(); + return directoryScope.isWithSubdirectories() ? "*" + url : url; + } + else { + return scope.getDisplayName(); + } + } + + public static SearchScope createScope(@NotNull Project project, @NotNull String descriptor, @NotNull Type scopeType) { + if (scopeType == Type.PROJECT) { + return GlobalSearchScope.projectScope(project); + } + else if (scopeType == Type.MODULE) { + final Module module = ModuleManager.getInstance(project).findModuleByName(descriptor); + if (module != null) { + return GlobalSearchScope.moduleScope(module); + } + } + else if (scopeType == Type.DIRECTORY) { + final boolean recursive = StringUtil.startsWithChar(descriptor, '*'); + if (recursive) { + descriptor = descriptor.substring(1); + } + final String path = FileUtil.toSystemIndependentName(descriptor.substring(1)); + final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path); + if (virtualFile == null) return null; + return new GlobalSearchScopesCore.DirectoryScope(project, virtualFile, recursive); + } + else if (scopeType == Type.NAMED) { + return ScopeChooserUtils.findScopeByName(project, descriptor); + } + assert false; + return null; + } + + public enum Type { + PROJECT, + MODULE, + DIRECTORY, + NAMED + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java index a035cdfd3ea2..aae12322a8db 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java @@ -51,6 +51,7 @@ public class ConfigurationManager implements PersistentStateComponent { configurations.clear(); historyConfigurations.clear(); readConfigurations(state, configurations, historyConfigurations); + historyConfigurations.forEach(c -> c.getMatchOptions().initScope(myProject)); } public void addHistoryConfiguration(Configuration configuration) { @@ -75,6 +76,7 @@ public class ConfigurationManager implements PersistentStateComponent { @NotNull Collection configurations, @NotNull Collection historyConfigurations) { for (final Configuration configuration : configurations) { + configuration.getMatchOptions().setScope(null); saveConfiguration(element, configuration); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/DirectoryComboBoxWithButtons.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/DirectoryComboBoxWithButtons.java index ffe1e2b73863..29a9009711f2 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/DirectoryComboBoxWithButtons.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/DirectoryComboBoxWithButtons.java @@ -7,24 +7,17 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.actionSystem.ToggleAction; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; -import com.intellij.openapi.ui.FixedSizeButton; -import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileProvider; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileSystem; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.util.ui.JBUI; +import com.intellij.ui.ComboboxWithBrowseButton; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,129 +26,87 @@ import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.List; +import java.util.function.BiConsumer; /** * @author Bas Leijdekkers */ public class DirectoryComboBoxWithButtons extends JPanel { - @NotNull private final Project myProject; - @NotNull private final ComboBox myDirectoryComboBox; + @NotNull private final ComboboxWithBrowseButton myDirectoryComboBox; private boolean myRecursive = true; + private BiConsumer myCallback; @SuppressWarnings("WeakerAccess") public DirectoryComboBoxWithButtons(@NotNull Project project) { super(new BorderLayout()); - myProject = project; - myDirectoryComboBox = new ComboBox<>(200); - myDirectoryComboBox.setEditable(true); + final ComboBox comboBox = new ComboBox<>(200); + myDirectoryComboBox = new ComboboxWithBrowseButton(comboBox); + myDirectoryComboBox.getComboBox().addItemListener(e -> myCallback.accept(getDirectory(), myRecursive)); + comboBox.setEditable(true); - FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); - Component editorComponent = myDirectoryComboBox.getEditor().getEditorComponent(); + final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); + final Component editorComponent = comboBox.getEditor().getEditorComponent(); if (editorComponent instanceof JTextField) { - JTextField field = (JTextField)editorComponent; + final JTextField field = (JTextField)editorComponent; field.setColumns(40); FileChooserFactory.getInstance().installFileCompletion(field, descriptor, true, null); } - myDirectoryComboBox.setMaximumRowCount(8); + comboBox.setMaximumRowCount(8); - FixedSizeButton mySelectDirectoryButton = new FixedSizeButton(myDirectoryComboBox); - TextFieldWithBrowseButton.MyDoClickAction.addTo(mySelectDirectoryButton, myDirectoryComboBox); - mySelectDirectoryButton.setMargin(JBUI.emptyInsets()); + myDirectoryComboBox.addBrowseFolderListener(project, descriptor); - mySelectDirectoryButton.addActionListener(__ -> { - FileChooser.chooseFiles(descriptor, myProject, null, null, - new FileChooser.FileChooserConsumer() { - @Override - public void consume(List files) { - ApplicationManager.getApplication().invokeLater(() -> { - IdeFocusManager.getInstance(myProject).requestFocus(myDirectoryComboBox.getEditor().getEditorComponent(), true); - myDirectoryComboBox.getEditor().setItem(files.get(0).getPresentableUrl()); - }); - } - - @Override - public void cancelled() { - ApplicationManager.getApplication().invokeLater(() -> { - IdeFocusManager.getInstance(myProject).requestFocus(myDirectoryComboBox.getEditor().getEditorComponent(), true); - }); - } - }); - }); - - RecursiveAction - recursiveDirectoryAction = new RecursiveAction(); - int mnemonicModifiers = SystemInfo.isMac ? InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK : InputEvent.ALT_DOWN_MASK; + final RecursiveAction recursiveDirectoryAction = new RecursiveAction(); + final int mnemonicModifiers = SystemInfo.isMac ? InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK : InputEvent.ALT_DOWN_MASK; recursiveDirectoryAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_Y, mnemonicModifiers)), myDirectoryComboBox); add(myDirectoryComboBox, BorderLayout.CENTER); - JPanel buttonsPanel = new JPanel(new GridLayout(1, 2)); - buttonsPanel.add(mySelectDirectoryButton); - buttonsPanel.add(FindPopupPanel.createToolbar(recursiveDirectoryAction).getComponent()); //check if toolbar updates the button with no delays - add(buttonsPanel, BorderLayout.EAST); + add(FindPopupPanel.createToolbar(recursiveDirectoryAction), BorderLayout.EAST); } - public void init(@Nullable String currentDirectory, @NotNull List recentDirectories) { - if (myDirectoryComboBox.getItemCount() > 0) { - myDirectoryComboBox.removeAllItems(); - } - if (currentDirectory != null && !currentDirectory.isEmpty()) { - recentDirectories.remove(currentDirectory); - myDirectoryComboBox.addItem(currentDirectory); - } + public void setCallback(BiConsumer callback) { + myCallback = callback; + } + + public void setRecentDirectories(@NotNull List recentDirectories) { + @SuppressWarnings("unchecked") final JComboBox comboBox = myDirectoryComboBox.getComboBox(); + comboBox.removeAllItems(); for (int i = recentDirectories.size() - 1; i >= 0; i--) { - myDirectoryComboBox.addItem(recentDirectories.get(i)); - } - if (myDirectoryComboBox.getItemCount() == 0) { - myDirectoryComboBox.addItem(""); + comboBox.addItem(recentDirectories.get(i)); } } - public void setCurrentDirectory(@NotNull VirtualFile directory) { - final String text = directory.getPresentableUrl(); - final int count = myDirectoryComboBox.getItemCount(); - for (int i = 0; i < count; i++) { - if (text.equals(myDirectoryComboBox.getItemAt(i))) { - myDirectoryComboBox.removeItemAt(i); - } - } - myDirectoryComboBox.setSelectedItem(text); + public void setDirectory(@NotNull VirtualFile directory) { + setDirectory(directory.getPresentableUrl()); + } + + private void setDirectory(String path) { + @SuppressWarnings("unchecked") final JComboBox comboBox = myDirectoryComboBox.getComboBox(); + comboBox.removeItem(path); + comboBox.insertItemAt(path, 0); } @Nullable public VirtualFile getDirectory() { - String directoryName = (String)myDirectoryComboBox.getSelectedItem(); + @SuppressWarnings("unchecked") final JComboBox comboBox = myDirectoryComboBox.getComboBox(); + final String directoryName = (String)comboBox.getSelectedItem(); if (StringUtil.isEmptyOrSpaces(directoryName)) { return null; } - String path = FileUtil.toSystemIndependentName(directoryName); - VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path); - if (virtualFile == null || !virtualFile.isDirectory()) { - virtualFile = null; - @SuppressWarnings("deprecation") VirtualFileSystem[] fileSystems = ApplicationManager.getApplication().getComponents(VirtualFileSystem.class); - for (VirtualFileSystem fs : fileSystems) { - if (fs instanceof LocalFileProvider) { - @SuppressWarnings("deprecation") VirtualFile file = ((LocalFileProvider)fs).findLocalVirtualFileByPath(path); - if (file != null && file.isDirectory()) { - if (file.getChildren().length > 0) { - virtualFile = file; - break; - } - if (virtualFile == null) { - virtualFile = file; - } - } - } - } - } - return virtualFile; + final String path = FileUtil.toSystemIndependentName(directoryName); + final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path); + return virtualFile == null || !virtualFile.isDirectory() ? null : virtualFile; } public boolean isRecursive() { return myRecursive; } + public void setRecursive(boolean recursive) { + myRecursive = recursive; + } + private class RecursiveAction extends ToggleAction { RecursiveAction() { super(FindBundle.message("find.scope.directory.recursive.checkbox"), "Recursively", AllIcons.Actions.ShowAsTree); @@ -168,7 +119,8 @@ public class DirectoryComboBoxWithButtons extends JPanel { @Override public void setSelected(AnActionEvent e, boolean state) { - myRecursive = true; + myRecursive = state; + myCallback.accept(getDirectory(), myRecursive); } } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/FilterPanel.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/FilterPanel.java index 921d23c91c67..7801df360adc 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/FilterPanel.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/FilterPanel.java @@ -4,7 +4,6 @@ package com.intellij.structuralsearch.plugin.ui; import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; @@ -12,16 +11,20 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileFactory; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.MatchVariableConstraint; +import com.intellij.structuralsearch.SSRBundle; +import com.intellij.structuralsearch.StructuralSearchProfile; +import com.intellij.structuralsearch.impl.matcher.CompiledPattern; import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.fields.IntegerField; import com.intellij.ui.table.JBTable; import com.intellij.ui.table.TableView; import com.intellij.util.SmartList; import com.intellij.util.ui.ColumnInfo; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.ListTableModel; import com.intellij.util.ui.table.JBListTable; import com.intellij.util.ui.table.JBTableRow; @@ -31,10 +34,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.table.JTableHeader; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Collections; import java.util.List; /** @@ -43,20 +46,30 @@ import java.util.List; public class FilterPanel { private final JPanel myFilterPanel; - private final JBListTable myFilterTable; - private final ListTableModel myTableModel; - @NotNull private final Project myProject; - private MatchVariableConstraint myConstraint; + final JBListTable myFilterTable; + final ListTableModel myTableModel; - public FilterPanel(@NotNull Project project, Disposable parent) { + @NotNull private final Project myProject; + private CompiledPattern myCompiledPattern; + MatchVariableConstraint myConstraint; + StructuralSearchProfile myProfile; + + final Header myHeader = new Header(); + private final TextFilter myTextFilter = new TextFilter(); + private final CountFilter myCountFilter = new CountFilter(); + private final TypeFilter myTypeFilter = new TypeFilter(); + private final ReferenceFilter myReferenceFilter = new ReferenceFilter(); + + public FilterPanel(@NotNull Project project, StructuralSearchProfile profile, Disposable parent) { myProject = project; - myTableModel = new ListTableModel<>(new ColumnInfo("") { + myProfile = profile; + myTableModel = new ListTableModel<>(new ColumnInfo[]{new ColumnInfo("") { @Nullable @Override public Filter valueOf(Filter s) { return s; } - }); + }}, new SmartList<>()); myFilterTable = new JBListTable(new TableView<>(myTableModel), parent) { @Override @@ -64,17 +77,18 @@ public class FilterPanel { return new JBTableRowRenderer() { @Override public JComponent getRowRendererComponent(JTable table, int row, boolean selected, boolean focused) { - return myTableModel.getRowValue(row).getRowRendererComponent(); + return myTableModel.getRowValue(row).getRenderer(); } }; } @Override protected JBTableRowEditor getRowEditor(int row) { - return myTableModel.getRowValue(row).getRowEditor(); + return myTableModel.getRowValue(row).getEditor(); } }; final JBTable table = myFilterTable.getTable(); + table.setTableHeader(new JTableHeader()); table.setStriped(false); myFilterPanel = ToolbarDecorator.createDecorator(table) .disableUpDownActions() @@ -87,39 +101,43 @@ public class FilterPanel { showAddFilterPopup(button.getContextComponent(), point); } }) + .setRemoveAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + myFilterTable.stopEditing(); + final int selectedRow = myFilterTable.getTable().getSelectedRow(); + final Filter filter = myTableModel.getRowValue(selectedRow); + if (filter instanceof FilterAction) { + ((FilterAction)filter).removeFilter(); + } + } + }) + .setRemoveActionUpdater(new AnActionButtonUpdater() { + @Override + public boolean isEnabled(AnActionEvent e) { + return myFilterTable.getTable().getSelectedRow() != 0; + } + }) + .setPanelBorder(null) .createPanel(); - myFilterPanel.setPreferredSize(new Dimension(350, 40)); - myFilterPanel.setVisible(false); - myFilterPanel.setBorder(com.intellij.util.ui.UIUtil.getTextFieldBorder()); + myFilterPanel.setPreferredSize(new Dimension(350, 60)); + myFilterPanel.setBorder(BorderFactory.createCompoundBorder(JBUI.Borders.empty(3, 0), myFilterPanel.getBorder())); } - private void showAddFilterPopup(Component component, RelativePoint point) { - final DefaultActionGroup group = new DefaultActionGroup( - new AnAction("Text") { - @Override - public void actionPerformed(AnActionEvent e) { - myTableModel.addRow(new TextFilter(myConstraint)); - } - }, - new AnAction("Type") { - @Override - public void actionPerformed(AnActionEvent e) { - assert false : "not implemented"; - } - }, - new AnAction("Reference") { - @Override - public void actionPerformed(AnActionEvent e) { - assert false : "not implemented"; - } - }, - new AnAction("Script") { - @Override - public void actionPerformed(AnActionEvent e) { - assert false : "not implemented"; - } + void showAddFilterPopup(Component component, RelativePoint point) { + myFilterTable.getTable().requestFocus(); + final DefaultActionGroup group = new DefaultActionGroup(); + group.add(myTextFilter); + group.add(myCountFilter); + group.add(myTypeFilter); + group.add(myReferenceFilter); + + group.add(new AnAction("Script") { + @Override + public void actionPerformed(AnActionEvent e) { + assert false : "not implemented"; } - ); + }); final DataContext context = DataManager.getInstance().getDataContext(component); final ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup("Add Filter", group, context, JBPopupFactory.ActionSelectionAid.ALPHA_NUMBERING, true, null); @@ -130,51 +148,44 @@ public class FilterPanel { return myFilterPanel; } - public void setFilters(MatchVariableConstraint constraint) { - myConstraint = constraint; - final List items = new SmartList<>(); - final String name = constraint.getName(); - items.add(() -> { - final SimpleColoredComponent label = new SimpleColoredComponent(); - label.append("Filters for $" + name + "$:", SimpleTextAttributes.GRAYED_ATTRIBUTES); - return label; - }); - if (!StringUtil.isEmpty(constraint.getRegExp())) { - items.add(new TextFilter(constraint)); - } - final int min = constraint.getMinCount(); - final int max = constraint.getMaxCount(); - if (min != 1 || max != 1) { - items.add(() -> new SimpleColoredComponent().append("count=[" + min + "," + (max == Integer.MAX_VALUE ? "∞" : max) + ']')); - } - - if (items.size() <= 1) { - items.clear(); - final String message; - if (Configuration.CONTEXT_VAR_NAME.equals(name)) { - message = "No filters added for the complete match."; - } - else { - message = "No Filters added for $" + name + "$."; - } - myFilterTable.getTable().getEmptyText().setText(message) - .appendSecondaryText("Add filter", SimpleTextAttributes.LINK_ATTRIBUTES, - new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - final JBTable table = myFilterTable.getTable(); - showAddFilterPopup(table, new RelativePoint(table, table.getMousePosition())); - } - }); - } - myTableModel.setItems(items); + public void setProfile(StructuralSearchProfile profile) { + myProfile = profile; } - private EditorTextField createTextComponent(String text) { + public void setCompiledPattern(CompiledPattern compiledPattern) { + myCompiledPattern = compiledPattern; + } + + public void setFilters(MatchVariableConstraint constraint) { + myConstraint = constraint; + final String varName = myConstraint.getName(); + final List nodes = myCompiledPattern.getVariableNodes(varName); + final boolean completePattern = Configuration.CONTEXT_VAR_NAME.equals(varName); + final boolean target = myConstraint.isPartOfSearchResults(); + myTableModel.setItems(new SmartList<>()); + myTextFilter.init(nodes, completePattern, target); + myCountFilter.init(nodes, completePattern, target); + myTypeFilter.init(nodes, completePattern, target); + + final String message = Configuration.CONTEXT_VAR_NAME.equals(varName) + ? "No filters added for the complete match." + : "No Filters added for $" + varName + "$."; + myFilterTable.getTable().getEmptyText().setText(message) + .appendSecondaryText("Add filter", SimpleTextAttributes.LINK_ATTRIBUTES, + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + final JBTable table = myFilterTable.getTable(); + showAddFilterPopup(table, new RelativePoint(table, table.getMousePosition())); + } + }); + } + + EditorTextField createTextComponent(String text) { return createEditorComponent(text, "1.txt"); } - private EditorTextField createRegexComponent(String text) { + EditorTextField createRegexComponent(String text) { return createEditorComponent(text, "1.regexp"); } @@ -187,54 +198,83 @@ public class FilterPanel { return new EditorTextField(text, myProject, getFileType(fileName)); } - private Document createDocument(final String fileName, final FileType fileType, String text) { - final PsiFile file = PsiFileFactory.getInstance(myProject).createFileFromText(fileName, fileType, text, -1, true); - return PsiDocumentManager.getInstance(myProject).getDocument(file); - } - private static FileType getFileType(final String fileName) { FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName); if (fileType == FileTypes.UNKNOWN) fileType = FileTypes.PLAIN_TEXT; return fileType; } - private interface Filter { - JComponent getRowRendererComponent(); - default JBTableRowEditor getRowEditor() { - return null; + private class Header implements Filter { + + private final SimpleColoredComponent myLabel = new SimpleColoredComponent(); + + Header() {} + + @Override + public int position() { + return 0; + } + + @Override + public SimpleColoredComponent getRenderer() { + myLabel.clear(); + final String varName = myConstraint.getName(); + myLabel.append(Configuration.CONTEXT_VAR_NAME.equals(varName) ? "Filters for the Complete Match:" : "Filters for $" + varName + "$:", + SimpleTextAttributes.GRAYED_ATTRIBUTES); + return myLabel; } } - private class TextFilter implements Filter { + private class TextFilter extends FilterAction { - private final MatchVariableConstraint myConstraint; + boolean showHierarchy; - public TextFilter(MatchVariableConstraint constraint) { - myConstraint = constraint; + TextFilter() { + super("Text"); } @Override - public JComponent getRowRendererComponent() { - final SimpleColoredComponent component = new SimpleColoredComponent(); - component.append("text=" + myConstraint.getRegExp()); - if (myConstraint.isWholeWordsOnly()) component.append(", whole words", SimpleTextAttributes.GRAYED_ATTRIBUTES); - if (myConstraint.isWithinHierarchy()) component.append(", within hierarchy", SimpleTextAttributes.GRAYED_ATTRIBUTES); - return component; + public int position() { + return 1; } @Override - public JBTableRowEditor getRowEditor() { - return new JBTableRowEditor() { + protected boolean hasFilter() { + return !StringUtil.isEmpty(myConstraint.getRegExp()); + } - private final EditorTextField myTextField = createRegexComponent(myConstraint.getRegExp()); - private final JCheckBox myWordsCheckBox = new JCheckBox("Words", myConstraint.isWholeWordsOnly()); - private final JCheckBox myHierarchyCheckBox = new JCheckBox("Within type hierarchy", myConstraint.isWithinHierarchy()); + public void clearFilter() { + myConstraint.setRegExp(""); + myConstraint.setWholeWordsOnly(false); + myConstraint.setWithinHierarchy(false); + } - @Override - public void prepareEditor(JTable table, int row) { - final JLabel nameLabel = new JLabel("name="); - final ContextHelpLabel helpLabel = ContextHelpLabel.create("Text of the match is checked against the provided pattern."); + @Override + public boolean isApplicable(List nodes, boolean completePattern, boolean target) { + showHierarchy = myProfile.isApplicableConstraint(UIUtil.TEXT_HIERARCHY, nodes, completePattern, target); + return myProfile.isApplicableConstraint(UIUtil.TEXT, nodes, completePattern, target); + } + @Override + protected void setLabel(SimpleColoredComponent component) { + myLabel.append("text="); + if (myConstraint.isInvertRegExp()) myLabel.append("!"); + myLabel.append(myConstraint.getRegExp()); + if (myConstraint.isWholeWordsOnly()) myLabel.append(", whole words", SimpleTextAttributes.GRAYED_ATTRIBUTES); + if (myConstraint.isWithinHierarchy()) myLabel.append(", within hierarchy", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + + @Override + public FilterEditor getEditor() { + return new FilterEditor(myConstraint) { + + private final EditorTextField myTextField = createRegexComponent(""); + private final JCheckBox myWordsCheckBox = new JCheckBox("Words", false); + private final JCheckBox myHierarchyCheckBox = new JCheckBox("Within type hierarchy", false); + private final JLabel myNameLabel = new JLabel("name="); + private final ContextHelpLabel myHelpLabel = ContextHelpLabel.create("Text of the match is checked against the provided pattern."); + + protected void layoutComponents() { final GroupLayout layout = new GroupLayout(this); setLayout(layout); layout.setAutoCreateContainerGaps(true); @@ -243,10 +283,10 @@ public class FilterPanel { layout.createParallelGroup() .addGroup( layout.createSequentialGroup() - .addComponent(nameLabel) + .addComponent(myNameLabel) .addComponent(myTextField) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 1, 1) - .addComponent(helpLabel) + .addComponent(myHelpLabel) ) .addGroup( layout.createSequentialGroup() @@ -259,9 +299,9 @@ public class FilterPanel { layout.createSequentialGroup() .addGroup( layout.createParallelGroup(GroupLayout.Alignment.CENTER) - .addComponent(nameLabel) + .addComponent(myNameLabel) .addComponent(myTextField) - .addComponent(helpLabel) + .addComponent(myHelpLabel) ) .addGroup( layout.createParallelGroup(GroupLayout.Alignment.CENTER) @@ -272,11 +312,18 @@ public class FilterPanel { } @Override - public JBTableRow getValue() { + protected void loadValues() { + myTextField.setText(myConstraint.getRegExp()); + myWordsCheckBox.setSelected(myConstraint.isWholeWordsOnly()); + myHierarchyCheckBox.setSelected(myConstraint.isWithinHierarchy()); + myHierarchyCheckBox.setVisible(showHierarchy); + } + + @Override + public void saveValues() { myConstraint.setRegExp(myTextField.getText()); myConstraint.setWholeWordsOnly(myWordsCheckBox.isSelected()); myConstraint.setWithinHierarchy(myHierarchyCheckBox.isSelected()); - return __ -> this; } @Override @@ -291,4 +338,377 @@ public class FilterPanel { }; } } + + private class CountFilter extends FilterAction { + + boolean myMinZero; + boolean myMaxUnlimited; + + CountFilter() { + super("Count"); + } + + @Override + public int position() { + return 2; + } + + @Override + protected boolean hasFilter() { + return myConstraint.getMinCount() != 1 || myConstraint.getMaxCount() != 1; + } + + @Override + protected void clearFilter() { + myConstraint.setMinCount(1); + myConstraint.setMaxCount(1); + } + + @Override + public boolean isApplicable(List nodes, boolean completePattern, boolean target) { + myMinZero = myProfile.isApplicableConstraint(UIUtil.MINIMUM_ZERO, nodes, completePattern, false); + myMaxUnlimited = myProfile.isApplicableConstraint(UIUtil.MAXIMUM_UNLIMITED, nodes, completePattern, false); + return myMinZero || myMaxUnlimited; + } + + @Override + protected void setLabel(SimpleColoredComponent component) { + final int min = myConstraint.getMinCount(); + final int max = myConstraint.getMaxCount(); + myLabel.append("count=[" + min + "," + (max == Integer.MAX_VALUE ? "∞" : max) + ']'); + } + + @Override + public FilterEditor getEditor() { + return new FilterEditor(myConstraint) { + + private final IntegerField myMinField = new IntegerField(); + private final IntegerField myMaxField = new IntegerField(); + private final JLabel myMinLabel = new JLabel("min="); + private final JLabel myMaxLabel = new JLabel("max="); + + { + myMinField.getValueEditor().addListener(newValue -> { + if (myMinField.getValueEditor().isValid(newValue) && myMaxField.getValue() < newValue) myMaxField.setValue(newValue); + }); + myMaxField.getValueEditor().addListener(newValue -> { + if (myMaxField.getValueEditor().isValid(newValue) && myMinField.getValue() > newValue) myMinField.setValue(newValue); + }); + } + + protected void layoutComponents() { + final GroupLayout layout = new GroupLayout(this); + setLayout(layout); + layout.setAutoCreateContainerGaps(true); + + layout.setHorizontalGroup( + layout.createSequentialGroup() + .addComponent(myMinLabel) + .addComponent(myMinField) + .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 20, 20) + .addComponent(myMaxLabel) + .addComponent(myMaxField) + ); + layout.setVerticalGroup( + layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(myMinLabel) + .addComponent(myMinField) + .addComponent(myMaxLabel) + .addComponent(myMaxField) + ); + } + + @Override + protected void loadValues() { + myMinField.setMinValue(myMinZero ? 0 : 1); + myMinField.setDefaultValue(myMinZero ? 0 : 1); + myMinField.setDefaultValueText(myMinZero ? "0" : "1"); + myMinField.setValue(myConstraint.getMinCount()); + myMinField.selectAll(); + + myMaxField.setMaxValue(myMaxUnlimited ? Integer.MAX_VALUE : 1); + myMaxField.setDefaultValue(myMaxUnlimited ? Integer.MAX_VALUE : 1); + myMaxField.setDefaultValueText(myMaxUnlimited ? SSRBundle.message("editvarcontraints.unlimited") : "1"); + myMaxField.setValue(myConstraint.getMaxCount()); + myMaxField.selectAll(); + } + + @Override + public void saveValues() { + myConstraint.setMinCount(myMinField.getValue()); + myConstraint.setMaxCount(myMaxField.getValue()); + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myMinField; + } + + @Override + public JComponent[] getFocusableComponents() { + return new JComponent[] {myMinField, myMaxField}; + } + }; + } + } + + private class TypeFilter extends FilterAction { + + TypeFilter() { + super("Type"); + } + + @Override + public int position() { + return 3; + } + + @Override + protected boolean hasFilter() { + return !StringUtil.isEmpty(myConstraint.getNameOfExprType()); + } + + @Override + protected void clearFilter() { + myConstraint.setNameOfExprType(""); + myConstraint.setInvertExprType(false); + myConstraint.setExprTypeWithinHierarchy(false); + } + + @Override + public boolean isApplicable(List nodes, boolean completePattern, boolean target) { + return myProfile.isApplicableConstraint(UIUtil.TYPE, nodes, completePattern, target); + } + + @Override + protected void setLabel(SimpleColoredComponent component) { + myLabel.append("type="); + if (myConstraint.isInvertExprType()) myLabel.append("!"); + myLabel.append(myConstraint.getNameOfExprType()); + if (myConstraint.isExprTypeWithinHierarchy()) myLabel.append(", within hierarchy", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + + @Override + public FilterEditor getEditor() { + return new FilterEditor(myConstraint) { + + private final EditorTextField myTextField = createTextComponent(""); + private final JLabel myTypeLabel = new JLabel("type="); + private final JCheckBox myHierarchyCheckBox = new JCheckBox("Within type hierarchy", false); + + protected void layoutComponents() { + final GroupLayout layout = new GroupLayout(this); + setLayout(layout); + layout.setAutoCreateContainerGaps(true); + + layout.setHorizontalGroup( + layout.createParallelGroup() + .addGroup( + layout.createSequentialGroup() + .addComponent(myTypeLabel) + .addComponent(myTextField) + ) + .addComponent(myHierarchyCheckBox) + ); + layout.setVerticalGroup( + layout.createSequentialGroup() + .addGroup( + layout.createParallelGroup(GroupLayout.Alignment.CENTER) + .addComponent(myTypeLabel) + .addComponent(myTextField) + ) + .addComponent(myHierarchyCheckBox) + ); + } + + @Override + protected void loadValues() { + myTextField.setText((myConstraint.isInvertExprType() ? "!" : "") + myConstraint.getNameOfExprType()); + } + + @Override + public void saveValues() { + final String text = myTextField.getText(); + if (text.startsWith("!")) { + myConstraint.setNameOfExprType(text.substring(1)); + myConstraint.setInvertExprType(true); + } + else { + myConstraint.setNameOfExprType(text); + myConstraint.setInvertExprType(false); + } + myConstraint.setExprTypeWithinHierarchy(myHierarchyCheckBox.isSelected()); + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myTextField; + } + + @Override + public JComponent[] getFocusableComponents() { + return new JComponent[] { myTextField }; + } + }; + } + } + + private class ReferenceFilter extends FilterAction { + + ReferenceFilter() { + super("Reference"); + } + + @Override + public int position() { + return 4; + } + + @Override + protected boolean hasFilter() { + return !StringUtil.isEmpty(myConstraint.getReferenceConstraint()); + } + + @Override + protected void clearFilter() { + myConstraint.setReferenceConstraint(""); + myConstraint.setInvertReference(false); + } + + @Override + public boolean isApplicable(List nodes, boolean completePattern, boolean target) { + return myProfile.isApplicableConstraint(UIUtil.REFERENCE, nodes, completePattern, target); + } + + @Override + protected void setLabel(SimpleColoredComponent component) { + component.append("reference"); + if (myConstraint.isInvertReference()) component.append("!"); + component.append(myConstraint.getReferenceConstraint()); + } + } + + private abstract class FilterAction extends AnAction implements Filter { + + protected final SimpleColoredComponent myLabel = new SimpleColoredComponent(); + + protected FilterAction(@Nullable String text) { + super(text); + } + + public final void init(List nodes, boolean completePattern, boolean target) { + if (isApplicable(nodes, completePattern, target) && !myTableModel.getItems().contains(this)) { + addFilterIfPresent(); + } + else { + clearFilter(); + getTemplatePresentation().setEnabledAndVisible(false); + } + } + + @Override + public final void actionPerformed(AnActionEvent e) { + addFilter(); + } + + @Override + public final SimpleColoredComponent getRenderer() { + if (!hasFilter()) removeFilter(); + myLabel.clear(); + setLabel(myLabel); + return myLabel; + } + + protected abstract void setLabel(SimpleColoredComponent component); + + protected abstract boolean hasFilter(); + + public final void addFilterIfPresent() { + if (hasFilter()) { + getTemplatePresentation().setEnabledAndVisible(false); + if (myTableModel.getRowCount() == 0) { + myTableModel.addRow(myHeader); + } + myTableModel.addRow(this); + } + else { + getTemplatePresentation().setEnabledAndVisible(true); + } + } + + public final void addFilter() { + getTemplatePresentation().setEnabledAndVisible(false); + final JBTable table = myFilterTable.getTable(); + TableUtil.stopEditing(table); + table.setRowHeight(table.getRowHeight()); // reset + int index = 0; + for (int max = myTableModel.getRowCount(); index < max; index++) { + if (position() < myTableModel.getItem(index).position()) { + break; + } + } + if (index == 0) { + myTableModel.addRow(myHeader); + index = 1; + } + myTableModel.insertRow(index, this); + table.editCellAt(index, 0); + table.setRowSelectionInterval(index, index); + table.setColumnSelectionInterval(0, 0); + TableUtil.updateScroller(table); + final Component editorComponent = table.getEditorComponent(); + if (editorComponent != null) { + table.scrollRectToVisible(editorComponent.getBounds()); + IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(editorComponent, true)); + } + } + + public final void removeFilter() { + final int index = myTableModel.indexOf(this); + if (index >= 0) myTableModel.removeRow(index); + if (myTableModel.getRowCount() == 1) myTableModel.removeRow(0); // remove header + getTemplatePresentation().setEnabledAndVisible(true); + clearFilter(); + } + + protected abstract void clearFilter(); + + public abstract boolean isApplicable(List nodes, boolean completePattern, boolean target); + } + + abstract static class FilterEditor extends JBTableRowEditor { + + protected final MatchVariableConstraint myConstraint; + + public FilterEditor(MatchVariableConstraint constraint) { + myConstraint = constraint; + } + + @Override + public final JBTableRow getValue() { + saveValues(); + return __ -> this; + } + + @Override + public final void prepareEditor(JTable table, int row) { + layoutComponents(); + loadValues(); + } + + protected abstract void layoutComponents(); + + protected abstract void loadValues(); + + protected abstract void saveValues(); + + } + + private interface Filter { + int position(); + SimpleColoredComponent getRenderer(); + default FilterEditor getEditor() { + return null; + } + } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ScopePanel.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ScopePanel.java index 934b31f54619..4f963ebdf1e2 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ScopePanel.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ScopePanel.java @@ -3,9 +3,9 @@ package com.intellij.structuralsearch.plugin.ui; import com.intellij.application.options.ModulesComboBox; import com.intellij.find.FindBundle; -import com.intellij.find.FindInProjectSettings; import com.intellij.ide.IdeBundle; import com.intellij.ide.util.scopeChooser.ScopeChooserCombo; +import com.intellij.ide.util.scopeChooser.ScopeDescriptor; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; import com.intellij.openapi.module.Module; @@ -15,8 +15,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScopesCore; -import com.intellij.psi.search.ProjectScopeImpl; import com.intellij.psi.search.SearchScope; +import com.intellij.structuralsearch.Scopes; +import com.intellij.ui.JBCardLayout; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; @@ -26,6 +27,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.util.Arrays; +import java.util.List; import java.util.function.Consumer; /** @@ -34,51 +36,42 @@ import java.util.function.Consumer; class ScopePanel extends JPanel { private final Project myProject; - private SearchScope mySelectedScope; + private SearchScope myScope; + private Scopes.Type myScopeType; private Consumer myCallback; private final ActionToolbarImpl myToolbar; - private final JPanel myScopeDetailsPanel = new JPanel(new CardLayout()); + private final JPanel myScopeDetailsPanel = new JPanel(new JBCardLayout()); private final ModulesComboBox myModulesComboBox = new ModulesComboBox(); private final DirectoryComboBoxWithButtons myDirectoryComboBox; - private final ScopeChooserCombo myScopeChooserComboBox = new ScopeChooserCombo(); + private final ScopeChooserCombo myScopesComboBox = new ScopeChooserCombo(); - public ScopePanel(@NotNull Project project, SearchScope selectedScope) { + public ScopePanel(@NotNull Project project) { super(null); myProject = project; - mySelectedScope = selectedScope; - Module[] allModules = ModuleManager.getInstance(project).getModules(); + final Module[] allModules = ModuleManager.getInstance(project).getModules(); myModulesComboBox.setModules(Arrays.asList(allModules)); if (allModules.length > 0) myModulesComboBox.setSelectedModule(allModules[0]); - myScopeChooserComboBox.init(project, true, false, "", - descriptor -> IdeBundle.message("scope.class.hierarchy").equals(descriptor.getDisplay()) || - !(descriptor.getScope() instanceof ModuleWithDependenciesScope)); + myModulesComboBox.addItemListener(e -> setScopeFromUI(Scopes.Type.MODULE)); + myScopesComboBox.init(project, true, false, "", + (ScopeDescriptor descriptor) -> IdeBundle.message("scope.class.hierarchy").equals(descriptor.getDisplay()) || + !(descriptor.getScope() instanceof ModuleWithDependenciesScope)); + myScopesComboBox.getComboBox().addItemListener(e -> setScopeFromUI(Scopes.Type.NAMED)); myDirectoryComboBox = new DirectoryComboBoxWithButtons(myProject); - myDirectoryComboBox.init(null, FindInProjectSettings.getInstance(myProject).getRecentDirectories()); // todo + myDirectoryComboBox.setCallback((vFile, recursive) -> setScopeFromUI(Scopes.Type.DIRECTORY)); - if (selectedScope instanceof ModuleWithDependenciesScope) { - final ModuleWithDependenciesScope scope = (ModuleWithDependenciesScope)selectedScope; - myModulesComboBox.setSelectedModule(scope.getModule()); - } - else if (selectedScope instanceof GlobalSearchScopesCore.DirectoryScope) { - //myDirectoryComboBox.setS; - } - else if (selectedScope != null) { - myScopeChooserComboBox.init(project, true, false, selectedScope.getDisplayName()); - } - - myScopeDetailsPanel.add(ScopeType.PROJECT.toString(), new JLabel()); - myScopeDetailsPanel.add(ScopeType.MODULE.toString(), myModulesComboBox); - myScopeDetailsPanel.add(ScopeType.DIRECTORY.toString(), myDirectoryComboBox); - myScopeDetailsPanel.add(ScopeType.SCOPE.toString(), myScopeChooserComboBox); + myScopeDetailsPanel.add(Scopes.Type.PROJECT.toString(), new JLabel()); + myScopeDetailsPanel.add(Scopes.Type.MODULE.toString(), shrinkWrap(myModulesComboBox)); + myScopeDetailsPanel.add(Scopes.Type.DIRECTORY.toString(), myDirectoryComboBox); + myScopeDetailsPanel.add(Scopes.Type.NAMED.toString(), shrinkWrap(myScopesComboBox)); myScopeDetailsPanel.setBorder(JBUI.Borders.emptyBottom(UIUtil.isUnderDefaultMacTheme() ? 0 : 3)); final DefaultActionGroup scopeActionGroup = new DefaultActionGroup( - new ScopeToggleAction(FindBundle.message("find.popup.scope.project"), ScopeType.PROJECT), - new ScopeToggleAction(FindBundle.message("find.popup.scope.module"), ScopeType.MODULE), - new ScopeToggleAction(FindBundle.message("find.popup.scope.directory"), ScopeType.DIRECTORY), - new ScopeToggleAction(FindBundle.message("find.popup.scope.scope"), ScopeType.SCOPE) + new ScopeToggleAction(FindBundle.message("find.popup.scope.project"), Scopes.Type.PROJECT), + new ScopeToggleAction(FindBundle.message("find.popup.scope.module"), Scopes.Type.MODULE), + new ScopeToggleAction(FindBundle.message("find.popup.scope.directory"), Scopes.Type.DIRECTORY), + new ScopeToggleAction(FindBundle.message("find.popup.scope.scope"), Scopes.Type.NAMED) ); myToolbar = (ActionToolbarImpl)ActionManager.getInstance().createActionToolbar("ScopePanel", scopeActionGroup, true); myToolbar.setForceMinimumSize(true); @@ -90,7 +83,7 @@ class ScopePanel extends JPanel { layout.createSequentialGroup() .addComponent(myToolbar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 25, 25) - .addComponent(myScopeDetailsPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(myScopeDetailsPanel) ); layout.setVerticalGroup( layout.createParallelGroup() @@ -99,19 +92,73 @@ class ScopePanel extends JPanel { ); } + private static JComponent shrinkWrap(JComponent component) { + final JPanel wrapper = new JPanel(new BorderLayout()); + wrapper.add(component, BorderLayout.WEST); + wrapper.add(Box.createHorizontalGlue(), BorderLayout.CENTER); + return wrapper; + } + + public void setRecentDirectories(@NotNull List recentDirectories) { + myDirectoryComboBox.setRecentDirectories(recentDirectories); + } + + public void setScope(SearchScope selectedScope) { + myScope = (selectedScope == null) ? GlobalSearchScope.projectScope(myProject) : selectedScope; + myScopeType = Scopes.getType(myScope); + + if (selectedScope instanceof ModuleWithDependenciesScope) { + final ModuleWithDependenciesScope scope = (ModuleWithDependenciesScope)selectedScope; + myModulesComboBox.setSelectedModule(scope.getModule()); + } + else if (selectedScope instanceof GlobalSearchScopesCore.DirectoryScope) { + final GlobalSearchScopesCore.DirectoryScope directoryScope = (GlobalSearchScopesCore.DirectoryScope)selectedScope; + final VirtualFile directory = directoryScope.getDirectory(); + myDirectoryComboBox.setDirectory(directory); + myDirectoryComboBox.setRecursive(directoryScope.isWithSubdirectories()); + } + else if (selectedScope != null) { + myScopesComboBox.init(myProject, true, false, selectedScope.getDisplayName()); + } + myToolbar.updateActionsImmediately(); + ((JBCardLayout)myScopeDetailsPanel.getLayout()).show(myScopeDetailsPanel, myScopeType.toString()); + } + public void setScopeCallback(Consumer callback) { myCallback = callback; } - public SearchScope getSelectedScope() { - return mySelectedScope; + public SearchScope getScope() { + return myScope; + } + + private void setScopeFromUI(Scopes.Type type) { + switch (type) { + case PROJECT: + myScope = GlobalSearchScope.projectScope(myProject); + break; + case MODULE: + final Module module = myModulesComboBox.getSelectedModule(); + if (module == null) return; + myScope = GlobalSearchScope.moduleScope(module); + break; + case DIRECTORY: + final VirtualFile directory = myDirectoryComboBox.getDirectory(); + if (directory == null) return; + myScope = GlobalSearchScopesCore.directoryScope(myProject, directory, myDirectoryComboBox.isRecursive()); + break; + case NAMED: + myScope = myScopesComboBox.getSelectedScope(); + break; + } + if (myCallback != null) myCallback.accept(myScope); } class ScopeToggleAction extends ToggleAction { - private final ScopeType myScopeType; + private final Scopes.Type myScopeType; - public ScopeToggleAction(@Nullable String text, ScopeType scopeType) { + public ScopeToggleAction(@Nullable String text, Scopes.Type scopeType) { super(text, null, EmptyIcon.ICON_0); myScopeType = scopeType; getTemplatePresentation().setDisabledIcon(EmptyIcon.ICON_0); @@ -119,35 +166,17 @@ class ScopePanel extends JPanel { @Override public boolean isSelected(AnActionEvent e) { - return myScopeType == ScopeType.fromScope(mySelectedScope); + return myScopeType == ScopePanel.this.myScopeType; } @Override public void setSelected(AnActionEvent e, boolean state) { if (state) { - switch (myScopeType) { - case PROJECT: - mySelectedScope = GlobalSearchScope.projectScope(myProject); - break; - case MODULE: - final Module module = myModulesComboBox.getSelectedModule(); - if (module != null) { - mySelectedScope = GlobalSearchScope.moduleScope(module); - } - break; - case DIRECTORY: - final VirtualFile directory = myDirectoryComboBox.getDirectory(); - if (directory != null) { - mySelectedScope = GlobalSearchScopesCore.directoryScope(myProject, directory, myDirectoryComboBox.isRecursive()); - } - break; - case SCOPE: - mySelectedScope = myScopeChooserComboBox.getSelectedScope(); - break; - } + ((JBCardLayout)myScopeDetailsPanel.getLayout()).swipe(myScopeDetailsPanel, myScopeType.toString(), + ScopePanel.this.myScopeType.compareTo(myScopeType) > 0 ? JBCardLayout.SwipeDirection.FORWARD : JBCardLayout.SwipeDirection.BACKWARD); + ScopePanel.this.myScopeType = myScopeType; + setScopeFromUI(myScopeType); myToolbar.updateActionsImmediately(); - ((CardLayout)myScopeDetailsPanel.getLayout()).show(myScopeDetailsPanel, myScopeType.toString()); - if (myCallback != null) myCallback.accept(mySelectedScope); } } @@ -156,26 +185,4 @@ class ScopePanel extends JPanel { return true; } } - - enum ScopeType { - PROJECT, - MODULE, - DIRECTORY, - SCOPE; - - static ScopeType fromScope(SearchScope scope) { - if (scope instanceof ProjectScopeImpl || scope == null) { - return PROJECT; - } - else if (scope instanceof ModuleWithDependenciesScope) { - return MODULE; - } - else if (scope instanceof GlobalSearchScopesCore.DirectoryScope) { - return DIRECTORY; - } - else { - return SCOPE; - } - } - } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchDialog.java index 4c808f180505..2071428bdec9 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchDialog.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchDialog.java @@ -4,6 +4,7 @@ package com.intellij.structuralsearch.plugin.ui; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.template.impl.TemplateEditorUtil; import com.intellij.find.FindBundle; +import com.intellij.find.FindInProjectSettings; import com.intellij.find.FindSettings; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; @@ -27,18 +28,28 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.Splitter; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.GlobalSearchScopesCore; import com.intellij.psi.search.SearchScope; import com.intellij.structuralsearch.*; +import com.intellij.structuralsearch.impl.matcher.CompiledPattern; import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler; import com.intellij.structuralsearch.plugin.StructuralSearchPlugin; import com.intellij.ui.EditorTextField; +import com.intellij.ui.OnePixelSplitter; +import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Alarm; import com.intellij.util.ObjectUtils; import com.intellij.util.SmartList; @@ -50,11 +61,13 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -62,37 +75,34 @@ import java.util.List; */ public class StructuralSearchDialog extends DialogWrapper { static final Key STRUCTURAL_SEARCH = Key.create("STRUCTURAL_SEARCH_AREA"); - protected SearchContext searchContext; - - // text for search - protected EditorTextField searchCriteriaEdit; - - private JCheckBox recursiveMatching; - private JCheckBox caseSensitiveMatch; - - private FileTypeSelector fileTypes; - - protected Configuration myConfiguration; - private JCheckBox openInNewTab; - private final Alarm myAlarm; - public static final String USER_DEFINED = SSRBundle.message("new.template.defaultname"); - private boolean useLastConfiguration; - @NonNls private FileType ourFtSearchVariant = StructuralSearchUtil.getDefaultFileType(); - private static Language ourDialect = null; - private static String ourContext = null; + // search info + protected SearchContext mySearchContext; + protected Configuration myConfiguration; + @NonNls private FileType myFileType = StructuralSearchUtil.getDefaultFileType(); + private Language myDialect = null; + private String myContext = null; + // ui management + private final Alarm myAlarm; + private boolean myUseLastConfiguration; private final boolean myShowScopePanel; private final boolean myRunFindActionOnClose; private boolean myDoingOkAction; - private String mySavedEditorText; - private JPanel myEditorPanel; private boolean myFilterButtonEnabled = false; - private FilterPanel myFilterPanel; + + // components + private JCheckBox myRecursiveMatching; + private JCheckBox myCaseSensitiveMatch; + private FileTypeSelector myFileTypesComboBox; + protected EditorTextField mySearchCriteriaEdit; + private OnePixelSplitter myEditorPanel; + private FilterPanel myFilterPanel; private LinkComboBox myTargetComboBox; private ScopePanel myScopePanel; + private JCheckBox myOpenInNewTab; public StructuralSearchDialog(SearchContext searchContext) { this(searchContext, true, true); @@ -104,7 +114,7 @@ public class StructuralSearchDialog extends DialogWrapper { if (showScope) setModal(false); myShowScopePanel = showScope; myRunFindActionOnClose = runFindActionOnClose; - this.searchContext = searchContext; + this.mySearchContext = searchContext; setTitle(getDefaultTitle()); if (runFindActionOnClose) { @@ -124,7 +134,7 @@ public class StructuralSearchDialog extends DialogWrapper { } public void setUseLastConfiguration(boolean useLastConfiguration) { - this.useLastConfiguration = useLastConfiguration; + this.myUseLastConfiguration = useLastConfiguration; } void setSearchPattern(final Configuration config) { @@ -133,14 +143,9 @@ public class StructuralSearchDialog extends DialogWrapper { } protected EditorTextField createEditor(final SearchContext searchContext, String text) { - final FileTypeInfo info = fileTypes.getSelectedItem(); - assert info != null; - final FileType fileType = info.getFileType(); - final Language dialect = info.getDialect(); - - final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(fileType); + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(myFileType); assert profile != null; - final Document document = profile.createDocument(searchContext.getProject(), fileType, dialect, text); + final Document document = profile.createDocument(searchContext.getProject(), myFileType, myDialect, text); document.addDocumentListener(new DocumentListener() { @Override public void documentChanged(final DocumentEvent event) { @@ -148,7 +153,7 @@ public class StructuralSearchDialog extends DialogWrapper { } }); - final EditorTextField textField = new EditorTextField(document, searchContext.getProject(), fileType) { + final EditorTextField textField = new EditorTextField(document, searchContext.getProject(), myFileType) { @Override protected EditorEx createEditor() { EditorEx editorEx = super.createEditor(); @@ -158,6 +163,7 @@ public class StructuralSearchDialog extends DialogWrapper { } }; textField.setPreferredSize(new Dimension(850, 150)); + textField.setMinimumSize(new Dimension(200, 50)); return textField; } @@ -200,7 +206,9 @@ public class StructuralSearchDialog extends DialogWrapper { private boolean isCompiled() { try { - return PatternCompiler.compilePattern(getProject(), myConfiguration.getMatchOptions(), false) != null; + final CompiledPattern compiledPattern = PatternCompiler.compilePattern(getProject(), myConfiguration.getMatchOptions(), false); + myFilterPanel.setCompiledPattern(compiledPattern); + return compiledPattern != null; } catch (MalformedPatternException e) { return false; } @@ -208,45 +216,44 @@ public class StructuralSearchDialog extends DialogWrapper { void updateEditor() { if (myEditorPanel != null) { - if (searchCriteriaEdit != null) { - mySavedEditorText = searchCriteriaEdit.getText(); - myEditorPanel.remove(searchCriteriaEdit); + if (mySearchCriteriaEdit != null) { + mySavedEditorText = mySearchCriteriaEdit.getText(); + myEditorPanel.remove(mySearchCriteriaEdit); } - searchCriteriaEdit = createEditor(searchContext, mySavedEditorText != null ? mySavedEditorText : ""); - myEditorPanel.add(searchCriteriaEdit, BorderLayout.CENTER); + mySearchCriteriaEdit = createEditor(mySearchContext, mySavedEditorText != null ? mySavedEditorText : ""); + myEditorPanel.setFirstComponent(mySearchCriteriaEdit); myEditorPanel.revalidate(); - final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(ourFtSearchVariant); + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(myFileType); assert profile != null; - searchCriteriaEdit.addPropertyChangeListener(new PropertyChangeListener() { + mySearchCriteriaEdit.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - final Editor editor = searchCriteriaEdit.getEditor(); + final Editor editor = mySearchCriteriaEdit.getEditor(); if (editor == null) return; TemplateEditorUtil.setHighlighter(editor, profile.getTemplateContextType()); SubstitutionShortInfoHandler.install(editor, variableName -> myFilterPanel.setFilters(myConfiguration.getMatchOptions().getVariableConstraint(variableName))); - myFilterPanel.setFilters(UIUtil.getOrAddVariableConstraint(Configuration.CONTEXT_VAR_NAME, myConfiguration)); + //myFilterPanel.setFilters(UIUtil.getOrAddVariableConstraint(Configuration.CONTEXT_VAR_NAME, myConfiguration)); editor.putUserData(SubstitutionShortInfoHandler.CURRENT_CONFIGURATION_KEY, myConfiguration); - final Project project = searchContext.getProject(); - final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(searchCriteriaEdit.getDocument()); + final Project project = mySearchContext.getProject(); + final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(mySearchCriteriaEdit.getDocument()); if (file != null) { DaemonCodeAnalyzer.getInstance(project).setHighlightingEnabled(file, false); } - searchCriteriaEdit.removePropertyChangeListener(this); + mySearchCriteriaEdit.removePropertyChangeListener(this); } }); - } } private void detectFileTypeAndDialect() { - final PsiFile file = searchContext.getFile(); + final PsiFile file = mySearchContext.getFile(); if (file != null) { PsiElement context = null; - if (searchContext.getEditor() != null) { - context = file.findElementAt(searchContext.getEditor().getCaretModel().getOffset()); + if (mySearchContext.getEditor() != null) { + context = file.findElementAt(mySearchContext.getEditor().getCaretModel().getOffset()); if (context != null) { context = context.getParent(); } @@ -274,9 +281,7 @@ public class StructuralSearchDialog extends DialogWrapper { } } - ourFtSearchVariant = detectedFileType != null ? - detectedFileType : - StructuralSearchUtil.getDefaultFileType(); + myFileType = (detectedFileType != null) ? detectedFileType : StructuralSearchUtil.getDefaultFileType(); } } @@ -298,19 +303,20 @@ public class StructuralSearchDialog extends DialogWrapper { break; } } + myScopePanel.setScope(matchOptions.getScope()); + myScopePanel.setRecentDirectories(FindInProjectSettings.getInstance(getProject()).getRecentDirectories()); - final Document document = searchCriteriaEdit.getDocument(); - CommandProcessor.getInstance().executeCommand(searchContext.getProject(), () -> { + final Document document = mySearchCriteriaEdit.getDocument(); + CommandProcessor.getInstance().executeCommand(mySearchContext.getProject(), () -> { ApplicationManager.getApplication().runWriteAction(() -> { document.replaceString(0, document.getTextLength(), matchOptions.getSearchPattern()); }); }, null, null); - recursiveMatching.setSelected(isRecursiveSearchEnabled() && matchOptions.isRecursiveSearch()); - caseSensitiveMatch.setSelected(matchOptions.isCaseSensitiveMatch()); - - fileTypes.setSelectedItem(matchOptions.getFileType(), matchOptions.getDialect(), matchOptions.getPatternContext()); - final Editor editor = searchCriteriaEdit.getEditor(); + myRecursiveMatching.setSelected(isRecursiveSearchEnabled() && matchOptions.isRecursiveSearch()); + myCaseSensitiveMatch.setSelected(matchOptions.isCaseSensitiveMatch()); + myFileTypesComboBox.setSelectedItem(matchOptions.getFileType(), matchOptions.getDialect(), matchOptions.getPatternContext()); + final Editor editor = mySearchCriteriaEdit.getEditor(); if (editor != null) { editor.putUserData(SubstitutionShortInfoHandler.CURRENT_CONFIGURATION_KEY, myConfiguration); } @@ -321,13 +327,13 @@ public class StructuralSearchDialog extends DialogWrapper { } protected void setText(String text) { - setTextForEditor(text, searchCriteriaEdit); + setTextForEditor(text, mySearchCriteriaEdit); } protected final void setTextForEditor(final String selection, EditorTextField editor) { editor.setText(selection); editor.selectAll(); - final Project project = searchContext.getProject(); + final Project project = mySearchContext.getProject(); final Document document = editor.getDocument(); final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); documentManager.commitDocument(document); @@ -340,7 +346,7 @@ public class StructuralSearchDialog extends DialogWrapper { } protected void startSearching() { - new SearchCommand(myConfiguration, searchContext).startSearching(); + new SearchCommand(myConfiguration, mySearchContext).startSearching(); } protected String getDefaultTitle() { @@ -349,15 +355,46 @@ public class StructuralSearchDialog extends DialogWrapper { @Override protected JComponent createCenterPanel() { - myEditorPanel = new JPanel(new BorderLayout()); - searchCriteriaEdit = createEditor(searchContext, mySavedEditorText != null ? mySavedEditorText : ""); - myEditorPanel.add(BorderLayout.CENTER, searchCriteriaEdit); + myEditorPanel = new OnePixelSplitter(false, 1.0f) { + /*final Timer myTimer = com.intellij.util.ui.UIUtil.createNamedTimer("SlidingSplitter", 17); - myScopePanel = new ScopePanel(getProject(), myConfiguration.getMatchOptions().getScope()); - myScopePanel.setEnabled(myShowScopePanel); // todo initiateValidation() on change + @Override + public void setSecondComponent(@Nullable JComponent component) { + if (component != null) { + final Dimension size = component.getMinimumSize(); + component.setMinimumSize(new Dimension(0, size.height)); + final ActionListener listener = e -> { + final int width = component.getMinimumSize().width; + if (width < size.width) { + component.setMinimumSize(new Dimension(width + 1, size.height)); + myEditorPanel.revalidate(); + } + else { + myTimer.stop(); + } + }; + for (ActionListener actionListener: myTimer.getActionListeners()) { + myTimer.removeActionListener(actionListener); + } + myTimer.addActionListener(listener); + myTimer.start(); + super.setSecondComponent(component); + } + super.setSecondComponent(component); + }*/ + }; + myEditorPanel.setLackOfSpaceStrategy(Splitter.LackOfSpaceStrategy.HONOR_THE_SECOND_MIN_SIZE); + myEditorPanel.getDivider().setOpaque(false); + mySearchCriteriaEdit = createEditor(mySearchContext, mySavedEditorText != null ? mySavedEditorText : ""); + myEditorPanel.add(BorderLayout.CENTER, mySearchCriteriaEdit); - myFilterPanel = new FilterPanel(getProject(), getDisposable()); - myFilterPanel.getComponent().setMinimumSize(new Dimension(400, searchCriteriaEdit.getMinimumSize().height)); + myScopePanel = new ScopePanel(getProject()); + myScopePanel.setEnabled(myShowScopePanel); + myScopePanel.setScopeCallback(s -> initiateValidation()); + + myFilterPanel = + new FilterPanel(getProject(), StructuralSearchUtil.getProfileByFileType(myFileType), getDisposable()); + myFilterPanel.getComponent().setMinimumSize(new Dimension(300, 50)); final JLabel searchTargetLabel = new JLabel(SSRBundle.message("search.target.label")); myTargetComboBox = new LinkComboBox(SSRBundle.message("complete.match.variable.name")); @@ -369,23 +406,25 @@ public class StructuralSearchDialog extends DialogWrapper { layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(myEditorPanel) - .addComponent(myFilterPanel.getComponent())) + ) .addComponent(myScopePanel) .addGroup(layout.createSequentialGroup() .addComponent(searchTargetLabel) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 5, 5) - .addComponent(myTargetComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addComponent(myTargetComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(myEditorPanel) - .addComponent(myFilterPanel.getComponent())) + ) .addComponent(myScopePanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 2, 2) .addGroup(layout.createParallelGroup() .addComponent(searchTargetLabel) - .addComponent(myTargetComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addComponent(myTargetComboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + ) ); updateEditor(); @@ -398,7 +437,7 @@ public class StructuralSearchDialog extends DialogWrapper { final DefaultActionGroup historyActionGroup = new DefaultActionGroup(new AnAction(getShowHistoryIcon()) { @Override public void actionPerformed(AnActionEvent e) { - final SelectTemplateDialog dialog = new SelectTemplateDialog(searchContext.getProject(), true, isReplaceDialog()); + final SelectTemplateDialog dialog = new SelectTemplateDialog(mySearchContext.getProject(), true, isReplaceDialog()); if (!dialog.showAndGet()) { return; } @@ -415,9 +454,9 @@ public class StructuralSearchDialog extends DialogWrapper { final JLabel label = new JLabel(SSRBundle.message("search.template")); UIUtil.installCompleteMatchInfo(label, () -> myConfiguration); - recursiveMatching = new JCheckBox(SSRBundle.message("recursive.matching.checkbox"), true); - recursiveMatching.setVisible(isRecursiveSearchEnabled()); - caseSensitiveMatch = new JCheckBox(FindBundle.message("find.popup.case.sensitive"), true); + myRecursiveMatching = new JCheckBox(SSRBundle.message("recursive.matching.checkbox"), true); + myRecursiveMatching.setVisible(isRecursiveSearchEnabled()); + myCaseSensitiveMatch = new JCheckBox(FindBundle.message("find.popup.case.sensitive"), true); final List types = new ArrayList<>(); for (FileType fileType : StructuralSearchUtil.getSuitableFileTypes()) { if (StructuralSearchUtil.getProfileByFileType(fileType) != null) { @@ -425,20 +464,27 @@ public class StructuralSearchDialog extends DialogWrapper { } } Collections.sort(types, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); - fileTypes = new FileTypeSelector(types); - fileTypes.setMinimumAndPreferredWidth(200); - fileTypes.setSelectedItem(ourFtSearchVariant, ourDialect, ourContext); - fileTypes.addItemListener(new ItemListener() { + myFileTypesComboBox = new FileTypeSelector(types); + myFileTypesComboBox.setMinimumAndPreferredWidth(200); + myFileTypesComboBox.setSelectedItem(myFileType, myDialect, myContext); + myFileTypesComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { + final FileTypeInfo item = myFileTypesComboBox.getSelectedItem(); + if (item == null) return; + myFileType = item.getFileType(); + myDialect = item.getDialect(); + myContext = item.getContext(); updateEditor(); + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(myFileType); + myFilterPanel.setProfile(profile); initiateValidation(); } } }); final JLabel fileTypeLabel = new JLabel(SSRBundle.message("search.dialog.file.type.label")); - fileTypeLabel.setLabelFor(fileTypes); + fileTypeLabel.setLabelFor(myFileTypesComboBox); final DefaultActionGroup templateActionGroup = new DefaultActionGroup( new AnAction(SSRBundle.message("save.template.text.button")) { @@ -450,11 +496,12 @@ public class StructuralSearchDialog extends DialogWrapper { new AnAction(SSRBundle.message("copy.existing.template.button")) { @Override public void actionPerformed(AnActionEvent e) { - SelectTemplateDialog dialog = new SelectTemplateDialog(searchContext.getProject(), false, isReplaceDialog()); + System.out.println("StructuralSearchDialog.actionPerformed(" + e + ")"); + final SelectTemplateDialog dialog = new SelectTemplateDialog(mySearchContext.getProject(), false, isReplaceDialog()); if (!dialog.showAndGet()) { return; } - Configuration[] configurations = dialog.getSelectedConfigurations(); + final Configuration[] configurations = dialog.getSelectedConfigurations(); if (configurations.length == 1) { setSearchPattern(configurations[0]); } @@ -468,15 +515,12 @@ public class StructuralSearchDialog extends DialogWrapper { @Override public boolean isSelected(AnActionEvent e) { - return myFilterPanel.getComponent().isVisible(); + return myEditorPanel.getSecondComponent() != null; } @Override public void setSelected(AnActionEvent e, boolean state) { - if (state) { - myFilterPanel.getComponent().setMinimumSize(new Dimension(400, searchCriteriaEdit.getMinimumSize().height)); - } - myFilterPanel.getComponent().setVisible(state); + myEditorPanel.setSecondComponent(state ? myFilterPanel.getComponent() : null); } @Override @@ -485,7 +529,7 @@ public class StructuralSearchDialog extends DialogWrapper { } }; final DefaultActionGroup optionsActionGroup = new DefaultActionGroup(filterAction, templateActionGroup); - ActionToolbarImpl optionsToolbar = + final ActionToolbarImpl optionsToolbar = (ActionToolbarImpl)ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, optionsActionGroup, true); optionsToolbar.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY); optionsToolbar.setForceMinimumSize(true); @@ -499,23 +543,23 @@ public class StructuralSearchDialog extends DialogWrapper { .addComponent(historyToolbar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(label) .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 20, Integer.MAX_VALUE) - .addComponent(recursiveMatching) + .addComponent(myRecursiveMatching) .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 15, 15) - .addComponent(caseSensitiveMatch) + .addComponent(myCaseSensitiveMatch) .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 15, 15) .addComponent(fileTypeLabel) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 5, 5) - .addComponent(fileTypes, 125, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(myFileTypesComboBox, 125, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(optionsToolbar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ); layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(historyToolbar) .addComponent(label) - .addComponent(recursiveMatching) - .addComponent(caseSensitiveMatch) + .addComponent(myRecursiveMatching) + .addComponent(myCaseSensitiveMatch) .addComponent(fileTypeLabel) - .addComponent(fileTypes) + .addComponent(myFileTypesComboBox) .addComponent(optionsToolbar) ); @@ -529,9 +573,9 @@ public class StructuralSearchDialog extends DialogWrapper { if (!myRunFindActionOnClose) return null; JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(BorderFactory.createEmptyBorder(0, 6, 0, 0)); - openInNewTab = new JCheckBox(SSRBundle.message("open.in.new.tab.checkbox")); - openInNewTab.setSelected(FindSettings.getInstance().isShowResultsInSeparateView()); - panel.add(openInNewTab, BorderLayout.EAST); + myOpenInNewTab = new JCheckBox(SSRBundle.message("open.in.new.tab.checkbox")); + myOpenInNewTab.setSelected(FindSettings.getInstance().isShowResultsInSeparateView()); + panel.add(myOpenInNewTab, BorderLayout.EAST); return panel; } @@ -541,7 +585,7 @@ public class StructuralSearchDialog extends DialogWrapper { @NotNull private List getSearchVariables() { - final Editor editor = searchCriteriaEdit.getEditor(); + final Editor editor = mySearchCriteriaEdit.getEditor(); if (editor == null) { return new SmartList<>(); } @@ -554,7 +598,7 @@ public class StructuralSearchDialog extends DialogWrapper { } public final Project getProject() { - return searchContext.getProject(); + return mySearchContext.getProject(); } protected boolean isReplaceDialog() { @@ -565,8 +609,8 @@ public class StructuralSearchDialog extends DialogWrapper { public void show() { StructuralSearchPlugin.getInstance(getProject()).setDialogVisible(true); - if (!useLastConfiguration) { - final Editor editor = searchContext.getEditor(); + if (!myUseLastConfiguration) { + final Editor editor = mySearchContext.getEditor(); boolean setSomeText = false; if (editor != null) { @@ -593,7 +637,7 @@ public class StructuralSearchDialog extends DialogWrapper { @Override public JComponent getPreferredFocusedComponent() { - return searchCriteriaEdit; + return mySearchCriteriaEdit; } @Override @@ -604,24 +648,29 @@ public class StructuralSearchDialog extends DialogWrapper { if (!result) return; myAlarm.cancelAllRequests(); + removeUnusedVariableConstraints(myConfiguration); super.doOKAction(); if (!myRunFindActionOnClose) return; - final SearchScope selectedScope = myScopePanel.getSelectedScope(); - if (selectedScope == null) return; + final SearchScope scope = myScopePanel.getScope(); + if (scope == null) return; + + if (scope instanceof GlobalSearchScopesCore.DirectoryScope) { + final GlobalSearchScopesCore.DirectoryScope directoryScope = (GlobalSearchScopesCore.DirectoryScope)scope; + FindInProjectSettings.getInstance(getProject()).addDirectory(directoryScope.getDirectory().getPresentableUrl()); + } final FindSettings findSettings = FindSettings.getInstance(); - findSettings.setDefaultScopeName(selectedScope.getDisplayName()); - findSettings.setShowResultsInSeparateView(openInNewTab.isSelected()); + findSettings.setDefaultScopeName(scope.getDisplayName()); + findSettings.setShowResultsInSeparateView(myOpenInNewTab.isSelected()); try { - removeUnusedVariableConstraints(myConfiguration); ConfigurationManager.getInstance(getProject()).addHistoryConfiguration(myConfiguration); startSearching(); } catch (MalformedPatternException ex) { - reportMessage(SSRBundle.message("this.pattern.is.malformed.message", ex.getMessage()), searchCriteriaEdit); + reportMessage(SSRBundle.message("this.pattern.is.malformed.message", ex.getMessage()), mySearchCriteriaEdit); } } @@ -639,34 +688,42 @@ public class StructuralSearchDialog extends DialogWrapper { protected boolean isValid() { try { - Matcher.validate(searchContext.getProject(), getConfiguration().getMatchOptions()); + Matcher.validate(mySearchContext.getProject(), getConfiguration().getMatchOptions()); } catch (MalformedPatternException ex) { reportMessage(SSRBundle.message("this.pattern.is.malformed.message", - (ex.getMessage() != null) ? ex.getMessage() : ""), searchCriteriaEdit); + (ex.getMessage() != null) ? ex.getMessage() : ""), mySearchCriteriaEdit); return false; } catch (UnsupportedPatternException ex) { - reportMessage(SSRBundle.message("this.pattern.is.unsupported.message", ex.getMessage()), searchCriteriaEdit); + reportMessage(SSRBundle.message("this.pattern.is.unsupported.message", ex.getMessage()), mySearchCriteriaEdit); return false; } catch (NoMatchFoundException e) { - reportMessage(e.getMessage(), searchCriteriaEdit); + reportMessage(e.getMessage(), mySearchCriteriaEdit); return false; } - reportMessage(null, searchCriteriaEdit); + reportMessage(null, mySearchCriteriaEdit); return true; } - protected void reportMessage(String message, EditorTextField editor) { - com.intellij.util.ui.UIUtil.invokeLaterIfNeeded(() -> { - editor.putClientProperty("JComponent.outline", message == null ? null : "error"); - editor.setToolTipText(message); - editor.repaint(); - //status.setText(message); - //status.setToolTipText(message); - //status.revalidate(); - //statusText.setLabelFor(editor != null ? editor.getContentComponent() : null); + protected void reportMessage(String message, JComponent component) { + com.intellij.util.ui.UIUtil.invokeLaterIfNeeded(() -> { + component.putClientProperty("JComponent.outline", message == null ? null : "error"); + component.repaint(); + + if (message == null) return; + final Balloon balloon = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(message, MessageType.ERROR, null).createBalloon(); + if (component == mySearchCriteriaEdit) { + balloon.show(new RelativePoint(component, new Point(component.getWidth() / 2, component.getHeight())), Balloon.Position.below); + } + else { + balloon.show(new RelativePoint(component, new Point(component.getWidth() / 2, 0)), Balloon.Position.above); + } + //balloon.show(new RelativePoint(component, new Point(component.getWidth() / 2, 0)), Balloon.Position.above); + balloon.showInCenterOf(component); + Disposer.register(myDisposable, balloon); + IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(component, true)); }); } @@ -674,26 +731,19 @@ public class StructuralSearchDialog extends DialogWrapper { MatchOptions options = config.getMatchOptions(); if (myShowScopePanel) { - final SearchScope scope = myScopePanel.getSelectedScope(); + final SearchScope scope = myScopePanel.getScope(); if (scope != null) { - boolean searchWithinHierarchy = IdeBundle.message("scope.class.hierarchy").equals(scope.getDisplayName()); + final boolean searchWithinHierarchy = IdeBundle.message("scope.class.hierarchy").equals(scope.getDisplayName()); // We need to reset search within hierarchy scope during online validation since the scope works with user participation options.setScope(searchWithinHierarchy && !myDoingOkAction ? GlobalSearchScope.projectScope(getProject()) : scope); } } - options.setRecursiveSearch(isRecursiveSearchEnabled() && recursiveMatching.isSelected()); - - final FileTypeInfo info = fileTypes.getSelectedItem(); - ourFtSearchVariant = info != null ? info.getFileType() : null; - ourDialect = info != null ? info.getDialect() : null; - ourContext = info != null ? info.getContext() : null; - FileType fileType = ourFtSearchVariant; - options.setFileType(fileType); - options.setDialect(ourDialect); - options.setPatternContext(ourContext); - - options.setSearchPattern(searchCriteriaEdit.getDocument().getText()); - options.setCaseSensitiveMatch(caseSensitiveMatch.isSelected()); + options.setRecursiveSearch(isRecursiveSearchEnabled() && myRecursiveMatching.isSelected()); + options.setFileType(myFileType); + options.setDialect(myDialect); + options.setPatternContext(myContext); + options.setSearchPattern(mySearchCriteriaEdit.getDocument().getText()); + options.setCaseSensitiveMatch(myCaseSensitiveMatch.isSelected()); } @Override @@ -705,7 +755,7 @@ public class StructuralSearchDialog extends DialogWrapper { public void dispose() { StructuralSearchPlugin.getInstance(getProject()).setDialogVisible(false); myAlarm.cancelAllRequests(); - searchCriteriaEdit.removeNotify(); + mySearchCriteriaEdit.removeNotify(); super.dispose(); } diff --git a/xml/xml-psi-impl/resources/standardSchemas/XMLSchema-instance.xsd b/xml/xml-psi-impl/resources/standardSchemas/XMLSchema-instance.xsd index e57428f881b0..f47577b8ab82 100644 --- a/xml/xml-psi-impl/resources/standardSchemas/XMLSchema-instance.xsd +++ b/xml/xml-psi-impl/resources/standardSchemas/XMLSchema-instance.xsd @@ -1,25 +1,37 @@ + + + + + + +]> + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns="http://www.w3.org/1999/xhtml"> - +

XML Schema instance namespace

-

See The XML Schema draft recommendation for an introduction

+

See the XML Schema + Recommendation for an introduction


- $Date: 2004/06/09 12:44:55 $
- $Id: XMLSchema-instance.xsd,v 1.1 2004/06/09 12:44:55 max Exp $ + $Date: 2001/03/16 20:25:57 $
+ $Id: XMLSchema-instance.xsd,v 1.4 2001/03/16 20:25:57 ht Exp $ +
+
+ +

This schema should never be used as such: + the XML + Schema Recommendation forbids the declaration of + attributes in this namespace

- - - No definitions are provided here, as - this schema is never used as such - - - + +