--- project.ant/apichanges.xml +++ project.ant/apichanges.xml @@ -108,6 +108,23 @@ + + + Added CustomizerUtilities.createLicenseHeaderCustomizerPanel + + + + + + +

+ CustomizerUtilities.createLicenseHeaderCustomizerPanel() was introduced + to allow project modules to create license header selection and editing panel. +

+
+ + +
Added AntProjectHelper.createSharabilityQuery2 --- project.ant/manifest.mf +++ project.ant/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.project.ant/1 -OpenIDE-Module-Specification-Version: 1.52 +OpenIDE-Module-Specification-Version: 1.53 OpenIDE-Module-Layer: org/netbeans/modules/project/ant/resources/mf-layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class --- project.ant/nbproject/project.xml +++ project.ant/nbproject/project.xml @@ -50,6 +50,15 @@ org.netbeans.modules.project.ant + org.jdesktop.layout + + + + 1 + 1.25 + + + org.netbeans.api.annotations.common --- project.ant/src/org/netbeans/spi/project/support/ant/ui/Bundle.properties +++ project.ant/src/org/netbeans/spi/project/support/ant/ui/Bundle.properties @@ -0,0 +1,5 @@ +LicenseHeadersPanel.rbGlobal.text=Use global license +LicenseHeadersPanel.rbProject.text=Use project location +LicenseHeadersPanel.lblLicense.text=License header +LicenseHeadersPanel.btnProject.text=Browse... +LicenseHeadersPanel.btnGlobal.text=Edit global licenses --- project.ant/src/org/netbeans/spi/project/support/ant/ui/CustomizerUtilities.java +++ project.ant/src/org/netbeans/spi/project/support/ant/ui/CustomizerUtilities.java @@ -0,0 +1,121 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.project.support.ant.ui; + +import javax.swing.JComponent; +import org.netbeans.spi.project.ui.support.ProjectCustomizer; +import org.openide.filesystems.FileObject; + +/** + * set of factory methods to create customizer panels + * @author mkleint + * @since 1.53 + */ +public final class CustomizerUtilities { + + + /** + * for given category and data handler, create a component showing license header editing panel. To be used within ProjectCustomizer.CompositeCategoryProvider. + * @param category + * @param handler + * @return + * @since 1.53 + */ + public static JComponent createLicenseHeaderCustomizerPanel(ProjectCustomizer.Category category, LicensePanelContentHandler handler) { + return new LicenseHeadersPanel(category, handler); + } + + + /** + * handle data inputs and outputs in the license headers customizer panel. + * @since 1.53 + */ + public static interface LicensePanelContentHandler { + /** + * raw, unevaluated value points to the file in project space containing the header, + * if present takes precedence over getGlobalLicenseName() + * + * @return value or null if the value is unknown/doesn't exist + */ + String getProjectLicenseLocation(); + + /** + * value of pointing to the global license header in the IDE. + * @return + */ + String getGlobalLicenseName(); + + /** + * take the value from getProjectLicenseLocation and evaluate it to FileObject + * + * @param path + * @return FileObject instance if found, otherwise null + */ + FileObject resolveProjectLocation(String path); + + /** + * new value for project location, null value allowed and is meant to remove the value (to effectively use the global license) + * @param newLocation + */ + void setProjectLicenseLocation(String newLocation); + + /** + * set new value of global license template + * @param newName + */ + void setGlobalLicenseName(String newName); + + /** + * if no getProjectLicenseLocation is returned, this method will return the default project location. + * @return + */ + public String getDefaultProjectLicenseLocation(); + + /** + * set the user edited content of the license header file in project space. + * @param text + */ + void setProjectLicenseContent(String text); + + } +} --- project.ant/src/org/netbeans/spi/project/support/ant/ui/LicenseHeadersPanel.form +++ project.ant/src/org/netbeans/spi/project/support/ant/ui/LicenseHeadersPanel.form @@ -0,0 +1,144 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--- project.ant/src/org/netbeans/spi/project/support/ant/ui/LicenseHeadersPanel.java +++ project.ant/src/org/netbeans/spi/project/support/ant/ui/LicenseHeadersPanel.java @@ -0,0 +1,469 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.spi.project.support.ant.ui; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import javax.swing.Action; +import javax.swing.DefaultComboBoxModel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.netbeans.spi.project.ui.support.ProjectCustomizer; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; + +/** + * + * @author mkleint + */ +class LicenseHeadersPanel extends javax.swing.JPanel { + + private static final String defaultProjectLicense = +"<#if licenseFirst??>\n" + +"${licenseFirst}\n" + +"\n" + +"${licensePrefix}Here comes the text of your license\n" + +"${licensePrefix}Each line should be prefixed with ${licensePrefix}\n" + +"<#if licenseLast??>\n" + +"${licenseLast}\n" + +""; + private final CustomizerUtilities.LicensePanelContentHandler handler; + private final ProjectCustomizer.Category category; + private final FileChangeAdapter fslistener; + private final DocumentListener editorListener; + /** + * Creates new form LicenseHeadersPanel + */ + LicenseHeadersPanel(ProjectCustomizer.Category category, CustomizerUtilities.LicensePanelContentHandler handler) { + this.handler = handler; + this.category = category; + + initComponents(); + + btnProject.setVisible(false); //how to implement browse?? + + + editorListener = new DocumentListener() { + + @Override + public void insertUpdate(DocumentEvent e) { + LicenseHeadersPanel.this.handler.setProjectLicenseContent(epLicense.getText()); + } + + @Override + public void removeUpdate(DocumentEvent e) { + LicenseHeadersPanel.this.handler.setProjectLicenseContent(epLicense.getText()); + } + + @Override + public void changedUpdate(DocumentEvent e) { + LicenseHeadersPanel.this.handler.setProjectLicenseContent(epLicense.getText()); + } + }; + + loadGlobalLicenses(); + initValues(); + txtProject.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void insertUpdate(DocumentEvent e) { + changedUpdate(e); + } + + @Override + public void removeUpdate(DocumentEvent e) { + changedUpdate(e); + } + + @Override + public void changedUpdate(DocumentEvent e) { + LicenseHeadersPanel.this.handler.setProjectLicenseLocation(txtProject.getText().trim()); + setTextToProjectLicense(); + } + }); + + rbGlobal.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + txtProject.setEnabled(false); + epLicense.setEditable(false); + btnProject.setEnabled(false); + comGlobal.setEnabled(true); + LicenseHeadersPanel.this.category.setErrorMessage(null); + epLicense.getDocument().removeDocumentListener(editorListener); + LicenseHeadersPanel.this.handler.setProjectLicenseContent(null); + setTextToGlobalLicense(); + LicenseHeadersPanel.this.handler.setProjectLicenseLocation(null); + } + }); + rbProject.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + txtProject.setEnabled(true); + epLicense.setEditable(true); + btnProject.setEnabled(true); + comGlobal.setEnabled(false); + epLicense.getDocument().addDocumentListener(editorListener); + + LicenseHeadersPanel.this.handler.setProjectLicenseLocation(txtProject.getText().trim()); + setTextToProjectLicense(); + } + + }); + comGlobal.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + + setTextToGlobalLicense(); + GlobalItem item = (GlobalItem) comGlobal.getSelectedItem(); + LicenseHeadersPanel.this.handler.setGlobalLicenseName(item.getName()); + } + + }); + FileObject root = FileUtil.getConfigFile("Templates/Licenses"); + fslistener = new FileChangeAdapter() { + @Override + public void fileDataCreated(FileEvent fe) { + reloadGlobalTemplatesCombo(); + } + + @Override + public void fileDeleted(FileEvent fe) { + reloadGlobalTemplatesCombo(); + } + + @Override + public void fileRenamed(FileRenameEvent fe) { + reloadGlobalTemplatesCombo(); + } + + @Override + public void fileAttributeChanged(FileAttributeEvent fe) { + if ("displayName".equals(fe.getName())) { + reloadGlobalTemplatesCombo(); + } + } + + @Override + public void fileChanged(FileEvent fe) { + if (rbGlobal.isSelected()) { + setTextToGlobalLicense(); + } + } + }; + root.addRecursiveListener(FileUtil.weakFileChangeListener(fslistener, root)); + + } + + + + private void reloadGlobalTemplatesCombo() { + category.setErrorMessage(null); + GlobalItem item = (GlobalItem) comGlobal.getSelectedItem(); + String selection = item != null ? item.getName() : null; + loadGlobalLicenses(); + if (selection != null) { + boolean found = selectComboBoxItem(selection, rbGlobal.isSelected()); + if (!found) { + category.setErrorMessage("The project's license with name '" + selection + "' was not found in IDE's license headers."); + } + } + } + + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonGroup1 = new javax.swing.ButtonGroup(); + rbGlobal = new javax.swing.JRadioButton(); + rbProject = new javax.swing.JRadioButton(); + comGlobal = new javax.swing.JComboBox(); + btnGlobal = new javax.swing.JButton(); + txtProject = new javax.swing.JTextField(); + btnProject = new javax.swing.JButton(); + lblLicense = new javax.swing.JLabel(); + jScrollPane2 = new javax.swing.JScrollPane(); + epLicense = new javax.swing.JEditorPane(); + + buttonGroup1.add(rbGlobal); + rbGlobal.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(rbGlobal, org.openide.util.NbBundle.getMessage(LicenseHeadersPanel.class, "LicenseHeadersPanel.rbGlobal.text")); // NOI18N + + buttonGroup1.add(rbProject); + org.openide.awt.Mnemonics.setLocalizedText(rbProject, org.openide.util.NbBundle.getMessage(LicenseHeadersPanel.class, "LicenseHeadersPanel.rbProject.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(btnGlobal, org.openide.util.NbBundle.getMessage(LicenseHeadersPanel.class, "LicenseHeadersPanel.btnGlobal.text")); // NOI18N + btnGlobal.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnGlobalActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(btnProject, org.openide.util.NbBundle.getMessage(LicenseHeadersPanel.class, "LicenseHeadersPanel.btnProject.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(lblLicense, org.openide.util.NbBundle.getMessage(LicenseHeadersPanel.class, "LicenseHeadersPanel.lblLicense.text")); // NOI18N + + epLicense.setContentType("text/x-freemarker"); // NOI18N + jScrollPane2.setViewportView(epLicense); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(rbProject) + .add(rbGlobal)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(comGlobal, 0, 221, Short.MAX_VALUE) + .add(txtProject)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(btnGlobal) + .add(btnProject))) + .add(layout.createSequentialGroup() + .add(35, 35, 35) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .add(jScrollPane2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addContainerGap()) + .add(layout.createSequentialGroup() + .add(lblLicense) + .add(0, 0, Short.MAX_VALUE)))) + ); + + layout.linkSize(new java.awt.Component[] {btnGlobal, btnProject}, org.jdesktop.layout.GroupLayout.HORIZONTAL); + + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(rbGlobal) + .add(comGlobal, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(btnGlobal)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(rbProject) + .add(txtProject, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(btnProject)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(lblLicense) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 195, Short.MAX_VALUE) + .addContainerGap()) + ); + }// //GEN-END:initComponents + + private void btnGlobalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGlobalActionPerformed + // TODO add your handling code here: + Action action = FileUtil.getConfigObject("Actions/System/org-netbeans-modules-favorites-templates-TemplatesAction.instance", Action.class); + if (action != null) { + action.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "perform")); + } else { + Exceptions.printStackTrace(new Exception("Actions/System/org-netbeans-modules-favorites-templates-TemplatesAction.instance not found")); + } + }//GEN-LAST:event_btnGlobalActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnGlobal; + private javax.swing.JButton btnProject; + private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JComboBox comGlobal; + private javax.swing.JEditorPane epLicense; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JLabel lblLicense; + private javax.swing.JRadioButton rbGlobal; + private javax.swing.JRadioButton rbProject; + private javax.swing.JTextField txtProject; + // End of variables declaration//GEN-END:variables + + + private void loadGlobalLicenses() { + FileObject root = FileUtil.getConfigFile("Templates/Licenses"); + DefaultComboBoxModel model = new DefaultComboBoxModel(); + for (FileObject fo : root.getChildren()) { + if (fo.getAttribute("template") == null) { + continue; + } + String displayName = (String) fo.getAttribute("displayName"); + if (displayName == null) { + displayName = fo.getName(); + if (displayName.startsWith("license-")) { + displayName = displayName.substring("license-".length()); + } + } + model.addElement(new GlobalItem(displayName, fo)); + } + comGlobal.setModel(model); + } + + private void setTextToGlobalLicense() { + GlobalItem item = (GlobalItem) comGlobal.getSelectedItem(); + if (item == null) { + epLicense.setText(""); + } else { + try { + if (item.fileObject != null) { + epLicense.setText(item.fileObject.asText()); + } else { + epLicense.setText(""); + } + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + } + + private void setTextToProjectLicense() { + category.setErrorMessage(null); + String path = txtProject.getText(); + FileObject fo = handler.resolveProjectLocation(path); + if (fo != null) { + try { + epLicense.setText(fo.asText()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } else { + category.setErrorMessage("File at path '" + path + "' doesn't exist."); + epLicense.setText(defaultProjectLicense); + } + + } + + + + private void initValues() { + String name = handler.getGlobalLicenseName(); + String path = handler.getProjectLicenseLocation(); + if (name == null) { + name = "default"; + } + boolean found = selectComboBoxItem(name, true); + if (path == null) { + path = handler.getDefaultProjectLicenseLocation(); + txtProject.setText(path); + rbGlobal.setSelected(true); //has to come last + if (!found) { + category.setErrorMessage("The project's license with name '" + name + "' was not found in IDE's license headers."); + } + } else { + txtProject.setText(path); + rbProject.setSelected(true); //has to come last + setTextToProjectLicense(); + epLicense.getDocument().addDocumentListener(editorListener); + } + } + + private boolean selectComboBoxItem(String name, boolean setText) { + boolean found = false; + DefaultComboBoxModel model = (DefaultComboBoxModel) comGlobal.getModel(); + for (int i = 0; i < model.getSize(); i++) { + GlobalItem gi = (GlobalItem) model.getElementAt(i); + if (gi.getName().equals(name)) { + comGlobal.setSelectedItem(gi); + found = true; + if (setText) { + setTextToGlobalLicense(); + } + break; + } + } + if (!found) { + GlobalItem itm = new GlobalItem(name, null); + model.insertElementAt(itm, 0); + comGlobal.setSelectedItem(itm); + if (setText) { + setTextToGlobalLicense(); + } + } + return found; + } + + + private class GlobalItem { + + final String displayName; + final FileObject fileObject; + + public GlobalItem(String name, FileObject fileObject) { + this.displayName = name; + this.fileObject = fileObject; + } + + public String getName() { + if (fileObject == null) { + return displayName; + } + String name = fileObject.getName(); + if (name.startsWith("license-")) { + name = name.substring("license-".length()); + } + return name; + } + + @Override + public String toString() { + return displayName; + } + } + + + +}