PY-17265 Extracted PyBaseMoveDialog to later create new dialog for the refactoring
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Mon, 19 Oct 2015 12:22:30 +0000 (15:22 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Mon, 24 Oct 2016 21:03:49 +0000 (00:03 +0300)
python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java
python/src/com/jetbrains/python/PyBundle.properties
python/src/com/jetbrains/python/refactoring/move/PyBaseMoveDialog.java [new file with mode: 0644]
python/src/com/jetbrains/python/refactoring/move/PyMoveModuleMembersDelegate.java
python/src/com/jetbrains/python/refactoring/move/PyMoveModuleMembersDialog.form
python/src/com/jetbrains/python/refactoring/move/PyMoveModuleMembersDialog.java

index 496caeac594110556db5e78d8b0710db5cf0472e..df61f97405791a7dddb1ddbdf8682ef0d12fcd7a 100644 (file)
@@ -21,7 +21,9 @@ import com.intellij.lang.injection.InjectedLanguageManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.util.Couple;
+import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
 import com.intellij.psi.stubs.StubElement;
 import com.intellij.psi.tree.IElementType;
@@ -630,6 +632,21 @@ public class PyPsiUtils {
     return element.getContainingFile();
   }
 
+  @Nullable
+  public static String getContainingFilePath(@NotNull PsiElement element) {
+    final VirtualFile file;
+    if (element instanceof PsiFileSystemItem) {
+      file = ((PsiFileSystemItem)element).getVirtualFile();
+    }
+    else {
+      file = element.getContainingFile().getVirtualFile();
+    }
+    if (file != null) {
+      return FileUtil.toSystemDependentName(file.getPath());
+    }
+    return null;
+  }
+
   private static abstract class TopLevelVisitor extends PyRecursiveElementVisitor {
     public void visitPyElement(final PyElement node) {
       super.visitPyElement(node);
index db09df1ac8994bc1c7c559401b2a966672535152..8aa715f05933f762d188c6556161e1aa9d503590 100644 (file)
@@ -644,6 +644,9 @@ refactoring.extract.super.name.0.must.be.ident=Name ''{0}'' is invalid. Must be
 refactoring.extract.super.class.no.members.allowed=None of members could be extracted
 
 # move
+refactoring.move.choose.destination.file.title=Choose Destination File
+
+# move module members (top-level)
 refactoring.move.module.members=Move module members
 refactoring.move.module.members.dialog.title=Move Module Members
 refactoring.move.module.members.dialog.table.title=Bulk &move
@@ -651,7 +654,6 @@ refactoring.move.module.members.dialog.description.class.$0=Move class {0}
 refactoring.move.module.members.dialog.description.function.$0=Move function {0}()
 refactoring.move.module.members.dialog.description.variable.$0=Move global variable {0}
 refactoring.move.module.members.dialog.description.selection=Move selected elements
-refactoring.move.module.members.dialog.choose.destination.file.title=Choose Destination File
 refactoring.move.module.members.error.cannot.place.elements.into.nonpython.file=Cannot place elements into a non-Python file
 refactoring.move.module.members.error.destination.file.contains.class.$0=Destination file already contains class named ''{0}''
 refactoring.move.module.members.error.destination.file.contains.function.$0=Destination file already contains function named ''{0}()''
diff --git a/python/src/com/jetbrains/python/refactoring/move/PyBaseMoveDialog.java b/python/src/com/jetbrains/python/refactoring/move/PyBaseMoveDialog.java
new file mode 100644 (file)
index 0000000..ca93768
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2000-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.refactoring.move;
+
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.ui.TextComponentAccessor;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.refactoring.ui.RefactoringDialog;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.util.ui.update.UiNotifyConnector;
+import com.jetbrains.python.PyBundle;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.io.File;
+
+/**
+ * @author Mikhail Golubev
+ */
+public abstract class PyBaseMoveDialog extends RefactoringDialog {
+  protected JPanel myCenterPanel;
+  protected JPanel myExtraPanel;
+  protected TextFieldWithBrowseButton myBrowseFieldWithButton;
+  protected JBLabel myDescription;
+  protected JTextField mySourcePathField;
+
+  public PyBaseMoveDialog(Project project, @NotNull String sourcePath, @NotNull String destinationPath) {
+    super(project, true);
+    mySourcePathField.setText(sourcePath);
+    myBrowseFieldWithButton.setText(destinationPath);
+    final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor();
+    descriptor.setRoots(ProjectRootManager.getInstance(project).getContentRoots());
+    descriptor.withTreeRootVisible(true);
+    myBrowseFieldWithButton.addBrowseFolderListener(PyBundle.message("refactoring.move.choose.destination.file.title"),
+                                                    null,
+                                                    project,
+                                                    descriptor,
+                                                    TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
+  }
+
+  @Override
+  protected void init() {
+    UiNotifyConnector.doWhenFirstShown(myCenterPanel, new Runnable() {
+      @Override
+      public void run() {
+        doWhenFirstShown();
+      }
+    });
+    super.init();
+  }
+
+  protected void doWhenFirstShown() {
+    preselectLastPathComponent(myBrowseFieldWithButton.getTextField());
+  }
+
+  protected static void preselectLastPathComponent(@NotNull JTextField field) {
+    final String text = field.getText();
+    final int start = text.lastIndexOf(File.separatorChar);
+    final int lastDotIndex = text.lastIndexOf('.');
+    final int end = lastDotIndex < 0 ? text.length() : lastDotIndex;
+    if (start + 1 < end) {
+      field.select(start + 1, end);
+    }
+  }
+
+  @Override
+  protected abstract String getHelpId();
+
+  @Nullable
+  @Override
+  protected abstract String getDimensionServiceKey();
+
+  @Nullable
+  @Override
+  protected JComponent createCenterPanel() {
+    return myCenterPanel;
+  }
+
+  @Override
+  protected void doAction() {
+    close(OK_EXIT_CODE);
+  }
+
+  @Override
+  public JComponent getPreferredFocusedComponent() {
+    return myBrowseFieldWithButton.getTextField();
+  }
+
+  @NotNull
+  public String getTargetPath() {
+    return myBrowseFieldWithButton.getText();
+  }
+}
index dce1166265e66a7e7c817923aa670983cd92598e..b9aa2ed1590fde6ad5ec98e5221929e7344bd604 100644 (file)
@@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Condition;
 import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
 import com.intellij.refactoring.BaseRefactoringProcessor;
@@ -36,6 +37,7 @@ import com.intellij.util.containers.ContainerUtil;
 import com.jetbrains.python.PyBundle;
 import com.jetbrains.python.psi.PyElement;
 import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.impl.PyPsiUtils;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -68,14 +70,17 @@ public class PyMoveModuleMembersDelegate extends MoveHandlerDelegate {
       }
       initialElements.add(e);
     }
-    String initialDestination = null;
+    String initialPath = null;
     if (targetContainer instanceof PsiFile) {
       final VirtualFile virtualFile = ((PsiFile)targetContainer).getVirtualFile();
       if (virtualFile != null) {
-        initialDestination = FileUtil.toSystemDependentName(virtualFile.getPath());
+        initialPath = FileUtil.toSystemDependentName(virtualFile.getPath());
       }
     }
-    final PyMoveModuleMembersDialog dialog = PyMoveModuleMembersDialog.getInstance(project, initialElements, initialDestination);
+    if (initialPath == null) {
+      initialPath = StringUtil.notNullize(PyPsiUtils.getContainingFilePath(elements[0]));
+    }
+    final PyMoveModuleMembersDialog dialog = PyMoveModuleMembersDialog.getInstance(project, initialElements, initialPath, initialPath);
     if (!dialog.showAndGet()) {
       return;
     }
index e4bd6399755e0f358f6b5e19a1403179b356fc9e..77f1d3c693ccbcfbaf5609a4622e39d12a8a2c64 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.refactoring.move.PyMoveModuleMembersDialog">
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.refactoring.move.PyBaseMoveDialog">
   <grid id="27dc6" binding="myCenterPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
     <margin top="5" left="5" bottom="5" right="5"/>
     <constraints>
@@ -25,7 +25,7 @@
         </constraints>
         <properties/>
       </component>
-      <grid id="37e2f" binding="myTablePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
+      <grid id="37e2f" binding="myExtraPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
         <constraints>
           <grid row="3" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
         </constraints>
index a458adc26d3f1567c7cfc8efd850cf8880ae2fb0..4e19705a4c29e7ce788fba7f3aa15c9b07492b57 100644 (file)
 package com.jetbrains.python.refactoring.move;
 
 import com.intellij.ide.util.PropertiesComponent;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ProjectRootManager;
 import com.intellij.openapi.ui.DialogWrapperPeer;
-import com.intellij.openapi.ui.TextComponentAccessor;
-import com.intellij.openapi.ui.TextFieldWithBrowseButton;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiNamedElement;
 import com.intellij.refactoring.classMembers.MemberInfoChange;
 import com.intellij.refactoring.classMembers.MemberInfoModel;
 import com.intellij.refactoring.ui.AbstractMemberSelectionTable;
-import com.intellij.refactoring.ui.RefactoringDialog;
 import com.intellij.ui.HideableDecorator;
 import com.intellij.ui.RowIcon;
-import com.intellij.ui.components.JBLabel;
 import com.intellij.ui.components.JBScrollPane;
 import com.intellij.util.Function;
 import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.ui.update.UiNotifyConnector;
 import com.jetbrains.python.PyBundle;
 import com.jetbrains.python.psi.PyClass;
 import com.jetbrains.python.psi.PyElement;
@@ -53,7 +42,6 @@ import javax.swing.*;
 import javax.swing.event.TableModelEvent;
 import javax.swing.event.TableModelListener;
 import java.awt.*;
-import java.io.File;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
@@ -61,7 +49,7 @@ import java.util.List;
 /**
  * @author Mikhail Golubev
  */
-public class PyMoveModuleMembersDialog extends RefactoringDialog {
+public class PyMoveModuleMembersDialog extends PyBaseMoveDialog {
   @NonNls private final static String BULK_MOVE_TABLE_VISIBLE = "python.move.module.members.dialog.show.table";
 
   /**
@@ -72,11 +60,6 @@ public class PyMoveModuleMembersDialog extends RefactoringDialog {
   private final TopLevelSymbolsSelectionTable myMemberSelectionTable;
   private final PyModuleMemberInfoModel myModuleMemberModel;
   private final boolean mySeveralElementsSelected;
-  private JPanel myCenterPanel;
-  private JPanel myTablePanel;
-  private TextFieldWithBrowseButton myBrowseFieldWithButton;
-  private JBLabel myDescription;
-  private JTextField mySourcePathField;
 
   /**
    * Either creates new dialog or return singleton instance initialized with {@link #setInstanceToReplace)}.
@@ -84,13 +67,14 @@ public class PyMoveModuleMembersDialog extends RefactoringDialog {
    *
    * @param project dialog project
    * @param elements elements to move
-   * @param destination destination where elements have to be moved
-   * @return dialog
+   * @param source
+   *@param destination destination where elements have to be moved  @return dialog
    */
-  public static PyMoveModuleMembersDialog getInstance(@NotNull final Project project,
-                                                       @NotNull final List<PsiNamedElement> elements,
-                                                       @Nullable final String destination) {
-    return ourInstanceToReplace != null ? ourInstanceToReplace : new PyMoveModuleMembersDialog(project, elements, destination);
+  public static PyMoveModuleMembersDialog getInstance(@NotNull Project project,
+                                                      @NotNull List<PsiNamedElement> elements,
+                                                      @NotNull String source, 
+                                                      @NotNull String destination) {
+    return ourInstanceToReplace != null ? ourInstanceToReplace : new PyMoveModuleMembersDialog(project, elements, source, destination);
   }
 
   /**
@@ -106,30 +90,19 @@ public class PyMoveModuleMembersDialog extends RefactoringDialog {
   /**
    * @param project dialog project
    * @param elements elements to move
+   * @param source
    * @param destination destination where elements have to be moved
    */
-  protected PyMoveModuleMembersDialog(@NotNull Project project, @NotNull final List<PsiNamedElement> elements, @Nullable String destination) {
-    super(project, true);
+  protected PyMoveModuleMembersDialog(@NotNull Project project,
+                                      @NotNull List<PsiNamedElement> elements,
+                                      @NotNull String source, 
+                                      @NotNull String destination) {
+    super(project, source, destination);
 
     assert !elements.isEmpty();
     final PsiNamedElement firstElement = elements.get(0);
     setTitle(PyBundle.message("refactoring.move.module.members.dialog.title"));
 
-    final String sourceFilePath = getContainingFileName(firstElement);
-    mySourcePathField.setText(sourceFilePath);
-    if (destination == null) {
-      destination = sourceFilePath;
-    }
-    myBrowseFieldWithButton.setText(destination);
-    final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor();
-    descriptor.setRoots(ProjectRootManager.getInstance(project).getContentRoots());
-    descriptor.withTreeRootVisible(true);
-    myBrowseFieldWithButton.addBrowseFolderListener(PyBundle.message("refactoring.move.module.members.dialog.choose.destination.file.title"),
-                                                    null,
-                                                    project,
-                                                    descriptor,
-                                                    TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
-
     final PyFile pyFile = (PyFile)firstElement.getContainingFile();
     myModuleMemberModel = new PyModuleMemberInfoModel(pyFile);
 
@@ -165,7 +138,7 @@ public class PyMoveModuleMembersDialog extends RefactoringDialog {
       description = PyBundle.message("refactoring.move.module.members.dialog.description.selection");
     }
     myDescription.setText(description);
-    final HideableDecorator decorator = new HideableDecorator(myTablePanel, PyBundle.message("refactoring.move.module.members.dialog.table.title"), true) {
+    final HideableDecorator decorator = new HideableDecorator(myExtraPanel, PyBundle.message("refactoring.move.module.members.dialog.table.title"), true) {
       @Override
       protected void on() {
         super.on();
@@ -188,13 +161,15 @@ public class PyMoveModuleMembersDialog extends RefactoringDialog {
       }
     });
 
-    UiNotifyConnector.doWhenFirstShown(myCenterPanel, () -> {
-      enlargeDialogHeightIfNecessary();
-      preselectLastPathComponent(myBrowseFieldWithButton.getTextField());
-    });
     init();
   }
 
+  @Override
+  protected void doWhenFirstShown() {
+    super.doWhenFirstShown();
+    enlargeDialogHeightIfNecessary();
+  }
+  
   private void enlargeDialogHeightIfNecessary() {
     if (mySeveralElementsSelected && !PropertiesComponent.getInstance(getProject()).getBoolean(BULK_MOVE_TABLE_VISIBLE)) {
       final DialogWrapperPeer peer = getPeer();
@@ -206,53 +181,22 @@ public class PyMoveModuleMembersDialog extends RefactoringDialog {
     }
   }
 
-  private static void preselectLastPathComponent(@NotNull JTextField field) {
-    final String text = field.getText();
-    final int start = text.lastIndexOf(File.separatorChar);
-    final int lastDotIndex = text.lastIndexOf('.');
-    final int end = lastDotIndex < 0 ? text.length() : lastDotIndex;
-    if (start + 1 < end) {
-      field.select(start + 1, end);
-    }
-  }
-
   @Nullable
   @Override
   protected String getDimensionServiceKey() {
     return "#com.jetbrains.python.refactoring.move.PyMoveModuleMembersDialog";
   }
 
-  @Nullable
-  @Override
-  protected JComponent createCenterPanel() {
-    return myCenterPanel;
-  }
-
-  @Override
-  protected void doAction() {
-    close(OK_EXIT_CODE);
-  }
-
   @Override
   protected String getHelpId() {
     return "python.reference.moveModuleMembers";
   }
 
-  @Override
-  public JComponent getPreferredFocusedComponent() {
-    return myBrowseFieldWithButton.getTextField();
-  }
-
   @Override
   protected boolean areButtonsValid() {
     return !myMemberSelectionTable.getSelectedMemberInfos().isEmpty();
   }
 
-  @NotNull
-  public String getTargetPath() {
-    return myBrowseFieldWithButton.getText();
-  }
-
   /**
    * @return selected elements in the same order as they are declared in the original file
    */
@@ -269,17 +213,6 @@ public class PyMoveModuleMembersDialog extends RefactoringDialog {
     return ContainerUtil.mapNotNull(moduleMembers, element -> new PyModuleMemberInfo(element));
   }
 
-  @NotNull
-  private static String getContainingFileName(@NotNull PsiElement element) {
-    final VirtualFile file = element.getContainingFile().getVirtualFile();
-    if (file != null) {
-      return FileUtil.toSystemDependentName(file.getPath());
-    }
-    else {
-      return "";
-    }
-  }
-
   static class TopLevelSymbolsSelectionTable extends AbstractMemberSelectionTable<PyElement, PyModuleMemberInfo> {
     public TopLevelSymbolsSelectionTable(Collection<PyModuleMemberInfo> memberInfos,
                                          @Nullable MemberInfoModel<PyElement, PyModuleMemberInfo> memberInfoModel) {