package com.google.jstestdriver.idea.assertFramework.support; import com.google.common.base.Supplier; import com.google.common.collect.Lists; import com.google.jstestdriver.idea.util.SwingUtils; import com.google.jstestdriver.idea.util.TextChangeListener; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.List; /* * All operations should be executed on EDT. */ class ExtractDirectoryTypeManager { private final Project myProject; private final JPanel myDirectoryTypeContent; private final String myAssertionFrameworkName; private final File myDefaultDir; private final List<ChangeListener> myChangeListeners = Lists.newArrayList(); private TextFieldWithBrowseButton myCustomDirectoryTextFieldWithBrowseButton; private DirectoryType mySelectedDirectoryType; private ExtractDirectoryTypeManager(Project project, JPanel directoryTypeContent, String assertionFrameworkName) { myProject = project; myDirectoryTypeContent = directoryTypeContent; myAssertionFrameworkName = assertionFrameworkName; myDefaultDir = getDefaultDir(assertionFrameworkName); } private void populate(JRadioButton defaultRadioButton, JRadioButton customRadioButton) { addContentForExtractDirecoryType(defaultRadioButton, DirectoryType.DEFAULT, new Supplier<JPanel>() { @Override public JPanel get() { JPanel defaultDirectoryTypePanel = new JPanel(new BorderLayout()); defaultDirectoryTypePanel.add(new JLabel(myDefaultDir.getPath()), BorderLayout.WEST); return defaultDirectoryTypePanel; } }); addContentForExtractDirecoryType(customRadioButton, DirectoryType.CUSTOM, new Supplier<JPanel>() { @Override public JPanel get() { FileChooserDescriptor fileChooserDescriptor = new FileChooserDescriptor(false, true, false, false, false, false); String adapterName = myAssertionFrameworkName + " adapter"; String title = "Select a folder for " + adapterName; String description = adapterName + " source files will be extracted into the selected folder"; myCustomDirectoryTextFieldWithBrowseButton = new TextFieldWithBrowseButton(); myCustomDirectoryTextFieldWithBrowseButton.addBrowseFolderListener( title, description, myProject, fileChooserDescriptor ); SwingUtils.addTextChangeListener(myCustomDirectoryTextFieldWithBrowseButton.getTextField(), new TextChangeListener() { @Override public void textChanged(String oldText, @NotNull String newText) { fireDirectoryTypeSelected(); } } ); JPanel panel = new JPanel(new BorderLayout()); panel.add(myCustomDirectoryTextFieldWithBrowseButton, BorderLayout.NORTH); return panel; } }); selectDirectoryType(DirectoryType.DEFAULT); } private void addContentForExtractDirecoryType( JRadioButton radioButton, DirectoryType directoryType, Supplier<JPanel> producer ) { JPanel panel = producer.get(); if (panel == null) { throw new RuntimeException(); } myDirectoryTypeContent.add(panel, directoryType.name()); radioButton.addActionListener(new MyActionListener(directoryType)); } public static ExtractDirectoryTypeManager install( @NotNull Project project, @NotNull JPanel directoryTypeContent, @NotNull String assertionFrameworkName, @NotNull JRadioButton defaultRadioButton, @NotNull JRadioButton customRadioButton ) { ExtractDirectoryTypeManager directoryTypeManager = new ExtractDirectoryTypeManager( project, directoryTypeContent, assertionFrameworkName ); directoryTypeManager.populate(defaultRadioButton, customRadioButton); return directoryTypeManager; } public void addChangeListener(ChangeListener changeListener) { myChangeListeners.add(changeListener); } private File getExtractDir() { if (mySelectedDirectoryType == DirectoryType.DEFAULT) { return myDefaultDir; } return new File(myCustomDirectoryTextFieldWithBrowseButton.getText()); } public DialogWrapper.ValidationInfo validate() { if (mySelectedDirectoryType == DirectoryType.DEFAULT) { return null; } File extractDirectory = getExtractDir(); if (!extractDirectory.isDirectory()) { return new DialogWrapper.ValidationInfo("'" + extractDirectory.getPath() + "' is not a directory.", myCustomDirectoryTextFieldWithBrowseButton); } return null; } private void selectDirectoryType(DirectoryType directoryType) { CardLayout cardLayout = (CardLayout) myDirectoryTypeContent.getLayout(); cardLayout.show(myDirectoryTypeContent, directoryType.name()); mySelectedDirectoryType = directoryType; fireDirectoryTypeSelected(); } private void fireDirectoryTypeSelected() { File extractDir = getExtractDir(); for (ChangeListener changeListener : myChangeListeners) { changeListener.onExtractDirectoryChanged(extractDir); } } /** * * @param bundledAdapterFiles files for coping * @return extracted file list or null if extraction was failed */ @Nullable public List<VirtualFile> extractAdapterFiles(final List<VirtualFile> bundledAdapterFiles) { return ApplicationManager.getApplication().runWriteAction(new Computable<List<VirtualFile>>() { @Override public List<VirtualFile> compute() { VirtualFile extractDir = getExtractDirAsVirtualFile(); return copyVirtualFilesToDir(bundledAdapterFiles, extractDir); } }); } @NotNull private VirtualFile getExtractDirAsVirtualFile() { if (mySelectedDirectoryType == DirectoryType.DEFAULT) { if (!myDefaultDir.isDirectory() && !myDefaultDir.mkdirs()) { throw new RuntimeException("Can't create dir " + myDefaultDir.getAbsolutePath()); } } File extractDir = getExtractDir(); VirtualFile vfExtractDir = LocalFileSystem.getInstance().findFileByIoFile(extractDir); if (vfExtractDir == null) { throw new RuntimeException("Can't find VirtualFile for " + extractDir.getAbsolutePath()); } return vfExtractDir; } @SuppressWarnings({"NullableProblems"}) @Nullable private List<VirtualFile> copyVirtualFilesToDir(List<VirtualFile> virtualFiles, @NotNull VirtualFile targetDir) { List<VirtualFile> copiedFiles = Lists.newArrayList(); for (VirtualFile virtualFile : virtualFiles) { try { copiedFiles.add(VfsUtilCore.copyFile(null, virtualFile, targetDir)); } catch (IOException e) { Messages.showErrorDialog("Extract operation failed!\nUnable to copy " + virtualFile.getPath() + " to " + targetDir.getPath(), "Adding " + myAssertionFrameworkName + " adapter support for JsTestDriver"); return null; } } return copiedFiles; } public void init() { selectDirectoryType(DirectoryType.DEFAULT); } private static File getDefaultDir(String assertionFrameworkName) { File file = new File(PathManager.getSystemPath(), "extLibs/" + assertionFrameworkName + "AdapterForJsTestDriver"); try { return file.getCanonicalFile(); } catch (IOException e) { return file; } } private class MyActionListener implements ActionListener { private final DirectoryType myDirectoryType; private MyActionListener(DirectoryType directoryType) { myDirectoryType = directoryType; } @Override public void actionPerformed(ActionEvent e) { selectDirectoryType(myDirectoryType); } } interface ChangeListener { void onExtractDirectoryChanged(File extractDirectory); } private enum DirectoryType { DEFAULT, CUSTOM } }