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