package liveplugin.toolwindow; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileChooser.FileElement; import com.intellij.openapi.fileChooser.FileSystemTree; import com.intellij.openapi.fileChooser.actions.FileChooserAction; import com.intellij.openapi.fileChooser.ex.FileNodeDescriptor; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import liveplugin.IDEUtil; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeModel; import java.io.IOException; import java.util.LinkedList; import java.util.Queue; public class RenameFileAction extends FileChooserAction { @Override protected void actionPerformed(final FileSystemTree fileSystemTree, final AnActionEvent event) { final VirtualFile file = fileSystemTree.getSelectedFile(); if (file == null) return; String defaultName = file.getName(); final String newFileName = Messages.showInputDialog("Rename file to:", "Rename", null, defaultName, null); if (newFileName == null || newFileName.equals(file.getName())) return; ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { try { file.rename(null, newFileName); updateTreeModel_HACK(); } catch (IOException e) { IDEUtil.showErrorDialog(event.getProject(), "Couldn't rename " + file.getName() + " to " + newFileName, "Error"); } } /** * Couldn't find any way to update file chooser tree to show new file name, therefore this hack. * There is still a problem with this except that it's a hack. * If new file name is longer than previous name, it's not shown fully. * The workaround is to collapse, expand parent tree node. */ private void updateTreeModel_HACK() { TreeModel model = fileSystemTree.getTree().getModel(); Queue<DefaultMutableTreeNode> queue = new LinkedList<>(); DefaultMutableTreeNode node = (DefaultMutableTreeNode) model.getRoot(); queue.add(node); while (!queue.isEmpty()) { node = queue.remove(); final Object userObject = node.getUserObject(); boolean nodeContainsRenamedFile = userObject instanceof FileNodeDescriptor && file.equals(((FileNodeDescriptor) userObject).getElement().getFile()); if (nodeContainsRenamedFile) { final DefaultMutableTreeNode finalNode = node; SwingUtilities.invokeLater(() -> { FileNodeDescriptor nodeDescriptor = (FileNodeDescriptor) userObject; FileElement fileElement = new FileElement(file, newFileName); fileElement.setParent(nodeDescriptor.getElement().getParent()); finalNode.setUserObject(new FileNodeDescriptor( nodeDescriptor.getProject(), fileElement, nodeDescriptor.getParentDescriptor(), nodeDescriptor.getIcon(), newFileName, nodeDescriptor.getComment() )); }); return; } for (int i = 0; i < model.getChildCount(node); i++) { queue.add((DefaultMutableTreeNode) model.getChild(node, i)); } } } }); } @Override protected void update(FileSystemTree fileChooser, AnActionEvent e) { e.getPresentation().setVisible(true); e.getPresentation().setEnabled(fileChooser.selectionExists()); } }