| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.netbeans.modules.apisupport.project.ui.wizard.common; |
| |
| import org.netbeans.modules.apisupport.project.api.BasicWizardPanel; |
| import org.netbeans.modules.apisupport.project.api.BasicVisualPanel; |
| import java.awt.Component; |
| import java.io.IOException; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.NoSuchElementException; |
| import java.util.Set; |
| import javax.swing.event.ChangeListener; |
| import javax.swing.text.BadLocationException; |
| import org.netbeans.api.annotations.common.NonNull; |
| import org.netbeans.modules.editor.indent.api.Reformat; |
| import org.netbeans.api.java.project.JavaProjectConstants; |
| import org.netbeans.api.project.Project; |
| import org.netbeans.api.project.ProjectUtils; |
| import org.netbeans.api.project.SourceGroup; |
| import org.netbeans.api.project.Sources; |
| import org.netbeans.editor.BaseDocument; |
| import org.netbeans.modules.apisupport.project.api.Util; |
| import org.netbeans.modules.apisupport.project.spi.NbModuleProvider; |
| import org.netbeans.spi.project.ui.templates.support.Templates; |
| import org.openide.ErrorManager; |
| import org.openide.WizardDescriptor; |
| import org.openide.cookies.EditorCookie; |
| import org.openide.filesystems.FileObject; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.loaders.DataObject; |
| import org.openide.loaders.DataObjectNotFoundException; |
| import org.openide.util.HelpCtx; |
| import static org.netbeans.modules.apisupport.project.ui.wizard.common.Bundle.*; |
| import org.openide.util.NbBundle.Messages; |
| |
| /** |
| * Convenient class for implementing {@link org.openide.WizardDescriptor.InstantiatingIterator}. |
| * |
| * @author Radek Matous |
| */ |
| public abstract class BasicWizardIterator implements WizardDescriptor.AsynchronousInstantiatingIterator<WizardDescriptor> { |
| |
| private int position = 0; |
| private BasicWizardIterator.PrivateWizardPanel[] wizardPanels; |
| |
| /** Create a new wizard iterator. */ |
| protected BasicWizardIterator() {} |
| |
| /** @return all panels provided by this {@link org.openide.WizardDescriptor.InstantiatingIterator} */ |
| protected abstract BasicWizardIterator.Panel[] createPanels(WizardDescriptor wiz); |
| |
| /** Basic visual panel.*/ |
| public abstract static class Panel extends BasicVisualPanel { |
| |
| protected Panel(WizardDescriptor wiz) { |
| super(wiz); |
| } |
| |
| /** |
| * Returned name is used by a wizard. e.g. on its left side in the |
| * <em>step list</em>. |
| * @return name of panel |
| */ |
| protected abstract String getPanelName(); |
| |
| /** |
| * Gives a chance to store an instance of {@link |
| * BasicWizardIterator.BasicDataModel}. It is called when a panel is |
| * going to be <em>hidden</em> (e.g. when switching to next/previous |
| * panel). |
| */ |
| protected abstract void storeToDataModel(); |
| |
| /** |
| * Gives a chance to refresh a panel (usually by reading a state of an |
| * instance of {@link BasicWizardIterator.BasicDataModel}. It is called |
| * when a panel is going to be <em>displayed</em> (e.g. when switching |
| * from next/previous panel). |
| */ |
| protected abstract void readFromDataModel(); |
| |
| protected abstract HelpCtx getHelp(); |
| |
| } |
| |
| /** DataModel that is passed through individual panels.*/ |
| public static class BasicDataModel { |
| |
| private Project project; |
| private NbModuleProvider module; |
| private SourceGroup sourceRootGroup; |
| private String packageName; |
| |
| /** Creates a new instance of NewFileDescriptorData */ |
| public BasicDataModel(WizardDescriptor wiz) { |
| Project tmpProject = Templates.getProject(wiz); |
| |
| if (tmpProject == null) { |
| throw new IllegalArgumentException(); |
| } |
| module = tmpProject.getLookup().lookup(NbModuleProvider.class); |
| if (module == null) { |
| throw new IllegalArgumentException(tmpProject.getClass().toString()); |
| } |
| |
| project = tmpProject; |
| // #66339 need to prefetch the packagename and populate data with it.. |
| FileObject fo = Templates.getTargetFolder(wiz); |
| if (fo != null) { |
| Sources srcs = ProjectUtils.getSources(project); // #63247: don't use lookup directly |
| SourceGroup[] grps = srcs.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); |
| for (int i = 0; i < grps.length; i++) { |
| if (FileUtil.isParentOf(grps[i].getRootFolder(), fo)) { |
| String relPath = FileUtil.getRelativePath(grps[i].getRootFolder(), fo); |
| relPath = relPath.replace('/', '.'); |
| setPackageName(relPath); |
| break; |
| } |
| } |
| } |
| } |
| |
| public Project getProject() { |
| return project; |
| } |
| |
| public NbModuleProvider getModuleInfo() { |
| return module; |
| } |
| |
| public String getPackageName() { |
| return packageName; |
| } |
| |
| public void setPackageName(String packageName) { |
| this.packageName = packageName; |
| } |
| |
| public SourceGroup getSourceRootGroup() { |
| if (sourceRootGroup == null) { |
| FileObject tempSrcRoot = getModuleInfo().getSourceDirectory(); |
| assert tempSrcRoot != null; |
| |
| Sources sources = ProjectUtils.getSources(project); |
| SourceGroup[] groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); |
| for (int i = 0; sourceRootGroup == null && i < groups.length; i++) { |
| if (groups[i].getRootFolder().equals(tempSrcRoot)) { |
| sourceRootGroup = groups[i]; |
| } |
| } |
| } |
| return sourceRootGroup; |
| } |
| |
| public String getDefaultPackagePath(String fileName, boolean resource) { |
| return getDefaultPackagePath(fileName, resource, false); |
| } |
| |
| public String getDefaultPackagePath(String fileName, boolean resource, boolean inTests) { |
| if (inTests) { |
| String path; |
| if (resource) { |
| path = getModuleInfo().getResourceDirectoryPath(true); |
| } else { |
| path = getModuleInfo().getTestSourceDirectoryPath(); |
| } |
| return path + '/' |
| + getPackageName().replace('.', '/') + '/' + fileName; |
| } |
| |
| return (resource ? getModuleInfo().getResourceDirectoryPath(inTests) : getModuleInfo().getSourceDirectoryPath()) + '/' + |
| getPackageName().replace('.','/') + '/' + fileName; |
| } |
| |
| /** |
| * Conditionally adds an operation to the given {@link |
| * CreatedModifiedFiles}. Result of the operation, after given |
| * CreatedModifiedFiles are run, is copied (into the package) icon |
| * representing given <code>origIconPath</code>. If the origIconPath is |
| * already inside the project's source directory nothing happens. |
| * |
| * @return path of the icon relative to the project's source directory |
| */ |
| public String addCreateIconOperation(CreatedModifiedFiles cmf, @NonNull FileObject originalIcon) { |
| String relativeIconPath = null; |
| if (!FileUtil.isParentOf(Util.getResourceDirectory(getProject()), originalIcon)) { |
| String iconPath = getDefaultPackagePath(originalIcon.getNameExt(), true); |
| cmf.add(cmf.createFile(iconPath, originalIcon)); |
| relativeIconPath = getPackageName().replace('.', '/') + '/' + originalIcon.getNameExt(); |
| } else { |
| relativeIconPath = FileUtil.getRelativePath(Util.getResourceDirectory(getProject()), originalIcon); |
| } |
| return relativeIconPath; |
| } |
| |
| } |
| |
| public static class InvalidProjectPanel extends Panel { |
| |
| @Messages("LBL_InvalidProjectMsg=Unable to finish selected wizard. Project is either not initialized or of wrong type.") |
| public InvalidProjectPanel(WizardDescriptor wiz) { |
| super(wiz); |
| setError(LBL_InvalidProjectMsg()); |
| } |
| |
| @Messages("LBL_InvalidProject=Invalid Project") |
| protected @Override String getPanelName() { |
| return LBL_InvalidProject(); |
| } |
| |
| @Override |
| protected HelpCtx getHelp() { |
| return new HelpCtx(InvalidProjectPanel.class); |
| } |
| |
| @Override |
| protected void readFromDataModel() { |
| // nothing |
| } |
| |
| @Override |
| protected void storeToDataModel() { |
| // nothing |
| } |
| |
| } |
| |
| public void initialize(WizardDescriptor wiz) { |
| // mkleint: copied from the NewJavaFileWizardIterator.. there must be something painfully wrong.. |
| String[] beforeSteps = null; |
| Object prop = wiz.getProperty(WizardDescriptor.PROP_CONTENT_DATA); // NOI18N |
| if (prop != null && prop instanceof String[]) { |
| beforeSteps = (String[])prop; |
| } |
| position = 0; |
| |
| // #176828: do not continue with wizard if called on non-NBM project; |
| // can be e.g. LazyProject or project without preferred templates |
| Project tmpProject = Templates.getProject(wiz); |
| boolean isValidPrj = (tmpProject != null && tmpProject.getLookup().lookup(NbModuleProvider.class) != null); |
| Panel[] panels = isValidPrj ? createPanels(wiz) |
| : new Panel[] { new InvalidProjectPanel(wiz) }; |
| String[] steps = BasicWizardIterator.createSteps(beforeSteps, panels); |
| wizardPanels = new BasicWizardIterator.PrivateWizardPanel[panels.length]; |
| |
| for (int i = 0; i < panels.length; i++) { |
| wizardPanels[i] = new BasicWizardIterator.PrivateWizardPanel(panels[i], steps, i); |
| } |
| } |
| |
| // mkleint: copied from the NewJavaFileWizardIterator.. there must be something painfully wrong.. |
| private static String[] createSteps(String[] before, BasicWizardIterator.Panel[] panels) { |
| assert panels != null; |
| // hack to use the steps set before this panel processed |
| int diff = 0; |
| if (before == null) { |
| before = new String[0]; |
| } else if (before.length > 0) { |
| diff = ("...".equals(before[before.length - 1])) ? 1 : 0; // NOI18N |
| } |
| String[] res = new String[ (before.length - diff) + panels.length]; |
| for (int i = 0; i < res.length; i++) { |
| if (i < (before.length - diff)) { |
| res[i] = before[i]; |
| } else { |
| res[i] = panels[i - before.length + diff].getPanelName(); |
| } |
| } |
| return res; |
| } |
| |
| public void uninitialize(WizardDescriptor wiz) { |
| wizardPanels = null; |
| } |
| |
| public String name() { |
| return ((BasicWizardIterator.PrivateWizardPanel) |
| current()).getPanel().getPanelName(); |
| } |
| |
| public boolean hasNext() { |
| return position < (wizardPanels.length - 1); |
| } |
| |
| public boolean hasPrevious() { |
| return position > 0; |
| } |
| |
| public void nextPanel() { |
| if (!hasNext()) { |
| throw new NoSuchElementException(); |
| } |
| position++; |
| } |
| |
| public void previousPanel() { |
| if (!hasPrevious()) { |
| throw new NoSuchElementException(); |
| } |
| position--; |
| } |
| |
| public WizardDescriptor.Panel<WizardDescriptor> current() { |
| return wizardPanels[position]; |
| } |
| |
| public final void addChangeListener(ChangeListener l) {} |
| public final void removeChangeListener(ChangeListener l) {} |
| |
| public static Set<FileObject> getCreatedFiles(final CreatedModifiedFiles cmf, final Project project) throws IOException { |
| Collection<DataObject> toBeShown = new HashSet<DataObject>(); |
| Set<FileObject> set = new HashSet<FileObject>(); |
| for (String path : cmf.getCreatedPaths()) { |
| FileObject fo = project.getProjectDirectory().getFileObject(path); |
| assert fo != null : path; |
| formatFile(fo); |
| DataObject dObj = DataObject.find(fo); |
| if (dObj != null && toBeShown.size() < 10 && toBeShown.add(dObj)) { |
| set.add(fo); |
| } |
| } |
| return set; |
| } |
| |
| private static BaseDocument getDocument(final FileObject fo) throws DataObjectNotFoundException, IOException { |
| BaseDocument doc = null; |
| DataObject dObj = DataObject.find(fo); |
| if (dObj != null) { |
| EditorCookie editor = dObj.getLookup().lookup(EditorCookie.class); |
| if (editor != null) { |
| doc = (BaseDocument) editor.openDocument(); |
| } |
| } |
| return doc; |
| } |
| |
| // copy-pasted-adjusted from org.netbeans.editor.ActionFactory.FormatAction |
| private static void formatFile(final FileObject fo) { |
| assert fo != null; |
| final BaseDocument doc; |
| try { |
| doc = BasicWizardIterator.getDocument(fo); |
| if (doc == null) { |
| return; |
| } |
| final Reformat reformat = Reformat.get(doc); |
| reformat.lock(); |
| try { |
| doc.runAtomic(new Runnable() { |
| public void run() { |
| try { |
| reformat.reformat(0, doc.getLength()); |
| } catch (BadLocationException x) { |
| throw new RuntimeException(x); |
| } |
| } |
| }); |
| } finally { |
| reformat.unlock(); |
| } |
| try { |
| DataObject.find(fo).getLookup().lookup(EditorCookie.class).saveDocument(); |
| } catch (IOException e) { |
| Util.err.notify(ErrorManager.INFORMATIONAL, e); |
| } |
| } catch (Exception ex) { |
| // no disaster |
| ErrorManager.getDefault().log(ErrorManager.WARNING, "Cannot reformat the file: " + fo.getPath()); // NOI18N |
| } |
| } |
| |
| private static final class PrivateWizardPanel extends BasicWizardPanel { |
| |
| private BasicWizardIterator.Panel panel; |
| |
| PrivateWizardPanel(BasicWizardIterator.Panel panel, String[] allSteps, int stepIndex) { |
| super(panel.getSettings()); |
| panel.addPropertyChangeListener(this); |
| panel.setName(panel.getPanelName()); // NOI18N |
| this.panel = panel; |
| panel.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, new Integer(stepIndex)); // NOI18N |
| // names of currently used steps |
| panel.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, allSteps); // NOI18N |
| } |
| |
| private BasicWizardIterator.Panel getPanel() { |
| return panel; |
| } |
| |
| public Component getComponent() { |
| return getPanel(); |
| } |
| |
| public @Override void storeSettings(WizardDescriptor wiz) { |
| if (WizardDescriptor.NEXT_OPTION.equals(wiz.getValue()) || |
| WizardDescriptor.FINISH_OPTION.equals(wiz.getValue())) { |
| panel.storeToDataModel(); |
| } |
| //XXX hack |
| wiz.putProperty("NewFileWizard_Title", null); // NOI18N |
| } |
| |
| public @Override void readSettings(WizardDescriptor wiz) { |
| // mkleint - copied from someplace.. is definitely weird.. |
| // XXX hack, TemplateWizard in final setTemplateImpl() forces new wizard's title |
| // this name is used in NewProjectWizard to modify the title |
| Object substitute = getPanel().getClientProperty("NewFileWizard_Title"); // NOI18N |
| if (substitute != null) { |
| wiz.putProperty("NewFileWizard_Title", substitute); // NOI18N |
| } |
| |
| if (WizardDescriptor.NEXT_OPTION.equals(wiz.getValue()) || wiz.getValue() == null) { |
| panel.readFromDataModel(); |
| } |
| } |
| |
| public @Override HelpCtx getHelp() { |
| return getPanel().getHelp(); |
| } |
| |
| } |
| |
| } |
| |