mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
SSR: import/export templates through copy/paste (IDEA-161879)
This commit is contained in:
+27
@@ -12,6 +12,7 @@ import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.structuralsearch.MatchVariableConstraint;
|
||||
import com.intellij.structuralsearch.SSRBundle;
|
||||
@@ -22,13 +23,17 @@ import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import com.intellij.util.ui.TextTransferable;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.*;
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -214,7 +219,29 @@ public class ExistingTemplatesComponent {
|
||||
tree.setDragEnabled(false);
|
||||
tree.setEditable(false);
|
||||
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||
tree.setTransferHandler(new TransferHandler() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected Transferable createTransferable(JComponent c) {
|
||||
final Object selection = tree.getLastSelectedPathComponent();
|
||||
if (!(selection instanceof DefaultMutableTreeNode)) {
|
||||
return null;
|
||||
}
|
||||
final DefaultMutableTreeNode node = (DefaultMutableTreeNode)selection;
|
||||
if (!(node.getUserObject() instanceof Configuration)) {
|
||||
return null;
|
||||
}
|
||||
final Configuration configuration = (Configuration)node.getUserObject();
|
||||
final Element element = new Element(configuration instanceof SearchConfiguration ? "searchConfiguration" : "replaceConfiguration");
|
||||
configuration.writeExternal(element);
|
||||
return new TextTransferable(JDOMUtil.writeElement(element));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSourceActions(JComponent c) {
|
||||
return COPY;
|
||||
}
|
||||
});
|
||||
|
||||
final TreeSpeedSearch speedSearch = new TreeSpeedSearch(
|
||||
tree,
|
||||
|
||||
+78
-16
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.event.DocumentListener;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.ide.CopyPasteManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.*;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
@@ -29,10 +30,7 @@ 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.DimensionService;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -59,14 +57,19 @@ import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.textCompletion.TextCompletionUtil;
|
||||
import com.intellij.util.ui.LafIconLookup;
|
||||
import com.intellij.util.ui.TextTransferable;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -108,6 +111,7 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
private JCheckBox myReformat; // replace
|
||||
private JCheckBox myUseStaticImport; // replace
|
||||
FileTypeSelector myFileTypesComboBox;
|
||||
ActionToolbarImpl myOptionsToolbar;
|
||||
EditorTextField mySearchCriteriaEdit;
|
||||
EditorTextField myReplaceCriteriaEdit;
|
||||
OnePixelSplitter mySearchEditorPanel;
|
||||
@@ -263,7 +267,7 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
myFileType = StructuralSearchUtil.getDefaultFileType();
|
||||
}
|
||||
|
||||
public Configuration createConfiguration(Configuration template) {
|
||||
private Configuration createConfiguration(Configuration template) {
|
||||
if (myReplace) {
|
||||
return (template == null) ? new ReplaceConfiguration(USER_DEFINED, USER_DEFINED) : new ReplaceConfiguration(template);
|
||||
}
|
||||
@@ -273,6 +277,7 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
}
|
||||
|
||||
private void setText(String text) {
|
||||
text = text.trim();
|
||||
setTextForEditor(text, mySearchCriteriaEdit);
|
||||
if (myReplace) {
|
||||
setTextForEditor(text, myReplaceCriteriaEdit);
|
||||
@@ -495,6 +500,8 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
ConfigurationManager.getInstance(getProject()).showSaveTemplateAsDialog(getConfiguration());
|
||||
}
|
||||
},
|
||||
new CopyConfigurationAction(),
|
||||
new PasteConfigurationAction(),
|
||||
new DumbAwareAction(SSRBundle.message("copy.existing.template.button")) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
@@ -533,10 +540,9 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
}
|
||||
};
|
||||
final DefaultActionGroup optionsActionGroup = new DefaultActionGroup(filterAction, templateActionGroup);
|
||||
final ActionToolbarImpl optionsToolbar =
|
||||
(ActionToolbarImpl)actionManager.createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, optionsActionGroup, true);
|
||||
optionsToolbar.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY);
|
||||
optionsToolbar.setForceMinimumSize(true);
|
||||
myOptionsToolbar = (ActionToolbarImpl)actionManager.createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, optionsActionGroup, true);
|
||||
myOptionsToolbar.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY);
|
||||
myOptionsToolbar.setForceMinimumSize(true);
|
||||
|
||||
final JPanel northPanel = new JPanel(null);
|
||||
final GroupLayout layout = new GroupLayout(northPanel);
|
||||
@@ -554,7 +560,7 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
.addComponent(fileTypeLabel)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, 5, 5)
|
||||
.addComponent(myFileTypesComboBox, 125, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(optionsToolbar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(myOptionsToolbar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
@@ -564,7 +570,7 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
.addComponent(myMatchCase)
|
||||
.addComponent(fileTypeLabel)
|
||||
.addComponent(myFileTypesComboBox)
|
||||
.addComponent(optionsToolbar)
|
||||
.addComponent(myOptionsToolbar)
|
||||
);
|
||||
|
||||
return northPanel;
|
||||
@@ -616,9 +622,9 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
|
||||
if (editor != null) {
|
||||
final SelectionModel selectionModel = editor.getSelectionModel();
|
||||
|
||||
if (selectionModel.hasSelection()) {
|
||||
setText(selectionModel.getSelectedText());
|
||||
final String selectedText = selectionModel.getSelectedText();
|
||||
if (selectedText != null && !loadConfiguration(selectedText)) {
|
||||
setText(selectedText);
|
||||
myScopePanel.setScope(null);
|
||||
setSomeText = true;
|
||||
}
|
||||
@@ -743,7 +749,7 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
return myEditConfigOnly || myScopePanel.getScope() != null;
|
||||
}
|
||||
|
||||
private void reportMessage(String message, boolean error, JComponent component) {
|
||||
void reportMessage(String message, boolean error, JComponent component) {
|
||||
com.intellij.util.ui.UIUtil.invokeLaterIfNeeded(() -> {
|
||||
component.putClientProperty("JComponent.outline", (!error || message == null) ? null : "error");
|
||||
component.repaint();
|
||||
@@ -752,7 +758,7 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
final Balloon balloon = JBPopupFactory.getInstance()
|
||||
.createHtmlTextBalloonBuilder(message, error ? MessageType.ERROR : MessageType.WARNING, null)
|
||||
.createBalloon();
|
||||
if (component == mySearchCriteriaEdit) {
|
||||
if (component != myScopePanel) {
|
||||
balloon.show(new RelativePoint(component, new Point(component.getWidth() / 2, component.getHeight())), Balloon.Position.below);
|
||||
}
|
||||
else {
|
||||
@@ -809,6 +815,32 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
boolean loadConfiguration(String text) {
|
||||
if (text == null) {
|
||||
return false;
|
||||
}
|
||||
text = text.trim();
|
||||
final Configuration configuration;
|
||||
if (text.startsWith("<searchConfiguration ") && text.endsWith("</searchConfiguration>")) {
|
||||
configuration = new SearchConfiguration();
|
||||
}
|
||||
else if (text.startsWith("<replaceConfiguration ") && text.endsWith("</replaceConfiguration>")) {
|
||||
configuration = new ReplaceConfiguration();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
final Element element = JDOMUtil.load(text);
|
||||
configuration.readExternal(element);
|
||||
loadConfiguration(configuration);
|
||||
return true;
|
||||
}
|
||||
catch (IOException | JDOMException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfiguration(Configuration configuration) {
|
||||
myConfiguration = createConfiguration(configuration);
|
||||
final MatchOptions matchOptions = myConfiguration.getMatchOptions();
|
||||
@@ -974,4 +1006,34 @@ public class StructuralSearchDialog extends DialogWrapper {
|
||||
registerCustomShortcutSet(shortcutSet, getRootPane());
|
||||
}
|
||||
}
|
||||
|
||||
private class CopyConfigurationAction extends AnAction implements DumbAware {
|
||||
|
||||
CopyConfigurationAction() {
|
||||
super("Copy Template to Clipboard");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
final Element element = new Element(myConfiguration instanceof SearchConfiguration ? "searchConfiguration" : "replaceConfiguration");
|
||||
myConfiguration.writeExternal(element);
|
||||
final TextTransferable transferable = new TextTransferable(JDOMUtil.writeElement(element));
|
||||
CopyPasteManager.getInstance().setContents(transferable);
|
||||
}
|
||||
}
|
||||
|
||||
private class PasteConfigurationAction extends AnAction implements DumbAware {
|
||||
|
||||
PasteConfigurationAction() {
|
||||
super("Paste Template from Clipboard");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
final String contents = CopyPasteManager.getInstance().getContents(DataFlavor.stringFlavor);
|
||||
if (!loadConfiguration(contents)) {
|
||||
reportMessage("No template found on the clipboard", false, myOptionsToolbar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user