xml.schema/src/org/netbeans/modules/xml/schema/wizard/SampleXMLGeneratorWizardIterator.java
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2009-2017 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
9 * The contents of this file are subject to the terms of either the GNU
10 * General Public License Version 2 only ("GPL") or the Common
11 * Development and Distribution License("CDDL") (collectively, the
12 * "License"). You may not use this file except in compliance with the
13 * License. You can obtain a copy of the License at
14 * http://www.netbeans.org/cddl-gplv2.html
15 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16 * specific language governing permissions and limitations under the
17 * License. When distributing the software, include this License Header
18 * Notice in each file and include the License file at
19 * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
20 * particular file as subject to the "Classpath" exception as provided
21 * by Oracle in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the
23 * License Header, with the fields enclosed by brackets [] replaced by
24 * your own identifying information:
25 * "Portions Copyrighted [year] [name of copyright owner]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Sun Microsystems, Inc. Portions Copyright 2009-2010 Sun
31 * Microsystems, Inc. All Rights Reserved.
33 * If you wish your version of this file to be governed by only the CDDL
34 * or only the GPL Version 2, indicate your decision by adding
35 * "[Contributor] elects to include this software in this distribution
36 * under the [CDDL or GPL Version 2] license." If you do not indicate a
37 * single choice of license, a recipient has the option to distribute
38 * your version of this file under either the CDDL, the GPL Version 2 or
39 * to extend the choice of license to its licensees as provided above.
40 * However, if you add GPL Version 2 code and therefore, elected the GPL
41 * Version 2 license, then the option applies only if the new code is
42 * made subject to such option by the copyright holder.
45 * To change this template, choose Tools | Templates
46 * and open the template in the editor.
48 package org.netbeans.modules.xml.schema.wizard;
50 import java.awt.Component;
51 import java.awt.Dialog;
52 import java.io.BufferedOutputStream;
54 import java.io.IOException;
55 import java.io.OutputStream;
56 import java.io.OutputStreamWriter;
57 import java.io.Writer;
59 import java.net.URISyntaxException;
61 import java.text.DateFormat;
62 import java.text.MessageFormat;
63 import java.util.Date;
64 import java.util.HashSet;
66 import java.util.NoSuchElementException;
68 import javax.swing.JComponent;
69 import javax.swing.event.ChangeListener;
70 import javax.xml.parsers.DocumentBuilder;
71 import javax.xml.parsers.DocumentBuilderFactory;
72 import javax.xml.transform.OutputKeys;
73 import javax.xml.transform.Result;
74 import javax.xml.transform.Transformer;
75 import javax.xml.transform.TransformerFactory;
76 import javax.xml.transform.dom.DOMSource;
77 import javax.xml.transform.stream.StreamResult;
78 import org.netbeans.api.project.FileOwnerQuery;
79 import org.netbeans.api.project.Project;
80 import org.netbeans.editor.BaseDocument;
81 import org.netbeans.modules.xml.api.EncodingUtil;
82 import org.netbeans.modules.xml.lib.GuiUtil;
83 import org.netbeans.modules.xml.schema.SchemaDataObject;
84 import org.netbeans.modules.xml.text.TextEditorSupport;
85 import org.netbeans.modules.xml.wizard.AbstractPanel;
86 import org.netbeans.modules.xml.wizard.DocumentModel;
87 import org.netbeans.modules.xml.wizard.SchemaParser;
88 import org.netbeans.modules.xml.wizard.XMLContentPanel;
89 import org.netbeans.modules.xml.wizard.XMLGeneratorVisitor;
90 import org.openide.DialogDisplayer;
91 import org.openide.WizardDescriptor;
92 import org.openide.cookies.EditCookie;
93 import org.openide.cookies.EditorCookie;
94 import org.openide.filesystems.FileObject;
95 import org.openide.filesystems.FileLock;
96 import org.openide.filesystems.FileSystem;
97 import org.openide.filesystems.FileUtil;
98 import org.openide.loaders.DataObject;
99 import org.openide.util.NbBundle;
100 import org.w3c.dom.Attr;
101 import org.w3c.dom.Document;
102 import org.w3c.dom.NamedNodeMap;
104 public final class SampleXMLGeneratorWizardIterator implements WizardDescriptor.InstantiatingIterator {
107 private WizardDescriptor.Panel[] panels;
108 private Project srcProject;
109 private FileObject schemaFileObject;
110 private DocumentModel model;
111 private XMLContentPanel xmlPanel;
112 private static String PREFIX = "ns0";
113 private static final String XML_EXT = "xml";
115 public SampleXMLGeneratorWizardIterator(SchemaDataObject dobj) {
116 schemaFileObject = dobj.getPrimaryFile();
117 this.srcProject = FileOwnerQuery.getOwner(schemaFileObject);
121 WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
122 initialize(wizardDescriptor);
123 wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
124 wizardDescriptor.setTitle(NbBundle.getMessage(SampleXMLGeneratorWizardIterator.class,"TITLE_XML_WIZARD"));
125 Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
126 dialog.getAccessibleContext().setAccessibleName(
127 NbBundle.getMessage(SampleXMLGeneratorWizardIterator.class,"TITLE_XML_WIZARD"));
128 dialog.getAccessibleContext().setAccessibleDescription(
129 NbBundle.getMessage(SampleXMLGeneratorWizardIterator.class,"TITLE_XML_WIZARD"));
130 dialog.setVisible(true);
132 boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
137 }catch (Exception e){
145 * Initialize panels representing individual wizard's steps and sets
146 * various properties for them influencing wizard appearance.
148 private WizardDescriptor.Panel[] getPanels() {
150 xmlPanel = new XMLContentPanel(true);
152 if (panels == null) {
153 panels = new WizardDescriptor.Panel[]{
154 //Templates.createSimpleTargetChooser(srcProject, folders)
155 new AbstractPanel.WizardStep(xmlPanel)
157 String[] steps = new String[panels.length];
158 for (int i = 0; i < panels.length; i++) {
159 Component c = panels[i].getComponent();
160 if (steps[i] == null) {
161 // Default step name to component name of panel. Mainly
162 // useful for getting the name of the target chooser to
163 // appear in the list of steps.
164 steps[i] = c.getName();
166 if (c instanceof JComponent) { // assume Swing components
167 JComponent jc = (JComponent) c;
168 // Sets step number of a component
169 jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, new Integer(i));
170 // Sets steps names for a panel
171 jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
172 // Turn on subtitle creation on each step
173 jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, Boolean.TRUE);
174 // Show steps on the left side with the image on the background
175 jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, Boolean.TRUE);
176 // Turn on numbering of all steps
177 jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, Boolean.TRUE);
184 public Set instantiate() throws IOException {
185 final String extension = XML_EXT;
187 String targetName = schemaFileObject.getName();
188 if (targetName == null || "null".equals(targetName)) { // NOI18N
189 targetName = "XMLDocument"; // NOI18N
192 final FileObject targetFolder = schemaFileObject.getParent();
193 String uniqueTargetName = targetName;
195 while (targetFolder.getFileObject(uniqueTargetName, extension) != null) {
196 uniqueTargetName = targetName + i;
200 final String name = uniqueTargetName;
202 // in atomic action create data object and return it
204 FileSystem filesystem = targetFolder.getFileSystem();
205 final FileObject[] fileObject = new FileObject[1];
206 String encoding = EncodingUtil.getProjectEncoding(targetFolder);
207 if (!EncodingUtil.isValidEncoding(encoding)) {
208 encoding = "UTF-8"; //NOI18N
210 String nameExt = name + "." + extension;
211 FileSystem.AtomicAction fsAction = new FileSystem.AtomicAction() {
212 public void run() throws IOException {
214 FileObject fo = targetFolder.createData(name, extension);
219 filesystem.runAtomicAction(fsAction);
220 StringBuffer sb = new StringBuffer();
222 writeXMLComment(sb, nameExt, encoding);
226 FileLock lock = null;
228 lock = fileObject[0].lock();
229 OutputStream out = fileObject[0].getOutputStream(lock);
230 out = new BufferedOutputStream(out, 999);
231 Writer writer = new OutputStreamWriter(out, encoding);
232 writer.write(sb.toString());
243 // perform default action and return
245 Set set = new HashSet(1);
246 DataObject createdObject = DataObject.find(fileObject[0]);
247 GuiUtil.performDefaultAction(createdObject);
248 set.add(createdObject);
250 formatXML(fileObject[0]);
254 public void initialize(WizardDescriptor wiz) {
256 URL targetFolderURL = null;
258 FileObject folder = schemaFileObject.getParent();
259 targetFolderURL = folder.getURL();
261 if (targetFolderURL.toExternalForm().endsWith("/") == false) {
262 targetFolderURL = new URL(targetFolderURL.toExternalForm() + "/");
264 } catch (IOException ignore) {
267 model = new DocumentModel(targetFolderURL);
268 File file = FileUtil.toFile(schemaFileObject);
269 String uri = file.getPath();
272 // escape the non-ASCII characters
273 uri = new URI(uri).toASCIIString();
274 } catch (URISyntaxException e) {
275 // the specified uri is not valid, it is too late to fix it now
278 model.setPrimarySchema(uri);
280 xmlPanel.setObject(model);
281 model.setPrefix(PREFIX);
282 String ns = SchemaParser.getNamespace(schemaFileObject);
283 model.setNamespace(ns);
286 public void uninitialize(WizardDescriptor wizard) {
290 public WizardDescriptor.Panel current() {
291 return panels[index];
294 public String name() {
295 return NbBundle.getMessage(SchemaWizardIterator.class, "TITLE_x_of_y",
296 Integer.valueOf(index + 1), Integer.valueOf(panels.length));
299 public boolean hasNext() {
300 return index < getPanels().length - 1;
303 public boolean hasPrevious() {
307 public void nextPanel() {
309 throw new NoSuchElementException();
314 public void previousPanel() {
315 if (!hasPrevious()) {
316 throw new NoSuchElementException();
321 // If nothing unusual changes in the middle of the wizard, simply:
322 public void addChangeListener(ChangeListener l) {
325 public void removeChangeListener(ChangeListener l) {
329 private void generateXMLBody(DocumentModel model, String root, StringBuffer writer){
330 XMLGeneratorVisitor visitor = new XMLGeneratorVisitor(model.getPrimarySchema(), model.getXMLContentAttributes(), writer);
331 visitor.generateXML(root);
335 private void modifyRootElementAttrs(FileObject fobj) {
337 File file = new File(fobj.getPath());
338 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
339 DocumentBuilder db = dbf.newDocumentBuilder();
340 Document doc = db.parse(file);
341 doc.getDocumentElement().normalize();
343 NamedNodeMap rootAttributes = doc.getDocumentElement().getAttributes();
344 Map<String, String> nsAttrs = model.getXMLContentAttributes().getNamespaceToPrefixMap();
346 if(nsAttrs == null || nsAttrs.size() == 0)
348 for(String ns:nsAttrs.keySet()) {
349 Attr galaxy = doc.createAttribute("xmlns:" + nsAttrs.get(ns));
351 rootAttributes.setNamedItem(galaxy);
354 //write to oputput file
355 Transformer transformer = TransformerFactory.newInstance().newTransformer();
356 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
358 DOMSource source = new DOMSource(doc);
359 Result result = new StreamResult(file);
360 transformer.transform(source, result);
362 } catch(Exception e) {
367 private void writeXMLComment(StringBuffer writer, String filename, String encoding) throws IOException {
368 writer.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n"); // NOI18N
369 writer.append("\n"); // NOI18N
371 Date now = new Date();
372 String currentDate = DateFormat.getDateInstance(DateFormat.LONG).format(now);
373 String currentTime = DateFormat.getTimeInstance(DateFormat.SHORT).format(now);
374 String userName = System.getProperty("user.name");
375 writer.append("<!--\n"); // NOI18N
376 writer.append(" Document : " + filename + "\n"); // NOI18N
377 writer.append(" Created on : " + currentDate + ", " + currentTime + "\n"); // NOI18N
378 writer.append(" Author : " + userName + "\n"); // NOI18N
379 writer.append(" Description:\n"); // NOI18N
380 writer.append(" Purpose of the document follows.\n"); // NOI18N
381 writer.append("-->\n"); // NOI18N
387 private void formatXML(FileObject fobj){
389 DataObject dobj = DataObject.find(fobj);
390 EditorCookie ec = dobj.getCookie(EditorCookie.class);
394 BaseDocument doc = (BaseDocument) ec.getDocument();
395 org.netbeans.modules.xml.text.api.XMLFormatUtil.reformat(doc, 0, doc.getLength());
396 EditCookie cookie = dobj.getCookie(EditCookie.class);
397 if (cookie instanceof TextEditorSupport) {
398 if (cookie != null) {
399 ((TextEditorSupport) cookie).saveDocument();
403 } catch (Exception e) {
404 //if exception , then the file will be informatted
410 private void modifyRootElementAttrs(StringBuffer xmlBuffer) {
411 Map<String, String> nsAttrs = model.getXMLContentAttributes().getNamespaceToPrefixMap();
413 if (nsAttrs == null || nsAttrs.size() == 0) {
416 int firstOccur = xmlBuffer.indexOf("xmlns");
417 int insertLoc = xmlBuffer.indexOf("xmlns", firstOccur + 1);
419 StringBuffer sb = new StringBuffer();
420 for (String ns : nsAttrs.keySet()) {
421 String xmlnsString = "xmlns:" + nsAttrs.get(ns) + "='" + ns + "'";
422 if (xmlBuffer.indexOf(xmlnsString) == -1) {
423 xmlBuffer.insert(insertLoc, xmlnsString + "\n ");
426 xmlBuffer.insert(insertLoc, sb.toString());
431 private void writeXMLFile(StringBuffer writer) throws IOException {
432 String root = model.getRoot();
436 String prefix = model.getPrefix();
437 String namespace = model.getNamespace();
438 if (prefix == null || "".equals(prefix)) {
439 writer.append("<" + root + " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n");
441 writer.append("<" + prefix + ":" + root + " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n");
444 if (prefix == null || "".equals(prefix)) {
445 writer.append(" xmlns='" + namespace + "'\n");
447 writer.append(" xmlns:" + prefix + "='" + namespace + "'\n");
449 writer.append(" xsi:schemaLocation='" + namespace + " " + schemaFileObject.getNameExt() + "'>\n");
450 generateXMLBody(model, root, writer);
451 modifyRootElementAttrs(writer);
452 if (prefix == null || "".equals(prefix)) {
453 writer.append("\n"); // NOI18N
454 writer.append("</" + root + ">\n"); // NOI18N
456 writer.append("\n"); // NOI18N
457 writer.append("</" + prefix + ":" + root + ">\n");
466 // If something changes dynamically (besides moving between panels), e.g.
467 // the number of panels changes in response to user input, then uncomment
468 // the following and call when needed: fireChangeEvent();
470 private Set<ChangeListener> listeners = new HashSet<ChangeListener>(1); // or can use ChangeSupport in NB 6.0
471 public final void addChangeListener(ChangeListener l) {
472 synchronized (listeners) {
476 public final void removeChangeListener(ChangeListener l) {
477 synchronized (listeners) {
481 protected final void fireChangeEvent() {
482 Iterator<ChangeListener> it;
483 synchronized (listeners) {
484 it = new HashSet<ChangeListener>(listeners).iterator();
486 ChangeEvent ev = new ChangeEvent(this);
487 while (it.hasNext()) {
488 it.next().stateChanged(ev);