private void updatePathFromTree(final List<VirtualFile> selection, boolean now) {
    if (!isToShowTextField() || myTreeIsUpdating) return;

    String text = "";
    if (selection.size() > 0) {
      text = VfsUtil.getReadableUrl(selection.get(0));
    } else {
      final List<VirtualFile> roots = myChooserDescriptor.getRoots();
      if (!myFileSystemTree.getTree().isRootVisible() && roots.size() == 1) {
        text = VfsUtil.getReadableUrl(roots.get(0));
      }
    }

    myPathTextField.setText(
        text,
        now,
        () -> {
          myPathTextField.getField().selectAll();
          setErrorText(null);
        });
  }
 private void showRecentFilesPopup() {
   final JBList files =
       new JBList(getRecentFiles()) {
         @Override
         public Dimension getPreferredSize() {
           return new Dimension(
               myPathTextField.getField().getWidth(), super.getPreferredSize().height);
         }
       };
   files.setCellRenderer(
       new ColoredListCellRenderer() {
         @Override
         protected void customizeCellRenderer(
             @NotNull JList list, Object value, int index, boolean selected, boolean hasFocus) {
           final String path = value.toString();
           append(path);
           final VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(path));
           if (file != null) {
             setIcon(IconUtil.getIcon(file, Iconable.ICON_FLAG_READ_STATUS, null));
           }
         }
       });
   JBPopupFactory.getInstance()
       .createListPopupBuilder(files)
       .setItemChoosenCallback(
           () -> myPathTextField.getField().setText(files.getSelectedValue().toString()))
       .createPopup()
       .showUnderneathOf(myPathTextField.getField());
 }
  private void updateTreeFromPath(final String text) {
    if (!isToShowTextField()) return;
    if (myPathTextField.isPathUpdating()) return;
    if (text == null) return;

    myUiUpdater.queue(
        new Update("treeFromPath.1") {
          public void run() {
            ApplicationManager.getApplication()
                .executeOnPooledThread(
                    new Runnable() {
                      public void run() {
                        final LocalFsFinder.VfsFile toFind =
                            (LocalFsFinder.VfsFile) myPathTextField.getFile();
                        if (toFind == null || !toFind.exists()) return;

                        myUiUpdater.queue(
                            new Update("treeFromPath.2") {
                              public void run() {
                                selectInTree(toFind.getFile(), text);
                              }
                            });
                      }
                    });
          }
        });
  }
  private VirtualFile[] getSelectedFilesInt() {
    if (myTreeIsUpdating || !myUiUpdater.isEmpty()) {
      if (isTextFieldActive() && !StringUtil.isEmpty(myPathTextField.getTextFieldText())) {
        LookupFile toFind = myPathTextField.getFile();
        if (toFind instanceof LocalFsFinder.VfsFile && toFind.exists()) {
          VirtualFile file = ((LocalFsFinder.VfsFile) toFind).getFile();
          if (file != null) {
            return new VirtualFile[] {file};
          }
        }
      }
      return VirtualFile.EMPTY_ARRAY;
    }

    return myFileSystemTree.getSelectedFiles();
  }
 public JComponent getPreferredFocusedComponent() {
   if (isToShowTextField()) {
     return myPathTextField != null ? myPathTextField.getField() : null;
   } else {
     return myFileSystemTree != null ? myFileSystemTree.getTree() : null;
   }
 }
 private void selectInTree(final VirtualFile vFile, String fromText) {
   if (vFile != null && vFile.isValid()) {
     if (fromText == null || fromText.equalsIgnoreCase(myPathTextField.getTextFieldText())) {
       selectInTree(new VirtualFile[] {vFile}, false);
     }
   } else {
     reportFileNotFound();
   }
 }
 @NotNull
 private String[] getRecentFiles() {
   final String[] recent = PropertiesComponent.getInstance().getValues(RECENT_FILES_KEY);
   if (recent != null) {
     if (recent.length > 0
         && myPathTextField.getField().getText().replace('\\', '/').equals(recent[0])) {
       final String[] pathes = new String[recent.length - 1];
       System.arraycopy(recent, 1, pathes, 0, recent.length - 1);
       return pathes;
     }
     return recent;
   }
   return ArrayUtil.EMPTY_STRING_ARRAY;
 }
  protected void doOKAction() {
    if (!isOKActionEnabled()) {
      return;
    }

    if (isTextFieldActive()) {
      final String text = myPathTextField.getTextFieldText();
      final LookupFile file = myPathTextField.getFile();
      if (text == null || file == null || !file.exists()) {
        setErrorText("Specified path cannot be found");
        return;
      }
    }

    final List<VirtualFile> selectedFiles = Arrays.asList(getSelectedFilesInt());
    final VirtualFile[] files =
        VfsUtilCore.toVirtualFileArray(
            FileChooserUtil.getChosenFiles(myChooserDescriptor, selectedFiles));
    if (files.length == 0) {
      myChosenFiles = VirtualFile.EMPTY_ARRAY;
      close(CANCEL_EXIT_CODE);
      return;
    }

    try {
      myChooserDescriptor.validateSelectedFiles(files);
    } catch (Exception e) {
      Messages.showErrorDialog(getContentPane(), e.getMessage(), getTitle());
      return;
    }

    myChosenFiles = files;
    storeSelection(files[files.length - 1]);

    super.doOKAction();
  }
  private void updateTextFieldShowing() {
    myTextFieldAction.update();
    myNorthPanel.remove(myPathTextFieldWrapper);
    if (isToShowTextField()) {
      final ArrayList<VirtualFile> selection = new ArrayList<VirtualFile>();
      if (myFileSystemTree.getSelectedFile() != null) {
        selection.add(myFileSystemTree.getSelectedFile());
      }
      updatePathFromTree(selection, true);
      myNorthPanel.add(myPathTextFieldWrapper, BorderLayout.CENTER);
    } else {
      setErrorText(null);
    }
    myPathTextField.getField().requestFocus();

    myNorthPanel.revalidate();
    myNorthPanel.repaint();
  }
  protected JComponent createHistoryButton() {
    JLabel label = new JLabel(AllIcons.Actions.Get);
    label.setToolTipText("Recent files");
    new ClickListener() {
      @Override
      public boolean onClick(@NotNull MouseEvent event, int clickCount) {
        showRecentFilesPopup();
        return true;
      }
    }.installOn(label);

    new AnAction() {
      @Override
      public void actionPerformed(AnActionEvent e) {
        showRecentFilesPopup();
      }

      @Override
      public void update(AnActionEvent e) {
        e.getPresentation().setEnabled(!IdeEventQueue.getInstance().isPopupActive());
      }
    }.registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, myPathTextField.getField());
    return label;
  }
 private boolean isTextFieldActive() {
   return myPathTextField.getField().getRootPane() != null;
 }
  protected JComponent createCenterPanel() {
    JPanel panel = new MyPanel();

    myUiUpdater = new MergingUpdateQueue("FileChooserUpdater", 200, false, panel);
    Disposer.register(myDisposable, myUiUpdater);
    new UiNotifyConnector(panel, myUiUpdater);

    panel.setBorder(JBUI.Borders.empty());

    createTree();

    final DefaultActionGroup group = createActionGroup();
    ActionToolbar toolBar =
        ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true);
    toolBar.setTargetComponent(panel);

    final JPanel toolbarPanel = new JPanel(new BorderLayout());
    toolbarPanel.add(toolBar.getComponent(), BorderLayout.CENTER);

    myTextFieldAction =
        new TextFieldAction() {
          public void linkSelected(final LinkLabel aSource, final Object aLinkData) {
            toggleShowTextField();
          }
        };
    toolbarPanel.add(myTextFieldAction, BorderLayout.EAST);

    myPathTextFieldWrapper = new JPanel(new BorderLayout());
    myPathTextFieldWrapper.setBorder(JBUI.Borders.emptyBottom(2));
    myPathTextField =
        new FileTextFieldImpl.Vfs(
            FileChooserFactoryImpl.getMacroMap(),
            getDisposable(),
            new LocalFsFinder.FileChooserFilter(myChooserDescriptor, myFileSystemTree)) {
          protected void onTextChanged(final String newValue) {
            myUiUpdater.cancelAllUpdates();
            updateTreeFromPath(newValue);
          }
        };
    Disposer.register(myDisposable, myPathTextField);
    myPathTextFieldWrapper.add(myPathTextField.getField(), BorderLayout.CENTER);
    if (getRecentFiles().length > 0) {
      myPathTextFieldWrapper.add(createHistoryButton(), BorderLayout.EAST);
    }

    myNorthPanel = new JPanel(new BorderLayout());
    myNorthPanel.add(toolbarPanel, BorderLayout.NORTH);

    updateTextFieldShowing();

    panel.add(myNorthPanel, BorderLayout.NORTH);

    registerMouseListener(group);

    JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myFileSystemTree.getTree());
    // scrollPane.setBorder(BorderFactory.createLineBorder(new Color(148, 154, 156)));
    panel.add(scrollPane, BorderLayout.CENTER);
    panel.setPreferredSize(JBUI.size(400));

    panel.add(
        new JLabel(
            "<html><center><small><font color=gray>Drag and drop a file into the space above to quickly locate it in the tree.</font></small></center></html>",
            SwingConstants.CENTER),
        BorderLayout.SOUTH);

    ApplicationManager.getApplication()
        .getMessageBus()
        .connect(getDisposable())
        .subscribe(
            ApplicationActivationListener.TOPIC,
            new ApplicationActivationListener.Adapter() {
              @Override
              public void applicationActivated(IdeFrame ideFrame) {
                ((SaveAndSyncHandlerImpl) SaveAndSyncHandler.getInstance())
                    .maybeRefresh(ModalityState.current());
              }
            });

    return panel;
  }
  public FileTextFieldImpl(
      final JTextField field,
      Finder finder,
      LookupFilter filter,
      Map<String, String> macroMap,
      final Disposable parent) {
    myPathTextField = field;
    myMacroMap = new TreeMap<String, String>();
    myMacroMap.putAll(macroMap);

    final InputMap listMap = (InputMap) UIManager.getDefaults().get("List.focusInputMap");
    final KeyStroke[] listKeys = listMap.keys();
    myDisabledTextActions = new HashSet<Action>();
    for (KeyStroke eachListStroke : listKeys) {
      final String listActionID = (String) listMap.get(eachListStroke);
      if ("selectNextRow".equals(listActionID) || "selectPreviousRow".equals(listActionID)) {
        final Object textActionID = field.getInputMap().get(eachListStroke);
        if (textActionID != null) {
          final Action textAction = field.getActionMap().get(textActionID);
          if (textAction != null) {
            myDisabledTextActions.add(textAction);
          }
        }
      }
    }

    final FileTextFieldImpl assigned = (FileTextFieldImpl) myPathTextField.getClientProperty(KEY);
    if (assigned != null) {
      assigned.myFinder = finder;
      assigned.myFilter = filter;
      return;
    }

    myPathTextField.putClientProperty(KEY, this);
    final boolean headless = ApplicationManager.getApplication().isUnitTestMode();

    myUiUpdater = new MergingUpdateQueue("FileTextField.UiUpdater", 200, false, myPathTextField);
    if (!headless) {
      new UiNotifyConnector(myPathTextField, myUiUpdater);
    }

    myFinder = finder;
    myFilter = filter;

    myFileSpitRegExp = myFinder.getSeparator().replaceAll("\\\\", "\\\\\\\\");

    myPathTextField
        .getDocument()
        .addDocumentListener(
            new DocumentListener() {
              public void insertUpdate(final DocumentEvent e) {
                processTextChanged();
              }

              public void removeUpdate(final DocumentEvent e) {
                processTextChanged();
              }

              public void changedUpdate(final DocumentEvent e) {
                processTextChanged();
              }
            });

    myPathTextField.addKeyListener(
        new KeyAdapter() {
          public void keyPressed(final KeyEvent e) {
            processListSelection(e);
          }
        });

    myPathTextField.addFocusListener(
        new FocusAdapter() {
          public void focusLost(final FocusEvent e) {
            closePopup();
          }
        });

    myCancelAction = new CancelAction();

    new LazyUiDisposable<FileTextFieldImpl>(parent, field, this) {
      protected void initialize(
          @NotNull Disposable parent, @NotNull FileTextFieldImpl child, @Nullable Project project) {
        Disposer.register(child, myUiUpdater);
      }
    };
  }