blob: cd49d6bff01ea06533fcec7a1323b3b24cdf94a5 [file] [log] [blame]
/*
* 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.
*/
package com.intellij.cvsSupport2.ui.experts;
import com.intellij.cvsSupport2.config.CvsApplicationLevelConfiguration;
import com.intellij.cvsSupport2.util.CvsVfsUtil;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.treeView.NodeRenderer;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileSystemTree;
import com.intellij.openapi.fileChooser.FileSystemTreeFactory;
import com.intellij.openapi.fileChooser.ex.FileDrop;
import com.intellij.openapi.fileChooser.ex.FileTextFieldImpl;
import com.intellij.openapi.fileChooser.ex.LocalFsFinder;
import com.intellij.openapi.fileChooser.impl.FileChooserFactoryImpl;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.UiNotifyConnector;
import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import java.awt.*;
import java.io.File;
import java.util.List;
/**
* @author lesya
*/
public abstract class SelectLocationStep extends WizardStep {
protected final FileSystemTree myFileSystemTree;
private final FileTextFieldImpl myPathTextField;
private final JPanel myNorthPanel = new JPanel(new BorderLayout());
private final JComponent myPathTextFieldWrapper;
private final TextFieldAction myTextFieldAction;
private ActionToolbar myFileSystemToolBar;
private VirtualFile mySelectedFile;
private boolean myShowPath = CvsApplicationLevelConfiguration.getInstance().SHOW_PATH;
private MergingUpdateQueue myUiUpdater;
private final TreeSelectionListener myTreeSelectionListener = new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
updatePathFromTree(myFileSystemTree.getSelectedFile(), false);
getWizard().updateStep();
}
};
private final FileChooserDescriptor myChooserDescriptor;
private boolean myTreeIsUpdating = false;
public SelectLocationStep(String description, CvsWizard wizard, @Nullable final Project project, boolean showFiles) {
super(description, wizard);
myChooserDescriptor = new FileChooserDescriptor(showFiles, true, false, false, false, true);
myFileSystemTree = FileSystemTreeFactory.SERVICE.getInstance().createFileSystemTree(project, myChooserDescriptor);
myFileSystemTree.updateTree();
myPathTextField = new FileTextFieldImpl.Vfs(
FileChooserFactoryImpl.getMacroMap(), myFileSystemTree,
new LocalFsFinder.FileChooserFilter(myChooserDescriptor, myFileSystemTree)) {
protected void onTextChanged(final String newValue) {
updateTreeFromPath(newValue);
}
};
myPathTextFieldWrapper = new JPanel(new BorderLayout());
myPathTextFieldWrapper.setBorder(new EmptyBorder(0, 0, 2, 0));
myPathTextFieldWrapper.add(myPathTextField.getField(), BorderLayout.CENTER);
myTextFieldAction = new TextFieldAction();
}
protected void init() {
final DefaultActionGroup fileSystemActionGroup = createFileSystemActionGroup();
myFileSystemToolBar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, fileSystemActionGroup, true);
final JTree tree = myFileSystemTree.getTree();
tree.getSelectionModel().addTreeSelectionListener(myTreeSelectionListener);
tree.setCellRenderer(new NodeRenderer());
tree.addMouseListener(new PopupHandler() {
public void invokePopup(Component comp, int x, int y) {
final ActionPopupMenu popupMenu =
ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UPDATE_POPUP, fileSystemActionGroup);
popupMenu.getComponent().show(comp, x, y);
}
});
tree.addSelectionPath(tree.getPathForRow(0));
new FileDrop(tree, new FileDrop.Target() {
public FileChooserDescriptor getDescriptor() {
return myChooserDescriptor;
}
public boolean isHiddenShown() {
return myFileSystemTree.areHiddensShown();
}
public void dropFiles(final List<VirtualFile> files) {
if (files.size() > 0) {
selectInTree(files.toArray(new VirtualFile[files.size()]));
}
}
});
super.init();
}
protected JComponent createComponent() {
final JPanel panel = new MyPanel();
final JPanel toolbarPanel = new JPanel(new GridBagLayout());
final GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 0;
toolbarPanel.add(myFileSystemToolBar.getComponent(), constraints);
constraints.gridx = 1;
constraints.weightx = 1.0;
constraints.anchor = GridBagConstraints.EAST;
toolbarPanel.add(myTextFieldAction, constraints);
myNorthPanel.add(toolbarPanel, BorderLayout.NORTH);
panel.add(myNorthPanel, BorderLayout.NORTH);
panel.add(ScrollPaneFactory.createScrollPane(myFileSystemTree.getTree()), BorderLayout.CENTER);
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);
myUiUpdater = new MergingUpdateQueue("FileChooserUpdater", 200, false, panel);
Disposer.register(myFileSystemTree, myUiUpdater);
new UiNotifyConnector(panel, myUiUpdater);
updateTextFieldShowing();
return panel;
}
protected void dispose() {
mySelectedFile = myFileSystemTree.getSelectedFile(); // remember the file - it will be requested after dispose
myFileSystemTree.getTree().getSelectionModel().removeTreeSelectionListener(myTreeSelectionListener);
Disposer.dispose(myFileSystemTree);
}
public boolean nextIsEnabled() {
final VirtualFile[] selectedFiles = myFileSystemTree.getSelectedFiles();
return selectedFiles.length == 1 && selectedFiles[0].isDirectory();
}
private DefaultActionGroup createFileSystemActionGroup() {
final DefaultActionGroup group = FileSystemTreeFactory.SERVICE.getInstance().createDefaultFileSystemActions(myFileSystemTree);
final AnAction[] actions = getActions();
if (actions.length > 0) group.addSeparator();
for (AnAction action : actions) {
group.add(action);
}
return group;
}
protected AnAction[] getActions(){
return AnAction.EMPTY_ARRAY;
}
public File getSelectedFile() {
if (mySelectedFile != null) {
return CvsVfsUtil.getFileFor(mySelectedFile);
}
return CvsVfsUtil.getFileFor(myFileSystemTree.getSelectedFile());
}
public JComponent getPreferredFocusedComponent() {
return myFileSystemTree.getTree();
}
private void updateTreeFromPath(final String text) {
if (!myShowPath) 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 void selectInTree(final VirtualFile vFile, String fromText) {
myTreeIsUpdating = true;
if (vFile == null || !vFile.isValid()) {
return;
}
if (fromText == null || fromText.equalsIgnoreCase(myPathTextField.getTextFieldText())) {
selectInTree(new VirtualFile[]{vFile});
}
myTreeIsUpdating = false;
}
private void selectInTree(VirtualFile[] vFiles) {
if (vFiles.length == 0) return;
myFileSystemTree.select(vFiles, null);
}
public void toggleShowTextField() {
myShowPath = !myShowPath;
CvsApplicationLevelConfiguration.getInstance().SHOW_PATH = myShowPath;
updateTextFieldShowing();
}
private void updateTextFieldShowing() {
myTextFieldAction.update();
myNorthPanel.remove(myPathTextFieldWrapper);
if (myShowPath) {
updatePathFromTree(myFileSystemTree.getSelectedFile(), true);
myNorthPanel.add(myPathTextFieldWrapper, BorderLayout.SOUTH);
}
myPathTextField.getField().requestFocus();
myNorthPanel.revalidate();
myNorthPanel.repaint();
}
private void updatePathFromTree(VirtualFile selection, boolean now) {
if (!myShowPath || myTreeIsUpdating) return;
String text = "";
if (selection != null) {
if (selection.isInLocalFileSystem()) {
text = selection.getPresentableUrl();
}
else {
text = selection.getUrl();
}
}
else {
final List<VirtualFile> roots = myChooserDescriptor.getRoots();
if (!myFileSystemTree.getTree().isRootVisible() && roots.size() == 1) {
text = VfsUtil.getReadableUrl(roots.get(0));
}
}
myPathTextField.setText(text, now, new Runnable() {
public void run() {
myPathTextField.getField().selectAll();
}
});
}
private class MyPanel extends JPanel implements TypeSafeDataProvider {
private MyPanel() {
super(new BorderLayout());
}
public void calcData(final DataKey key, final DataSink sink) {
if (key == CommonDataKeys.VIRTUAL_FILE_ARRAY) {
sink.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, myFileSystemTree.getSelectedFiles());
}
else if (key == FileSystemTree.DATA_KEY) {
sink.put(FileSystemTree.DATA_KEY, myFileSystemTree);
}
}
}
private class TextFieldAction extends LinkLabel implements LinkListener {
public TextFieldAction() {
super("", null);
setListener(this, null);
update();
}
protected void onSetActive(final boolean active) {
final String tooltip = KeymapUtil.createTooltipText(ActionsBundle.message("action.FileChooser.TogglePathShowing.text"),
ActionManager.getInstance().getAction("FileChooser.TogglePathShowing"));
setToolTipText(tooltip);
}
protected String getStatusBarText() {
return ActionsBundle.message("action.FileChooser.TogglePathShowing.text");
}
public void update() {
setVisible(true);
setText(myShowPath ? IdeBundle.message("file.chooser.hide.path") : IdeBundle.message("file.chooser.show.path"));
}
public void linkSelected(final LinkLabel aSource, final Object aLinkData) {
toggleShowTextField();
}
}
}