/* * Copyright (c) 2007-2009, Osmorc Development Team * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * Neither the name of 'Osmorc Development Team' nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.osmorc.facet.ui; import com.intellij.facet.ui.FacetEditorContext; import com.intellij.facet.ui.FacetEditorTab; import com.intellij.facet.ui.FacetValidatorsManager; import com.intellij.openapi.fileChooser.*; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.CompilerModuleExtension; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.ui.EditorTextField; import com.intellij.ui.UserActivityListener; import com.intellij.ui.UserActivityWatcher; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.osmorc.facet.OsmorcFacetConfiguration; import org.osmorc.i18n.OsmorcBundle; import org.osmorc.settings.MyErrorText; import javax.swing.*; import javax.swing.event.*; import javax.swing.table.TableColumn; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import static org.osmorc.facet.OsmorcFacetConfiguration.OutputPathType.*; /** * The facet editor tab which is used to set up Osmorc facet settings concerning the bundle JAR created by Osmorc. * * @author <a href="mailto:janthomae@janthomae.de">Jan Thomä</a> * @author Robert F. Beeger (robert@beeger.net) */ public class OsmorcFacetJAREditorTab extends FacetEditorTab { private JPanel myRoot; private JTable myAdditionalJARContentsTable; private final EditorTextField myIgnoreFilePatternTextField; private JButton myAddButton; private JButton myRemoveButton; private JButton myEditButton; private JCheckBox myAlwaysRebuildBundleJARCheckBox; private JLabel myFileIgnorePatternLabel; private JPanel myIgnoreFilePatternPanel; private JTextField myJarFileTextField; private JRadioButton myPlaceInCompilerOutputPathRadioButton; private JRadioButton myPlaceInProjectWideRadioButton; private JRadioButton myPlaceInThisPathRadioButton; private TextFieldWithBrowseButton myJarOutputPathChooser; private MyErrorText myErrorText; private JPanel myAdditionalJarContentsPanel; private boolean myModified; private final FacetEditorContext myEditorContext; private FacetValidatorsManager myValidatorsManager; private final AdditionalJARContentsTableModel myAdditionalJARContentsTableModel; public OsmorcFacetJAREditorTab(FacetEditorContext editorContext, FacetValidatorsManager validatorsManager) { myEditorContext = editorContext; myValidatorsManager = validatorsManager; final Project project = editorContext.getProject(); myIgnoreFilePatternTextField = new EditorTextField("", project, FileTypes.PLAIN_TEXT); FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName("*.regexp"); if (fileType == FileTypes.UNKNOWN) { fileType = FileTypeManager.getInstance().getFileTypeByFileName("*.txt"); // RegExp plugin is not installed } final PsiFile file = PsiFileFactory.getInstance(project).createFileFromText("*.regexp", fileType, myIgnoreFilePatternTextField.getText(), -1, true); myIgnoreFilePatternTextField.setNewDocumentAndFileType(fileType, PsiDocumentManager.getInstance(project).getDocument(file)); myIgnoreFilePatternPanel.add(myIgnoreFilePatternTextField, BorderLayout.CENTER); UserActivityWatcher watcher = new UserActivityWatcher(); watcher.addUserActivityListener(new UserActivityListener() { public void stateChanged() { myModified = true; updateGui(); } }); myJarOutputPathChooser.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { onOutputPathSelect(); } }); ChangeListener listener = new ChangeListener() { public void stateChanged(ChangeEvent e) { updateGui(); } }; myPlaceInProjectWideRadioButton.addChangeListener(listener); myPlaceInThisPathRadioButton.addChangeListener(listener); myPlaceInCompilerOutputPathRadioButton.addChangeListener(listener); watcher.register(myRoot); myAdditionalJARContentsTableModel = new AdditionalJARContentsTableModel(); myAdditionalJARContentsTable.setModel(myAdditionalJARContentsTableModel); TableColumn col = myAdditionalJARContentsTable.getColumnModel().getColumn(0); final FileSelectorTableCellEditor selectorTableCellEditor = new FileSelectorTableCellEditor(project, myEditorContext.getModule()); col.setCellEditor(selectorTableCellEditor); selectorTableCellEditor.addCellEditorListener(new CellEditorListener() { public void editingCanceled(ChangeEvent e) { } public void editingStopped(ChangeEvent e) { // ok we finished editing the left, now get the stuff from there, calculate a destination name and edit the other cell int row = myAdditionalJARContentsTable.getSelectedRow(); if (row > -1) { Pair<String, String> additionalJARContent = myAdditionalJARContentsTableModel.getAdditionalJARContent(row); VirtualFile preselectedPath = LocalFileSystem.getInstance().findFileByPath(additionalJARContent.getFirst()); String destinationName; if (preselectedPath != null) { destinationName = determineMostLikelyLocationInJAR(preselectedPath); } else { destinationName = ""; } myAdditionalJARContentsTableModel.changeAdditionalJARConent(row, additionalJARContent.first, destinationName); myAdditionalJARContentsTable.editCellAt(row, 1); myAdditionalJARContentsTable.getEditorComponent().requestFocus(); } } }); myAdditionalJARContentsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { myRemoveButton.setEnabled(myAdditionalJARContentsTable.getSelectedRowCount() > 0); myEditButton.setEnabled(myAdditionalJARContentsTable.getSelectedRowCount() > 0); } }); myAddButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onAddAdditionalJARContent(); } }); myRemoveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onRemoveAdditionalJARContent(); } }); myEditButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onEditAdditionalJARContent(); } }); myEditButton.setEnabled(false); myRemoveButton.setEnabled(false); myValidatorsManager.registerValidator(new OsmorcFacetJarEditorValidator(myEditorContext, this)); } private void onEditAdditionalJARContent() { int row = myAdditionalJARContentsTable.getSelectedRow(); if (row > -1) { Pair<String, String> additionalJARContent = myAdditionalJARContentsTableModel.getAdditionalJARContent(row); Project project = myEditorContext.getProject(); FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleLocalFileDescriptor(); descriptor.setTitle("Choose source file or folder"); FileChooserDialog fileChooserDialog = FileChooserFactory.getInstance().createFileChooser(descriptor, project); VirtualFile preselectedPath = LocalFileSystem.getInstance().findFileByPath(additionalJARContent.getFirst()); if (preselectedPath == null) { Module module = myEditorContext.getModule(); VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots(); if (contentRoots.length > 0) { for (VirtualFile contentRoot : contentRoots) { VirtualFile path = VfsUtil.findRelativeFile(additionalJARContent.getFirst(), contentRoot); if (path != null) { preselectedPath = path; break; } } if (preselectedPath == null) { preselectedPath = contentRoots[0]; } } else if (project.getBaseDir() != null) { preselectedPath = project.getBaseDir(); } } VirtualFile[] files = fileChooserDialog.choose(preselectedPath, project); if (files.length > 0) { String sourcePath = files[0].getPath(); String destPath = determineMostLikelyLocationInJAR(files[0]); myAdditionalJARContentsTableModel.changeAdditionalJARConent(row, sourcePath, destPath); myAdditionalJARContentsTable.editCellAt(row, 1); myAdditionalJARContentsTable.getEditorComponent().requestFocus(); } } } private void onRemoveAdditionalJARContent() { myAdditionalJARContentsTableModel.deleteAdditionalJARContent(myAdditionalJARContentsTable.getSelectedRow()); } private void onAddAdditionalJARContent() { Project project = myEditorContext.getProject(); FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createAllButJarContentsDescriptor(); descriptor.setTitle("Choose source file or folder"); FileChooserDialog fileChooserDialog = FileChooserFactory.getInstance().createFileChooser(descriptor, project); VirtualFile rootFolder = null; Module module = myEditorContext.getModule(); VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots(); if (contentRoots.length > 0) { rootFolder = contentRoots[0]; } else if (project.getBaseDir() != null) { rootFolder = project.getBaseDir(); } VirtualFile[] files = fileChooserDialog.choose(rootFolder, project); for (VirtualFile file : files) { String destFile = determineMostLikelyLocationInJAR(file); int row = myAdditionalJARContentsTableModel.addAdditionalJARContent(file.getPath(), destFile); myAdditionalJARContentsTable.editCellAt(row, 1); myAdditionalJARContentsTable.getEditorComponent().requestFocus(); } } private String determineMostLikelyLocationInJAR(@NotNull VirtualFile file) { Project project = myEditorContext.getProject(); Module module = myEditorContext.getModule(); VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots(); for (VirtualFile contentRoot : contentRoots) { if (VfsUtil.isAncestor(contentRoot, file, false)) { return VfsUtilCore.getRelativePath(file, contentRoot, '/'); } } VirtualFile projectBaseFolder = project.getBaseDir(); if (projectBaseFolder != null && VfsUtil.isAncestor(projectBaseFolder, file, false)) { return VfsUtilCore.getRelativePath(file, projectBaseFolder, '/'); } return file.getName(); } private void updateGui() { Boolean bnd = myEditorContext.getUserData(OsmorcFacetGeneralEditorTab.BND_CREATION_KEY); Boolean bundlor = myEditorContext.getUserData(OsmorcFacetGeneralEditorTab.BUNDLOR_CREATION_KEY); boolean useExternalTool = (bnd != null && bnd) || (bundlor != null && bundlor); myJarOutputPathChooser.setEnabled(myPlaceInThisPathRadioButton.isSelected()); myAdditionalJARContentsTable.setEnabled(!useExternalTool); myIgnoreFilePatternTextField.setEnabled(!useExternalTool); myAddButton.setEnabled(!useExternalTool); myRemoveButton.setEnabled(!useExternalTool); myEditButton.setEnabled(!useExternalTool); myAlwaysRebuildBundleJARCheckBox.setEnabled(!useExternalTool); myAdditionalJarContentsPanel.setEnabled(!useExternalTool); myFileIgnorePatternLabel.setEnabled(!useExternalTool); myValidatorsManager.validate(); if (myPlaceInThisPathRadioButton.isSelected() && myJarOutputPathChooser.getText().trim().length()==0) { myErrorText.setError("Please select an output path"); } else { myErrorText.setError(null); } } void onOutputPathSelect() { String currentFile = getSelectedOutputPath(); VirtualFile moduleCompilerOutputPath = CompilerModuleExtension.getInstance(myEditorContext.getModule()).getCompilerOutputPath(); // okay there is some strange thing going on here. The method getCompilerOutputPath() returns null // but getCompilerOutputPathUrl() returns something. I assume that we cannot get a VirtualFile object for a non-existing // path, so we need to make sure the compiler output path exists. if (moduleCompilerOutputPath == null) { // get the url String outputPathUrl = CompilerModuleExtension.getInstance(myEditorContext.getModule()).getCompilerOutputUrl(); // create the paths try { VfsUtil.createDirectories(VfsUtil.urlToPath(outputPathUrl)); } catch (IOException e) { Messages.showErrorDialog(myRoot, OsmorcBundle.getTranslation("error"), OsmorcBundle.getTranslation("faceteditor.cannot.create.outputpath")); return; } // now try again to get VirtualFile object for it moduleCompilerOutputPath = CompilerModuleExtension.getInstance(myEditorContext.getModule()).getCompilerOutputPath(); if (moduleCompilerOutputPath == null) { // this should not happen throw new IllegalStateException("Cannot access compiler output path."); } } VirtualFile preselectedFile = StringUtil.isNotEmpty(currentFile) ? LocalFileSystem.getInstance().findFileByPath(currentFile) : moduleCompilerOutputPath; FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); descriptor.setTitle("Select bundle output directory"); VirtualFile file = FileChooser.chooseFile(myEditorContext.getProject(), descriptor, preselectedFile); if (file != null) { if (VfsUtil.isAncestor(moduleCompilerOutputPath, file, false)) { Messages.showErrorDialog(myEditorContext.getProject(), OsmorcBundle.getTranslation("faceteditor.jar.cannot.be.in.output.path"), OsmorcBundle.getTranslation("error")); myJarOutputPathChooser.setText(""); return; } myJarOutputPathChooser.setText(file.getPath()); } } @Nls public String getDisplayName() { return "Bundle JAR"; } public JComponent createComponent() { return myRoot; } public boolean isModified() { return myModified; } public void apply() { OsmorcFacetConfiguration configuration = (OsmorcFacetConfiguration)myEditorContext.getFacet().getConfiguration(); String fileLocation = getSelectedOutputPath(); String jarFileName = getJarFileName(); OsmorcFacetConfiguration.OutputPathType pathType = getSelectedOutputPathType(); // Build a complete path if the user wants to put the file into some specific path. if (pathType == SpecificOutputPath) { String completeOutputPath = new File(fileLocation, jarFileName).getPath(); configuration.setJarFileLocation(completeOutputPath, pathType); } else { configuration.setJarFileLocation(jarFileName, pathType); } configuration.setIgnoreFilePattern(myIgnoreFilePatternTextField.getText()); configuration.setAlwaysRebuildBundleJAR(myAlwaysRebuildBundleJARCheckBox.isSelected()); configuration.setAdditionalJARContents(myAdditionalJARContentsTableModel.getAdditionalContents()); myModified = false; } public String getJarFileName() { return myJarFileTextField.getText(); } String getSelectedOutputPath() { return myJarOutputPathChooser.getText(); } OsmorcFacetConfiguration.OutputPathType getSelectedOutputPathType() { return myPlaceInProjectWideRadioButton.isSelected() ? OsgiOutputPath : myPlaceInCompilerOutputPathRadioButton.isSelected() ? CompilerOutputPath : SpecificOutputPath; } public void reset() { OsmorcFacetConfiguration configuration = (OsmorcFacetConfiguration)myEditorContext.getFacet().getConfiguration(); OsmorcFacetConfiguration.OutputPathType outputPathType = configuration.getOutputPathType(); myPlaceInCompilerOutputPathRadioButton.setSelected(outputPathType == CompilerOutputPath); myPlaceInProjectWideRadioButton.setSelected(outputPathType == OsgiOutputPath); myPlaceInThisPathRadioButton.setSelected(outputPathType == SpecificOutputPath); myJarFileTextField.setText(configuration.getJarFileName()); if (outputPathType == SpecificOutputPath) { myJarOutputPathChooser.setText(configuration.getJarFilePath()); } else { myJarOutputPathChooser.setText(""); } myAdditionalJARContentsTableModel.replaceContent(configuration.getAdditionalJARContents()); myIgnoreFilePatternTextField.setText(configuration.getIgnoreFilePattern()); myAlwaysRebuildBundleJARCheckBox.setSelected(configuration.isAlwaysRebuildBundleJAR()); updateGui(); myModified = false; } @Override public void onTabEntering() { super.onTabEntering(); updateGui(); myValidatorsManager.validate(); } public void disposeUIResources() { } @Override public String getHelpTopic() { return "reference.settings.module.facet.osgi"; } }