1 | /**
|
---|
2 | *#########################################################################
|
---|
3 | *
|
---|
4 | * A component of the Gatherer application, part of the Greenstone digital
|
---|
5 | * library suite from the New Zealand Digital Library Project at the
|
---|
6 | * University of Waikato, New Zealand.
|
---|
7 | *
|
---|
8 | * Copyright (C) 1999 New Zealand Digital Library Project
|
---|
9 | *
|
---|
10 | * This program is free software; you can redistribute it and/or modify
|
---|
11 | * it under the terms of the GNU General Public License as published by
|
---|
12 | * the Free Software Foundation; either version 2 of the License, or
|
---|
13 | * (at your option) any later version.
|
---|
14 | *
|
---|
15 | * This program is distributed in the hope that it will be useful,
|
---|
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
18 | * GNU General Public License for more details.
|
---|
19 | *
|
---|
20 | * You should have received a copy of the GNU General Public License
|
---|
21 | * along with this program; if not, write to the Free Software
|
---|
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
23 | *########################################################################
|
---|
24 | */
|
---|
25 |
|
---|
26 | package org.greenstone.gatherer.gui;
|
---|
27 |
|
---|
28 | import org.greenstone.gatherer.Configuration;
|
---|
29 | import org.greenstone.gatherer.Dictionary;
|
---|
30 | import org.greenstone.gatherer.Gatherer;
|
---|
31 | import org.greenstone.gatherer.cdm.CollectionConfigXMLReadWrite;
|
---|
32 | import org.greenstone.gatherer.util.Codec;
|
---|
33 | import org.greenstone.gatherer.util.InputStreamGobbler;
|
---|
34 | import org.greenstone.gatherer.util.OutputStreamGobbler;
|
---|
35 | import org.greenstone.gatherer.util.StaticStrings;
|
---|
36 | import org.greenstone.gatherer.util.XMLTools;
|
---|
37 |
|
---|
38 | import org.w3c.dom.*;
|
---|
39 |
|
---|
40 | import java.io.File;
|
---|
41 | import java.io.IOException;
|
---|
42 |
|
---|
43 | import java.awt.*;
|
---|
44 | import java.awt.event.*;
|
---|
45 | import java.util.*;
|
---|
46 | import javax.swing.*;
|
---|
47 | import javax.swing.border.*;
|
---|
48 | import javax.swing.event.*;
|
---|
49 |
|
---|
50 |
|
---|
51 | // TO DO:
|
---|
52 | // + StreamGobblers: http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html
|
---|
53 | // Need to test on Windows: the Ctrl-D/Ctrl-Z sent to formatconverter.exe. May not need to do anything special for Windows now that this code is using StreamGobblers to process the in/out streams of the process
|
---|
54 | // + Need to use dictionary for labels
|
---|
55 | // X convertFormat() for remote GS. Remote does not display Format Conversion wizard
|
---|
56 | // + HTML tidy (put all "<br/>" back to "<br>" in luce/etc/collectionConfig.xml and run again)
|
---|
57 | // + Help tooltips on buttons
|
---|
58 | // + Undo, Redo buttons
|
---|
59 | // X Split class into dialog/widgets and data processing?
|
---|
60 | // http://www.java2s.com/Tutorial/Java/0240__Swing/SettingJOptionPanebuttonlabelstoFrench.htm
|
---|
61 |
|
---|
62 | public class FormatConversionDialog extends ModalDialog
|
---|
63 | {
|
---|
64 | public static final String GSF_FORMAT_GS2_TAG = "gsf:format-gs2";
|
---|
65 | private static final String GSF_GS3_ROOT_TAG = "gsf:gs3-root";
|
---|
66 |
|
---|
67 | // The cmdline programs launched by this dialog
|
---|
68 | private static final int XMLTIDY = 0;
|
---|
69 | private static final int FORMATCONVERTER = 1;
|
---|
70 | private static final int FORMATCONVERTER_DOCUMENTNODE = 2;
|
---|
71 | private static final int FORMATCONVERTER_CLASSIFIERNODE = 3;
|
---|
72 |
|
---|
73 | // Online HTML tidy for learning usage: http://infohound.net/tidy/
|
---|
74 | private static final String[] xmltidy_cmd_args = {"tidy", "-config", Configuration.getGS3BinPath() + "tidyconfig.cfg", "-utf8", "-wrap", "0", "-raw", "-q"}; // {"tidy", "-xml", "-utf8"};
|
---|
75 | private static final String[] formatconverter_cmd_base_args = {Configuration.getGS3BinOSPath() + "formatconverter", "--silent"};
|
---|
76 |
|
---|
77 | private static final Dimension SIZE = new Dimension(640,480);
|
---|
78 |
|
---|
79 | // the important member variables
|
---|
80 | private File collect_cfg_file = null;
|
---|
81 | private Document xml_file_doc = null;
|
---|
82 | private NodeList gsf_format_gs2_list = null;
|
---|
83 |
|
---|
84 | private int current_index = -1;
|
---|
85 | private int dlgResult = OpenCollectionDialog.OK_OPTION;
|
---|
86 | private int process_exitValue = -1;
|
---|
87 |
|
---|
88 | // widgets
|
---|
89 | final String WARNING_TITLE = Dictionary.get("General.Warning")
|
---|
90 | + ": " + Dictionary.get("FormatConversionDialog.Invalid_XML")
|
---|
91 | + " " + Dictionary.get("FormatConversionDialog.Invalid_XML_Warning_Title");
|
---|
92 |
|
---|
93 | private static final Border EMPTYBORDER = new EmptyBorder(5, 5, 5, 5);
|
---|
94 | private JLabel section_label = null;
|
---|
95 | private GLIButton cancel_button = null;
|
---|
96 | private GLIButton next_button = null;
|
---|
97 | private GLIButton accept_all_button = null;
|
---|
98 | private GLIButton htmltidy_button = null;
|
---|
99 | private GLIButton xmltidy_button = null;
|
---|
100 | // the 2 NumberedJTextAreas. Each provide their own undo and redo buttons already hooked up to listeners
|
---|
101 | private NumberedJTextArea gs2_textarea = null;
|
---|
102 | private NumberedJTextArea gs3_textarea = null;
|
---|
103 | private JLabel count_label = null;
|
---|
104 | private JLabel statusbar = null;
|
---|
105 |
|
---|
106 | public FormatConversionDialog (File collect_cfg_file, Document xml_file_doc, NodeList gsf_format_gs2_list) {
|
---|
107 | super(Gatherer.g_man, "", true);
|
---|
108 |
|
---|
109 | this.collect_cfg_file = collect_cfg_file;
|
---|
110 | this.xml_file_doc = xml_file_doc;
|
---|
111 | this.gsf_format_gs2_list = gsf_format_gs2_list;
|
---|
112 |
|
---|
113 | this.setComponentOrientation(Dictionary.getOrientation());
|
---|
114 | setSize(SIZE);
|
---|
115 | setTitle(Dictionary.get("FormatConversionDialog.Title"));
|
---|
116 | this.addWindowListener(new WindowClosingListener()); // the dialog's top right close button should behave as a Cancel press
|
---|
117 | setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
---|
118 |
|
---|
119 | // The NumberedJTextArea provides its own undo and redo buttons, already hooked up to listeners
|
---|
120 | // Just need to place these buttons in the dialog
|
---|
121 | gs2_textarea = new NumberedJTextArea("gs2", Dictionary.get("FormatConversionDialog.GS2_Text_Tooltip"));
|
---|
122 | gs3_textarea = new NumberedJTextArea("gs3", Dictionary.get("FormatConversionDialog.GS3_Text_Tooltip"));
|
---|
123 |
|
---|
124 |
|
---|
125 | JPanel midbutton_panel = new JPanel(); // FlowLayout by default in a JPanel
|
---|
126 | midbutton_panel.setComponentOrientation(Dictionary.getOrientation());
|
---|
127 |
|
---|
128 | JButton reconvert_button = new GLIButton(Dictionary.get("FormatConversionDialog.Reconvert"), Dictionary.get("FormatConversionDialog.Reconvert_Tooltip"));
|
---|
129 |
|
---|
130 | midbutton_panel.add(gs2_textarea.undoButton);
|
---|
131 | midbutton_panel.add(gs2_textarea.redoButton);
|
---|
132 | midbutton_panel.add(reconvert_button);
|
---|
133 | reconvert_button.addActionListener(new ReconvertListener());
|
---|
134 | reconvert_button.setAlignmentY(Component.CENTER_ALIGNMENT);
|
---|
135 |
|
---|
136 | section_label = new JLabel("Section Label Goes Here"); // title will be replaced, don't need to translate
|
---|
137 | section_label.setBorder(EMPTYBORDER);
|
---|
138 | section_label.setComponentOrientation(Dictionary.getOrientation());
|
---|
139 |
|
---|
140 | JPanel button1_panel = new JPanel();
|
---|
141 | button1_panel.setComponentOrientation(Dictionary.getOrientation());
|
---|
142 |
|
---|
143 | xmltidy_button = new GLIButton(Dictionary.get("FormatConversionDialog.XHTML_Tidy"), Dictionary.get("FormatConversionDialog.XHTML_Tidy_Tooltip"));
|
---|
144 | xmltidy_button.addActionListener(new XMLTidyButtonListener());
|
---|
145 |
|
---|
146 | button1_panel.add(gs3_textarea.undoButton);
|
---|
147 | button1_panel.add(gs3_textarea.redoButton);
|
---|
148 | button1_panel.add(xmltidy_button);
|
---|
149 |
|
---|
150 | JPanel button_panel = new JPanel(new FlowLayout());
|
---|
151 | button_panel.setComponentOrientation(Dictionary.getOrientation());
|
---|
152 | count_label = new JLabel("<count>"); // placeholder text for numbers, no need to translate
|
---|
153 | cancel_button = new GLIButton(Dictionary.get("General.Cancel"), Dictionary.get("FormatConversionDialog.Cancel_Tooltip"));
|
---|
154 | next_button = new GLIButton(Dictionary.get("FormatConversionDialog.Next"), Dictionary.get("FormatConversionDialog.Next_Tooltip"));
|
---|
155 | accept_all_button = new GLIButton(Dictionary.get("FormatConversionDialog.Accept_All"), Dictionary.get("FormatConversionDialog.Accept_All_Tooltip"));
|
---|
156 | cancel_button.addActionListener(new CancelButtonListener());
|
---|
157 | next_button.addActionListener(new NextButtonListener());
|
---|
158 | accept_all_button.addActionListener(new AcceptAllButtonListener());
|
---|
159 | button_panel.add(cancel_button);
|
---|
160 | button_panel.add(next_button);
|
---|
161 | button_panel.add(accept_all_button);
|
---|
162 | button_panel.add(count_label);
|
---|
163 |
|
---|
164 |
|
---|
165 | JPanel centre_panel = new JPanel();
|
---|
166 | centre_panel.setLayout(new BoxLayout(centre_panel, BoxLayout.Y_AXIS));
|
---|
167 | centre_panel.setComponentOrientation(Dictionary.getOrientation());
|
---|
168 | centre_panel.setBorder(EMPTYBORDER);
|
---|
169 | centre_panel.add(new JScrollPane(gs2_textarea));
|
---|
170 | centre_panel.add(midbutton_panel);
|
---|
171 | centre_panel.add(new JScrollPane(gs3_textarea));
|
---|
172 |
|
---|
173 | JPanel bottom_panel = new JPanel();
|
---|
174 | bottom_panel.setLayout(new BoxLayout(bottom_panel, BoxLayout.Y_AXIS));
|
---|
175 | bottom_panel.setComponentOrientation(Dictionary.getOrientation());
|
---|
176 | bottom_panel.setBorder(EMPTYBORDER);
|
---|
177 |
|
---|
178 | bottom_panel.add(button1_panel);
|
---|
179 | bottom_panel.add(button_panel);
|
---|
180 | statusbar = new JLabel("");
|
---|
181 | statusbar.setBorder(EMPTYBORDER);
|
---|
182 | // http://stackoverflow.com/questions/2560784/how-to-center-elements-in-the-boxlayout-using-center-of-the-element
|
---|
183 | statusbar.setAlignmentX(Component.CENTER_ALIGNMENT);
|
---|
184 | bottom_panel.add(statusbar);
|
---|
185 |
|
---|
186 | // add all the widgets to the contentpane
|
---|
187 | JPanel content_pane = (JPanel) getContentPane();
|
---|
188 | content_pane.setComponentOrientation(Dictionary.getOrientation());
|
---|
189 | content_pane.setLayout(new BorderLayout());
|
---|
190 | //content_pane.setBorder(EMPTYBORDER);
|
---|
191 |
|
---|
192 | content_pane.add(section_label, BorderLayout.NORTH);
|
---|
193 | content_pane.add(centre_panel, BorderLayout.CENTER);
|
---|
194 | content_pane.add(bottom_panel, BorderLayout.SOUTH);
|
---|
195 |
|
---|
196 |
|
---|
197 | // Final dialog setup & positioning.
|
---|
198 | getRootPane().setDefaultButton(next_button);
|
---|
199 | Dimension screen_size = Configuration.screen_size;
|
---|
200 | setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
|
---|
201 | screen_size = null;
|
---|
202 | //setVisible(true);
|
---|
203 | }
|
---|
204 |
|
---|
205 |
|
---|
206 | public int getDialogResult() {
|
---|
207 | return dlgResult; // OK_OPTION or CANCEL_OPTION
|
---|
208 | }
|
---|
209 |
|
---|
210 | //*************************PROCESSING FUNCTIONS***************************//
|
---|
211 | public static int checkForGS2FormatStatements(File collect_cfg_file) {
|
---|
212 |
|
---|
213 | if(Gatherer.GS3 && collect_cfg_file.getAbsolutePath().endsWith(".xml")) {
|
---|
214 |
|
---|
215 | //System.err.println("*** Opening an xml config file");
|
---|
216 |
|
---|
217 | Document xml_file_doc = XMLTools.parseXMLFile(collect_cfg_file);
|
---|
218 | Element root = xml_file_doc.getDocumentElement();
|
---|
219 |
|
---|
220 | // check if there are any <gsf:format-gs2 /> elements. If there are, then may need to process them
|
---|
221 |
|
---|
222 | //NodeList gsf_format_gs2_list = root.getElementsByTagNameNS("gsf", "format-gs2");
|
---|
223 | NodeList gsf_format_gs2_list = root.getElementsByTagName(FormatConversionDialog.GSF_FORMAT_GS2_TAG);
|
---|
224 | if(gsf_format_gs2_list != null && gsf_format_gs2_list.getLength() > 0) {
|
---|
225 |
|
---|
226 | // Sample the first of the <gsf:gs2-format/> elements to
|
---|
227 | // check we don't have any CDataSections in the <gsf:gs2-format/> elements
|
---|
228 | // If the first <gsf:gs2-format/> has a CDataSection, it means we've already
|
---|
229 | // converted it to GS3 format statements during an earlier GLI session.
|
---|
230 |
|
---|
231 | Node gs2format = gsf_format_gs2_list.item(0);
|
---|
232 | //gs2format.normalize();
|
---|
233 | NodeList children = gs2format.getChildNodes();
|
---|
234 |
|
---|
235 | for(int i = 0; i < children.getLength(); i++) {
|
---|
236 | Node child = children.item(i);
|
---|
237 | if(child.getNodeType() == Node.CDATA_SECTION_NODE) {
|
---|
238 | // there are GS2 statements in col config, but they've already been converted to GS3
|
---|
239 | // can open the collection without going through the FormatConversionDialog
|
---|
240 | return OpenCollectionDialog.OK_OPTION;
|
---|
241 | }
|
---|
242 | }
|
---|
243 | System.err.println("*** Found GS2 format statements in config file to be converted to GS3.");
|
---|
244 |
|
---|
245 |
|
---|
246 | // if remote GS3, do we open the collection with the html-encoded GS2 format statements
|
---|
247 | // or do we not allow the remote user to open such a collection at all?
|
---|
248 | // For now we allow them to open it, but print a warning that conversions are not possible.
|
---|
249 |
|
---|
250 | if(Gatherer.isGsdlRemote) { // remote GS3
|
---|
251 | System.err.println("*** Cannot convert GS2 collections from a remote GS3 server.");
|
---|
252 | return OpenCollectionDialog.OK_OPTION;
|
---|
253 | }
|
---|
254 |
|
---|
255 | // If we get here, it means there were no CDataSections in the first (any) <gsf:gs2-format/>
|
---|
256 | // This means it's the first time the GS2 collection is being opened in GLI
|
---|
257 | // Open the FormatCconversionDialog and convert the gs2 statements to gs3:
|
---|
258 | FormatConversionDialog formatconversionDlg = new FormatConversionDialog(collect_cfg_file, xml_file_doc, gsf_format_gs2_list);
|
---|
259 | formatconversionDlg.convertGS2FormatStatements();
|
---|
260 | return formatconversionDlg.getDialogResult();
|
---|
261 |
|
---|
262 | }
|
---|
263 | }
|
---|
264 | return OpenCollectionDialog.OK_OPTION; // no GS2 statements in col config, and can open the collection
|
---|
265 | }
|
---|
266 |
|
---|
267 |
|
---|
268 | /**
|
---|
269 | * runInteractiveProgram() runs a cmdline program that reads from stdinput
|
---|
270 | * until Ctrl-D is encountered. It outputs the result to stdout.
|
---|
271 | *
|
---|
272 | * The cmdline programs HTML Tidy and FormatConverter both behave the same way:
|
---|
273 | * When the formatconverter binary is run in silent mode, it expects input
|
---|
274 | * followed by a newline and then EOF (or if no newline, then 2 EOFs)
|
---|
275 | * which is Ctrl-D on Linux/Mac and Ctrl-Z on Windows.
|
---|
276 | * Then the cmdline program exits by printing the result of the conversion.
|
---|
277 | *
|
---|
278 | * Explicitly sending EOFs from java is no longer necessary, as the OutputStreamGobbler
|
---|
279 | * Thread takes care of closing the process stream.
|
---|
280 | *
|
---|
281 | * HTMLTidy returns 0 if no warnings or errors, 1 if just Warnings, 2 if Errors (failure)
|
---|
282 | * http://sourceforge.net/p/tidy/mailman/tidy-develop/thread/[email protected]/
|
---|
283 | *
|
---|
284 | * This code uses the StreamGobbler classes based on
|
---|
285 | * http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2
|
---|
286 | */
|
---|
287 | public String runInteractiveProgram(int program, String inputstr) {
|
---|
288 | String outputstr = "";
|
---|
289 | String[] command_args;
|
---|
290 | process_exitValue = -1;
|
---|
291 |
|
---|
292 | switch(program) {
|
---|
293 | case XMLTIDY:
|
---|
294 | command_args = xmltidy_cmd_args;
|
---|
295 | break;
|
---|
296 | case FORMATCONVERTER:
|
---|
297 | command_args = formatconverter_cmd_base_args;
|
---|
298 | break;
|
---|
299 | case FORMATCONVERTER_DOCUMENTNODE:
|
---|
300 | case FORMATCONVERTER_CLASSIFIERNODE:
|
---|
301 | command_args = new String[formatconverter_cmd_base_args.length+1];
|
---|
302 | System.arraycopy(formatconverter_cmd_base_args, 0, command_args, 0, formatconverter_cmd_base_args.length);
|
---|
303 | if(program == FORMATCONVERTER_DOCUMENTNODE) {
|
---|
304 | command_args[command_args.length-1] = "--documentNode";
|
---|
305 | } else if(program == FORMATCONVERTER_CLASSIFIERNODE) {
|
---|
306 | command_args[command_args.length-1] = "--classifierNode";
|
---|
307 | }
|
---|
308 | break;
|
---|
309 | default:
|
---|
310 | System.err.println("*** Unrecognised program code: " + program);
|
---|
311 | return outputstr;
|
---|
312 | }
|
---|
313 |
|
---|
314 | // Generate the formatconverter command
|
---|
315 | /*if (Gatherer.isGsdlRemote) {
|
---|
316 |
|
---|
317 | }*/
|
---|
318 |
|
---|
319 | try {
|
---|
320 |
|
---|
321 | Runtime rt = Runtime.getRuntime();
|
---|
322 | Process prcs = null;
|
---|
323 |
|
---|
324 | prcs = rt.exec(command_args);
|
---|
325 |
|
---|
326 | // send inputstr to process
|
---|
327 | OutputStreamGobbler inputGobbler = new OutputStreamGobbler(prcs.getOutputStream(), inputstr);
|
---|
328 |
|
---|
329 | // monitor for any error messages
|
---|
330 | InputStreamGobbler errorGobbler = new InputStreamGobbler(prcs.getErrorStream(), true);
|
---|
331 |
|
---|
332 | // monitor for the expected output line(s)
|
---|
333 | InputStreamGobbler outputGobbler = new InputStreamGobbler(prcs.getInputStream());
|
---|
334 |
|
---|
335 | // kick them off
|
---|
336 | inputGobbler.start();
|
---|
337 | errorGobbler.start();
|
---|
338 | outputGobbler.start();
|
---|
339 |
|
---|
340 | // any error???
|
---|
341 | process_exitValue = prcs.waitFor();
|
---|
342 | //System.out.println("ExitValue: " + exitVal);
|
---|
343 |
|
---|
344 | // From the comments of
|
---|
345 | // http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2
|
---|
346 | // To avoid running into nondeterministic failures to get the process output
|
---|
347 | // if there's no waiting for the threads, call join() on each Thread (StreamGobbler) object:
|
---|
348 | outputGobbler.join();
|
---|
349 | errorGobbler.join();
|
---|
350 | inputGobbler.join();
|
---|
351 |
|
---|
352 | outputstr = outputGobbler.getOutput();
|
---|
353 | String errmsg = errorGobbler.getOutput();
|
---|
354 | if(!errmsg.equals("")) {
|
---|
355 | System.err.println("*** Process errorstream: \n" + errmsg + "\n****");
|
---|
356 | }
|
---|
357 |
|
---|
358 | } catch(IOException ioe) {
|
---|
359 | System.err.println("IOexception " + ioe.getMessage());
|
---|
360 | //ioe.printStackTrace();
|
---|
361 | } catch(InterruptedException ie) {
|
---|
362 | System.err.println("Process InterruptedException " + ie.getMessage());
|
---|
363 | //ie.printStackTrace();
|
---|
364 | }
|
---|
365 |
|
---|
366 | return outputstr;
|
---|
367 | }
|
---|
368 |
|
---|
369 | public void convertGS2FormatStatements() {
|
---|
370 |
|
---|
371 | // at this point, we know there are one or more <gsf:format-gs2 /> elements
|
---|
372 | // process each of them as follows: unescape, then call formatconverter, then call html tidy on it
|
---|
373 | //NodeList gsf_format_gs2_list = root.getElementsByTagNameNS("gsf", "format-gs2");
|
---|
374 |
|
---|
375 | int len = gsf_format_gs2_list.getLength();
|
---|
376 |
|
---|
377 | for(int i = 0; i < len; i++) {
|
---|
378 |
|
---|
379 | Element gs2format = (Element)gsf_format_gs2_list.item(i);
|
---|
380 | String gs2formatstr = XMLTools.getElementTextValue(gs2format); // seems to already unescape the html entities
|
---|
381 | //gs2formatstr = Codec.transform(gs2formatstr, Codec.ESCAPEDHTML_TO_UNESCAPED);
|
---|
382 |
|
---|
383 | processFormatStatement(i, gs2formatstr);
|
---|
384 | }
|
---|
385 |
|
---|
386 | increment(); // modifies the textareas to initialise them
|
---|
387 | setVisible(true);
|
---|
388 | }
|
---|
389 |
|
---|
390 |
|
---|
391 | private String processFormatStatement(int i, String gs2formatstr) {
|
---|
392 | String errorMsg = "";
|
---|
393 |
|
---|
394 | boolean startsWithTableCell = (gs2formatstr.toLowerCase().startsWith("<td")) ? true : false;
|
---|
395 |
|
---|
396 | //System.err.println("*** Found: " + gs2formatstr);
|
---|
397 |
|
---|
398 | // Running formatconverter. Decide on whether to pass in option --documentNode|--classifierNode
|
---|
399 | int formatConverterProgramMode = formatConverterMode(i);
|
---|
400 | String gs3formatstr = runInteractiveProgram(formatConverterProgramMode, gs2formatstr);
|
---|
401 | gs3formatstr = gs3formatstr.replaceAll(">\\s+<", "><");
|
---|
402 |
|
---|
403 | //System.err.println("*** Format is now: " + gs3formatstr);
|
---|
404 |
|
---|
405 | String gs3formatstr_notags = gs3formatstr;
|
---|
406 | gs3formatstr = addSurroundingTags(gs3formatstr);
|
---|
407 |
|
---|
408 |
|
---|
409 | String validationMsg = XMLTools.parseDOM(gs3formatstr);
|
---|
410 | if(!validationMsg.startsWith(XMLTools.WELLFORMED)) {
|
---|
411 | // Run Html Tidy in XML mode
|
---|
412 | //System.err.println("*** Needing to run HTML Tidy on: ");
|
---|
413 | //System.err.println(gs3formatstr_notags);
|
---|
414 |
|
---|
415 |
|
---|
416 | // HTMLTidy returns 0 if no warnings or errors, 1 if just Warnings, 2 if Errors (failure)
|
---|
417 | // http://sourceforge.net/p/tidy/mailman/tidy-develop/thread/[email protected]/
|
---|
418 | String htmltidy_string = runInteractiveProgram(XMLTIDY, gs3formatstr_notags);
|
---|
419 |
|
---|
420 | if(process_exitValue >= 2) {
|
---|
421 | // System.err.println("@@@ Process exit value: " + process_exitValue);
|
---|
422 | errorMsg = Dictionary.get("FormatConversionDialog.Tidy_Failed")
|
---|
423 | + " " + Dictionary.get("FormatConversionDialog.XML_Still_Invalid");
|
---|
424 | } else {
|
---|
425 | errorMsg = "";
|
---|
426 |
|
---|
427 | gs3formatstr_notags = htmltidy_string;
|
---|
428 |
|
---|
429 | gs3formatstr_notags = removeHTMLTags(i, gs3formatstr_notags, startsWithTableCell);
|
---|
430 | gs3formatstr = addSurroundingTags(gs3formatstr_notags);
|
---|
431 |
|
---|
432 | // Having applied html-tidy, setGS3Format() will return true if it finally parsed
|
---|
433 | }
|
---|
434 | }
|
---|
435 |
|
---|
436 | // For now, assume HTML Tidy has worked and that the gs3format has now been parsed successfully
|
---|
437 |
|
---|
438 | boolean parsed = setGS3Format(i, gs3formatstr); // will parse the gs3formatstr into a DOM object
|
---|
439 | if(!parsed && errorMsg.equals("")) {
|
---|
440 | errorMsg = Dictionary.get("FormatConversionDialog.Tidy_Done")
|
---|
441 | + " " + Dictionary.get("FormatConversionDialog.XML_Still_Invalid");
|
---|
442 | }
|
---|
443 | return errorMsg;
|
---|
444 | //return gs3formatstr;
|
---|
445 | }
|
---|
446 |
|
---|
447 | // HTML tidy adds entire HTML tags around a single format statement. This method removes it.
|
---|
448 | private String removeHTMLTags(int i, String gs3formatstr_notags, boolean startsWithTD) {
|
---|
449 |
|
---|
450 | // if it's a VList classifier <gsf:template match="documentNode|classifierNode"/>
|
---|
451 | // and the gs2 format statement starts with a <td>,
|
---|
452 | // then remove up to and including the outermost <tr>,
|
---|
453 | // else remove up to and including the <body> tag
|
---|
454 |
|
---|
455 | String removeOuterTag = "body>";
|
---|
456 | Element parent = (Element)getParentNode(i); // gets parent of GS2format: <gsf:template>
|
---|
457 | if(parent.hasAttribute("match") && (!parent.hasAttribute("mode") || !parent.getAttribute("mode").equals("horizontal"))) {
|
---|
458 | if(startsWithTD) {
|
---|
459 | removeOuterTag = "tr>"; // remove the outermost <tr> cell HTML tidy added around the tablecell
|
---|
460 | }
|
---|
461 | }
|
---|
462 |
|
---|
463 | // <unwanted>
|
---|
464 | // <removeThisOuterTag>
|
---|
465 | // lines we want
|
---|
466 | // </removeThisOuterTag>
|
---|
467 | // <unwanted>
|
---|
468 |
|
---|
469 | int end = gs3formatstr_notags.indexOf(removeOuterTag);
|
---|
470 | if(end != -1) {
|
---|
471 | gs3formatstr_notags = gs3formatstr_notags.substring(end+removeOuterTag.length());
|
---|
472 | }
|
---|
473 | int start = gs3formatstr_notags.lastIndexOf("</"+removeOuterTag); //closing tag
|
---|
474 | if(start != -1) {
|
---|
475 | gs3formatstr_notags = gs3formatstr_notags.substring(0, start);
|
---|
476 | }
|
---|
477 |
|
---|
478 | //System.err.println("@@@@ " + startsWithTD + " - TAG: " + removeOuterTag + " - AFTER REMOVING TAGS:\n" + gs3formatstr_notags);
|
---|
479 |
|
---|
480 | return gs3formatstr_notags;
|
---|
481 | }
|
---|
482 |
|
---|
483 |
|
---|
484 | //**************** ACCESS FUNCTIONS ***************//
|
---|
485 |
|
---|
486 | // gs2 format text is the text string that goes into <gsf:format-gs2/>: <gsf:format-gs2>text</gsf:format-gs2>
|
---|
487 | private void setGS2Format(int i, String text) {
|
---|
488 | XMLTools.setElementTextValue(getGS2Format(i), text);
|
---|
489 | }
|
---|
490 |
|
---|
491 | // gs3FormatStr represents DOM, and must be parsed and appended as sibling to the gs2format element
|
---|
492 | // as <gsf:gs3-root/>. If it fails to parse, nest it in a CDATA element of <gsf:gs3-root/>
|
---|
493 | private boolean setGS3Format(int i, String gs3formatstr) {
|
---|
494 |
|
---|
495 | Document ownerDoc = getGS2Format(i).getOwnerDocument();
|
---|
496 | Node gs3format = null;
|
---|
497 | boolean parse_success = false;
|
---|
498 |
|
---|
499 |
|
---|
500 | String validationMsg = XMLTools.parseDOM(gs3formatstr);
|
---|
501 | if(!validationMsg.startsWith(XMLTools.WELLFORMED)) {
|
---|
502 | // silently add the gs3formatstr in a CDATA block into the root
|
---|
503 |
|
---|
504 | gs3formatstr = removeSurroundingTags(gs3formatstr);
|
---|
505 | gs3format = ownerDoc.createElement(GSF_GS3_ROOT_TAG);
|
---|
506 | Node cdataSection = ownerDoc.createCDATASection(gs3formatstr);
|
---|
507 | gs3format.appendChild(cdataSection);
|
---|
508 | parse_success = false;
|
---|
509 | }
|
---|
510 | else {
|
---|
511 |
|
---|
512 | // parse DOM into XML
|
---|
513 | Document doc = XMLTools.getDOM(gs3formatstr);
|
---|
514 | Element root = doc.getDocumentElement();
|
---|
515 | gs3format = ownerDoc.importNode(root, true); // an element
|
---|
516 | parse_success = true;
|
---|
517 |
|
---|
518 | // System.err.println("@@@@ ROOT:\n" + XMLTools.xmlNodeToString(root));
|
---|
519 | }
|
---|
520 |
|
---|
521 | // add gs3format element as sibling to gs2format element
|
---|
522 | Element oldgs3format = getGS3Format(i);
|
---|
523 | if(oldgs3format == null) {
|
---|
524 | getParentNode(i).appendChild(gs3format);
|
---|
525 | // System.err.println("@@@ APPEND");
|
---|
526 | } else {
|
---|
527 | // replace the existing
|
---|
528 | getParentNode(i).replaceChild(gs3format, oldgs3format);
|
---|
529 | // System.err.println("@@@ REPLACE");
|
---|
530 | }
|
---|
531 |
|
---|
532 | //http://stackoverflow.com/questions/12524727/remove-empty-nodes-from-a-xml-recursively
|
---|
533 |
|
---|
534 | return parse_success;
|
---|
535 | }
|
---|
536 |
|
---|
537 | private Node getParentNode(int i) {
|
---|
538 | return gsf_format_gs2_list.item(i).getParentNode();
|
---|
539 | }
|
---|
540 |
|
---|
541 | private Element getGS2Format(int i) {
|
---|
542 | return (Element)gsf_format_gs2_list.item(i);
|
---|
543 | }
|
---|
544 |
|
---|
545 | private String getGS2FormatString(int i) {
|
---|
546 | return XMLTools.getElementTextValue(getGS2Format(i));
|
---|
547 | }
|
---|
548 |
|
---|
549 | private Element getGS3Format(int i) {
|
---|
550 | Element parent = (Element)getParentNode(i);
|
---|
551 | NodeList nl = parent.getElementsByTagName(GSF_GS3_ROOT_TAG);
|
---|
552 | if(nl.getLength() > 0) {
|
---|
553 | return (Element)nl.item(0);
|
---|
554 | }
|
---|
555 | return null;
|
---|
556 | }
|
---|
557 |
|
---|
558 | private String getGS3FormatString(int i) {
|
---|
559 | Element gs3format = getGS3Format(i);
|
---|
560 | if(gs3format == null) {
|
---|
561 | return "";
|
---|
562 | } else {
|
---|
563 |
|
---|
564 | // if any child is a CData section, return its text as-is. There will be no indenting
|
---|
565 | NodeList children = gs3format.getChildNodes();
|
---|
566 | for(int j = 0 ; j < children.getLength(); j++) {
|
---|
567 | if(children.item(j).getNodeType() == Node.CDATA_SECTION_NODE) {
|
---|
568 | return children.item(j).getNodeValue(); // content of CDataSection
|
---|
569 | }
|
---|
570 | }
|
---|
571 |
|
---|
572 | // else we have proper nodes, return indented string
|
---|
573 | StringBuffer sb = new StringBuffer();
|
---|
574 | XMLTools.xmlNodeToString(sb, gs3format, true, " ", 0);
|
---|
575 | return sb.toString();
|
---|
576 | }
|
---|
577 | }
|
---|
578 |
|
---|
579 | private int formatConverterMode(int i) {
|
---|
580 | String docOrClassNodeType = "";
|
---|
581 |
|
---|
582 | // Given XML of the form:
|
---|
583 | // <browse|search>
|
---|
584 | // <format>
|
---|
585 | // <gsf:template match="documentNode|classifierNode" [mode=horizontal]>
|
---|
586 | // <gsf-format:gs2 />
|
---|
587 | // <gs3format/>
|
---|
588 | // </format>
|
---|
589 | // </browse|search>
|
---|
590 |
|
---|
591 | Element parent = (Element)getParentNode(i); // gets parent of GS2format: <gsf:template>
|
---|
592 | String nodeType = parent.getAttribute("match"); //e.g. documentNode, classifierNode, or "" if no match attr
|
---|
593 |
|
---|
594 | if(nodeType.equals("documentNode")) {
|
---|
595 | return FORMATCONVERTER_DOCUMENTNODE; // convert just the part of the format stmt applicable to documentNodes
|
---|
596 | } else if(nodeType.equals("classifierNode")) {
|
---|
597 | return FORMATCONVERTER_CLASSIFIERNODE; // convert just the part of the format stmt applicable to classifierNodes
|
---|
598 | }
|
---|
599 | return FORMATCONVERTER; // convert the entire format statement
|
---|
600 | }
|
---|
601 |
|
---|
602 | private String getLabel(int i) {
|
---|
603 | String label = "";
|
---|
604 |
|
---|
605 | // Given XML of the form:
|
---|
606 | // <browse|search>
|
---|
607 | // <format>
|
---|
608 | // <gsf:template match="documentNode|classifierNode" [mode=horizontal]>
|
---|
609 | // <gsf-format:gs2 />
|
---|
610 | // <gs3format/>
|
---|
611 | // </format>
|
---|
612 | // </browse|search>
|
---|
613 |
|
---|
614 | // Want to return the label: "browse|search > documentNode|classifierNode [> horizontal]"
|
---|
615 |
|
---|
616 | Element parent = (Element)getParentNode(i); // gets parent of GS2format: <gsf:template>
|
---|
617 | label = parent.getAttribute("match"); //e.g. documentNode, classifierNode
|
---|
618 |
|
---|
619 | if(parent.hasAttribute("mode")) { // e.g. classifierNode mode=horizontal
|
---|
620 | label = label + " > " + parent.getAttribute("mode");
|
---|
621 | }
|
---|
622 |
|
---|
623 | Element ancestor = (Element) parent.getParentNode().getParentNode(); // ancestor: <browse>|<search>
|
---|
624 | label = ancestor.getTagName() + " > " + label;
|
---|
625 |
|
---|
626 | return label;
|
---|
627 | }
|
---|
628 |
|
---|
629 | // gs2 format statements have spaces instead of newlines. For display, replace with newlines
|
---|
630 | private String makeLines(String gs2formatstr) {
|
---|
631 | return gs2formatstr.replaceAll(">\\s+<", ">\n<");
|
---|
632 | }
|
---|
633 |
|
---|
634 | private String singleLine(String gs2formatstr) {
|
---|
635 | return gs2formatstr.replace(">\n<", "> <"); // put the spaces back
|
---|
636 | }
|
---|
637 |
|
---|
638 | private String removeSurroundingTags(String xml)
|
---|
639 | {
|
---|
640 | //return xml.replace("<"+GSF_GS3_ROOT_TAG+" xmlns:gsf=\"http://www.greenstone.org/greenstone3/schema/ConfigFormat\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n", "").replace("\n</"+GSF_GS3_ROOT_TAG+">", "");//.trim();
|
---|
641 | return xml.replaceAll("<"+GSF_GS3_ROOT_TAG+" xmlns:gsf=(\"|\')http://www.greenstone.org/greenstone3/schema/ConfigFormat(\"|\') xmlns:xsl=(\"|\')http://www.w3.org/1999/XSL/Transform(\"|\')>\n?", "").replaceAll("\n?</"+GSF_GS3_ROOT_TAG+">", "");//.trim();
|
---|
642 | }
|
---|
643 |
|
---|
644 | private String addSurroundingTags(String gs3formatstr) {
|
---|
645 | return "<"+GSF_GS3_ROOT_TAG+" xmlns:gsf='http://www.greenstone.org/greenstone3/schema/ConfigFormat' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>"+gs3formatstr+"</"+GSF_GS3_ROOT_TAG+">";
|
---|
646 | }
|
---|
647 |
|
---|
648 | //*************************FUNCTIONS THAT INTERACT WITH WIDGETS************************//
|
---|
649 | // increment() loads the next values into the dialog
|
---|
650 | private boolean increment() {
|
---|
651 | current_index++;
|
---|
652 | section_label.setText ( getLabel(current_index) );
|
---|
653 | gs2_textarea.setText( makeLines(getGS2FormatString(current_index)) );
|
---|
654 | gs3_textarea.setText( removeSurroundingTags(getGS3FormatString(current_index)) );
|
---|
655 | statusbar.setText("");
|
---|
656 |
|
---|
657 | // as we're on a new screen of dialog, need to clear all undo/redo history
|
---|
658 | gs2_textarea.discardAllEdits(); // will disable redo/undo buttons
|
---|
659 | gs3_textarea.discardAllEdits();
|
---|
660 |
|
---|
661 | int len = gsf_format_gs2_list.getLength();
|
---|
662 | count_label.setText((current_index+1) + " / " + len);
|
---|
663 | if((current_index+1) == len) {
|
---|
664 | return false;
|
---|
665 | } else {
|
---|
666 | return true;
|
---|
667 | }
|
---|
668 | }
|
---|
669 |
|
---|
670 |
|
---|
671 | private void setStatus(String msg) {
|
---|
672 | statusbar.setText(msg);
|
---|
673 | }
|
---|
674 | private void setErrorStatus(String msg) {
|
---|
675 | statusbar.setBackground(Color.red);
|
---|
676 | statusbar.setText(msg);
|
---|
677 | }
|
---|
678 |
|
---|
679 |
|
---|
680 | public void dispose() {
|
---|
681 | //System.err.println("@@@@ DIALOG CLOSING!");
|
---|
682 | if(dlgResult != OpenCollectionDialog.CANCEL_OPTION) {
|
---|
683 | // Need to remove the <gsf:gs3-root/> siblings of all <gsf:format-gs2/>
|
---|
684 | // Then, get the children of each <gsf:gs3-root/> and add these as siblings of <gsf:format-gs2/>
|
---|
685 |
|
---|
686 |
|
---|
687 | int len = gsf_format_gs2_list.getLength();
|
---|
688 | for(int k=len-1; k >= 0; k--) {
|
---|
689 | Element parent = (Element)getParentNode(k);
|
---|
690 |
|
---|
691 | //parent.normalize();
|
---|
692 |
|
---|
693 | NodeList children = parent.getChildNodes();
|
---|
694 |
|
---|
695 | // now have to loop/remove nodes in reverse order, since the following loop
|
---|
696 | // modifies the very nodelist we're looping over by removing nodes from it
|
---|
697 |
|
---|
698 | int numChildren = children.getLength()-1;
|
---|
699 |
|
---|
700 | for(int i=numChildren; i >= 0; i--) {
|
---|
701 | //for(int i = 0; i < children.getLength(); i++) {
|
---|
702 | Node child = children.item(i);
|
---|
703 |
|
---|
704 | if(child.getNodeName().equals(GSF_FORMAT_GS2_TAG)) {
|
---|
705 | // if we're dealing with gs2-format-stmts, put their textnode contents in CData sections
|
---|
706 | // http://www.w3schools.com/xml/xml_cdata.asp
|
---|
707 | // This avoids having to look at html-encoded gs2-format tags in the Format pane
|
---|
708 |
|
---|
709 | Element gs2format = (Element)child;
|
---|
710 | String gs2formatstr = XMLTools.getElementTextValue(gs2format);
|
---|
711 | gs2formatstr = Codec.transform(gs2formatstr, Codec.ESCAPEDHTML_TO_UNESCAPED);
|
---|
712 |
|
---|
713 | Node textNode = XMLTools.getNodeTextNode(gs2format);
|
---|
714 | Node cdataSection = gs2format.getOwnerDocument().createCDATASection(gs2formatstr);
|
---|
715 | gs2format.replaceChild(cdataSection, textNode);
|
---|
716 | }
|
---|
717 | else if(child.getNodeName().equals(GSF_GS3_ROOT_TAG)) {
|
---|
718 |
|
---|
719 | // remove GS3 node and append its children to the parent in its place
|
---|
720 | // the <gsf:gs3-root /> elements wouldn't be in the xml_file_doc DOM tree
|
---|
721 | // unless they were valid XML, so don't need to check for validity here
|
---|
722 |
|
---|
723 | Node gs3root = child;
|
---|
724 | NodeList gs3_format_lines = gs3root.getChildNodes();
|
---|
725 |
|
---|
726 | for(int j = 0; j < gs3_format_lines.getLength(); j++) {
|
---|
727 | Node duplicate = gs3_format_lines.item(j).cloneNode(true);
|
---|
728 | parent.appendChild(duplicate);
|
---|
729 | }
|
---|
730 | gs3root = parent.removeChild(gs3root);
|
---|
731 | gs3root = null; // finished processing
|
---|
732 |
|
---|
733 | } // else - skip all nodes other than <gsf:format-gs2/> and <gsf:gs3-root/>
|
---|
734 | }
|
---|
735 | }
|
---|
736 |
|
---|
737 | Element root = xml_file_doc.getDocumentElement();
|
---|
738 | //System.err.println("### XML file to write out:\n" + XMLTools.xmlNodeToString(root));
|
---|
739 |
|
---|
740 | // Finally, write out the collection xml file
|
---|
741 | String[] nonEscapingTagNames = { StaticStrings.FORMAT_STR, StaticStrings.DISPLAYITEM_STR };
|
---|
742 | XMLTools.writeXMLFile(collect_cfg_file, xml_file_doc, nonEscapingTagNames);
|
---|
743 |
|
---|
744 | }
|
---|
745 | super.dispose();
|
---|
746 |
|
---|
747 | }
|
---|
748 |
|
---|
749 | //******************INNER CLASSES including LISTENERS and STREAMGOBBLERS****************//
|
---|
750 |
|
---|
751 | // windowClosing() is called when the user presses the top-right close button the dialog
|
---|
752 | // this means the user wanted to cancel out of the entire Format Conversion Wizard.
|
---|
753 | private class WindowClosingListener extends WindowAdapter {
|
---|
754 | public void windowClosing(WindowEvent e) {
|
---|
755 | dlgResult = OpenCollectionDialog.CANCEL_OPTION;
|
---|
756 | }
|
---|
757 | }
|
---|
758 |
|
---|
759 | private class ReconvertListener implements ActionListener {
|
---|
760 | public void actionPerformed(ActionEvent e) {
|
---|
761 | String gs2formatstr = singleLine(gs2_textarea.getText());
|
---|
762 | String errorMsg = processFormatStatement(current_index, gs2formatstr);
|
---|
763 | gs3_textarea.setText( removeSurroundingTags(getGS3FormatString(current_index)) );
|
---|
764 | if(!errorMsg.equals("")) {
|
---|
765 | setErrorStatus(errorMsg);
|
---|
766 | } else {
|
---|
767 | statusbar.setText("");
|
---|
768 | }
|
---|
769 | }
|
---|
770 | }
|
---|
771 |
|
---|
772 |
|
---|
773 | private class NextButtonListener implements ActionListener {
|
---|
774 | public void actionPerformed(ActionEvent e) {
|
---|
775 | //statusbar.setText("");
|
---|
776 |
|
---|
777 | // check if the GS3 format statement is valid XML before storing. If not, let user to decide
|
---|
778 | // whether they want to re-edit it or if they want to keep it as-is, in which case it needs
|
---|
779 | // to be stored as CDATA, which will make it an inactive format statement.
|
---|
780 | // See http://www.w3schools.com/xml/xml_cdata.asp
|
---|
781 | // setGS3Format() already stores invalidXML as CDATA.
|
---|
782 |
|
---|
783 | // Check if the GS3 format statement is valid XML before storing. If not, let the
|
---|
784 | // user to decide whether they want to re-edit it or store it as-is and continue
|
---|
785 |
|
---|
786 | // user okay-ed the lines currently displayed, store them
|
---|
787 | setGS2Format( current_index, singleLine(gs2_textarea.getText()) );
|
---|
788 | boolean parse_success = setGS3Format( current_index, addSurroundingTags(gs3_textarea.getText()) );
|
---|
789 |
|
---|
790 | if(!parse_success) { // invalid XML, warn the user
|
---|
791 | String message = Dictionary.get("FormatConversionDialog.Invalid_XML") + " " + Dictionary.get("FormatConversionDialog.Cancel_Or_Continue_Next");
|
---|
792 | int user_choice = JOptionPane.showConfirmDialog(FormatConversionDialog.this, message, WARNING_TITLE, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
|
---|
793 |
|
---|
794 | if(user_choice == JOptionPane.CANCEL_OPTION) {
|
---|
795 | return; // do nothing on this NextButton press. Don't increment. Let user re-adjust invalid XML for GS3 statement.
|
---|
796 | }
|
---|
797 | }
|
---|
798 |
|
---|
799 | if(increment()) {
|
---|
800 | repaint();
|
---|
801 | } else {
|
---|
802 | next_button.setEnabled(false);
|
---|
803 | getRootPane().setDefaultButton(accept_all_button);
|
---|
804 |
|
---|
805 | }
|
---|
806 |
|
---|
807 | }
|
---|
808 | }
|
---|
809 |
|
---|
810 | private class CancelButtonListener implements ActionListener {
|
---|
811 | public void actionPerformed(ActionEvent e) {
|
---|
812 | dlgResult = OpenCollectionDialog.CANCEL_OPTION;
|
---|
813 | FormatConversionDialog.this.dispose(); // close dialog
|
---|
814 | }
|
---|
815 | }
|
---|
816 |
|
---|
817 |
|
---|
818 | private class AcceptAllButtonListener implements ActionListener {
|
---|
819 | public void actionPerformed(ActionEvent e) {
|
---|
820 |
|
---|
821 | // user okay-ed the lines, store them
|
---|
822 | setGS2Format(current_index, gs2_textarea.getText());
|
---|
823 | String gs3formatstr = gs3_textarea.getText();
|
---|
824 | boolean parse_success = setGS3Format(current_index, addSurroundingTags(gs3formatstr));
|
---|
825 | String message = "";
|
---|
826 |
|
---|
827 | if(!parse_success) { // invalid XML for current format statement, warn the user
|
---|
828 | setErrorStatus(Dictionary.get("FormatConversionDialog.Invalid_XML"));
|
---|
829 |
|
---|
830 | message = Dictionary.get("FormatConversionDialog.Invalid_XML") + " " + Dictionary.get("FormatConversionDialog.Cancel_Or_Continue_Next");
|
---|
831 | }
|
---|
832 |
|
---|
833 | // Even if the current GS3 format statement is valid XML, the user could have pressed
|
---|
834 | // Accept All at the very start of the FormatConversion dialog too. Check all the
|
---|
835 | // subsequent format statements, and if any have invalid XML, warn user.
|
---|
836 | for(int i = current_index+1; parse_success && i < gsf_format_gs2_list.getLength(); i++) {
|
---|
837 | gs3formatstr = getGS3FormatString(i);
|
---|
838 | String validationMsg = XMLTools.parseDOM(gs3formatstr);
|
---|
839 | if(!validationMsg.startsWith(XMLTools.WELLFORMED)) {
|
---|
840 | parse_success = false;
|
---|
841 | message = Dictionary.get("FormatConversionDialog.Cancel_Or_Accept_All");
|
---|
842 | }
|
---|
843 | }
|
---|
844 |
|
---|
845 | if(!parse_success) {
|
---|
846 | int user_choice = JOptionPane.showConfirmDialog(FormatConversionDialog.this, message, WARNING_TITLE, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
|
---|
847 | if(user_choice == JOptionPane.CANCEL_OPTION) {
|
---|
848 | return; // Don't close the dialog. Let the user continue looking at this or subsequent GS3 format statements.
|
---|
849 | }
|
---|
850 | }
|
---|
851 |
|
---|
852 | // If we're here, then either the format statements parsed, or the user accepted them anyway
|
---|
853 | FormatConversionDialog.this.dispose(); // close dialog
|
---|
854 | }
|
---|
855 | }
|
---|
856 |
|
---|
857 | private class XMLTidyButtonListener implements ActionListener {
|
---|
858 | // run HTML tidy taking input from stdin
|
---|
859 | // http://www.w3.org/People/Raggett/tidy/
|
---|
860 | public void actionPerformed(ActionEvent e) {
|
---|
861 | String gs3formatstr_notags = gs3_textarea.getText();
|
---|
862 |
|
---|
863 | // Flag to determine which tags that HTML tidy adds need to be removed
|
---|
864 | boolean startsWithTableCell = (gs3formatstr_notags.trim().toLowerCase().startsWith("<td")) ? true : false;
|
---|
865 | // run HTML tidy on the GS3 format statement
|
---|
866 | String htmltidy_string = runInteractiveProgram(XMLTIDY, gs3formatstr_notags);
|
---|
867 |
|
---|
868 | if(process_exitValue >= 2) {
|
---|
869 | //System.err.println("@@@ Process exit value: " + process_exitValue);
|
---|
870 | setErrorStatus(Dictionary.get("FormatConversionDialog.Tidy_Failed"));
|
---|
871 | } else {
|
---|
872 | gs3formatstr_notags = htmltidy_string;
|
---|
873 |
|
---|
874 | // HTML tidy adds extra HTML markup around the formatstring, so will need to remove it:
|
---|
875 | gs3formatstr_notags = removeHTMLTags(current_index, gs3formatstr_notags, startsWithTableCell);
|
---|
876 |
|
---|
877 | // put the XML tags around the gs3 format string again so we can convert it to a DOM object
|
---|
878 | String gs3formatstr = addSurroundingTags(gs3formatstr_notags);
|
---|
879 |
|
---|
880 | boolean parse_success = setGS3Format(current_index, gs3formatstr); // converts to DOM object
|
---|
881 |
|
---|
882 | // Get indented GS3 format string from DOM object and display it in the text area
|
---|
883 | gs3_textarea.setText( removeSurroundingTags(getGS3FormatString(current_index)) );
|
---|
884 |
|
---|
885 | if(parse_success) {
|
---|
886 | statusbar.setText(Dictionary.get("FormatConversionDialog.Tidy_Done"));
|
---|
887 | } else {
|
---|
888 | setErrorStatus(Dictionary.get("FormatConversionDialog.Tidy_Done")
|
---|
889 | + " " + Dictionary.get("FormatConversionDialog.Error_GS3_Format")
|
---|
890 | + " " + Dictionary.get("FormatConversionDialog.Invalid_XML"));
|
---|
891 | }
|
---|
892 | }
|
---|
893 | }
|
---|
894 | }
|
---|
895 |
|
---|
896 | }
|
---|