source: main/trunk/gli/src/org/greenstone/gatherer/gui/ConfigFileEditor.java@ 30959

Last change on this file since 30959 was 30959, checked in by kjdon, 7 years ago

Made the ConfigEditor modal so that people can't be editing the format statements in the background making the configeditor's contents stale.

File size: 10.0 KB
Line 
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
26package org.greenstone.gatherer.gui;
27
28import org.greenstone.gatherer.Configuration;
29import org.greenstone.gatherer.Dictionary;
30import org.greenstone.gatherer.Gatherer;
31import org.greenstone.gatherer.cdm.CollectionConfigXMLReadWrite;
32import org.greenstone.gatherer.util.Codec;
33import org.greenstone.gatherer.util.InputStreamGobbler;
34import org.greenstone.gatherer.util.OutputStreamGobbler;
35import org.greenstone.gatherer.util.StaticStrings;
36import org.greenstone.gatherer.util.Utility;
37import org.greenstone.gatherer.util.XMLTools;
38
39import org.w3c.dom.*;
40
41
42import java.io.File;
43import java.io.IOException;
44
45import java.awt.*;
46import java.awt.event.*;
47import java.util.*;
48import javax.swing.*;
49import javax.swing.border.*;
50import javax.swing.event.*;
51
52
53public class ConfigFileEditor extends ModalDialog
54 implements ActionListener, DocumentListener
55{
56 public final File config_file;
57
58 private GLIButton cancel_button = null;
59 private GLIButton save_button = null;
60 private NumberedJTextArea editor = null;
61 private JTextArea editor_msgarea;
62
63 //private final String DEFAULT_PROCESSING_INSTRUCTION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
64
65 private static final Dimension SIZE = new Dimension(850,550);
66
67 public ConfigFileEditor() {
68
69 super(Gatherer.g_man, true);
70 setModal(true);
71 setSize(SIZE);
72
73 String collection_folder_path = Gatherer.getCollectDirectoryPath();
74 String collectionName = Gatherer.c_man.getCollection().getName(); // we won't be in this constructor if collection is null.
75 this.config_file = new File(collection_folder_path + File.separator + collectionName, Utility.CONFIG_GS3_FILE); // col config editing is a GS3 feature
76
77
78 // Most of the validation_msg_panel code is from Format4gs3Manager.java
79 JPanel validation_msg_panel = new JPanel();
80 JLabel validation_label = new JLabel(Dictionary.get("CDM.FormatManager.MessageBox"));
81 validation_label.setBorder(new EmptyBorder(10,10,10,10)); // add some margin
82 editor_msgarea = new JTextArea();
83
84 editor_msgarea.setCaretPosition(0);
85 editor_msgarea.setLineWrap(true);
86 editor_msgarea.setRows(3);
87 editor_msgarea.setWrapStyleWord(false);
88 editor_msgarea.setEditable(false);
89 editor_msgarea.setToolTipText(Dictionary.get("CDM.FormatManager.MessageBox_Tooltip"));
90 validation_msg_panel.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
91 validation_msg_panel.setLayout(new BorderLayout(5, 0));
92 validation_msg_panel.add(validation_label, BorderLayout.WEST);
93 validation_msg_panel.add(new JScrollPane(editor_msgarea), BorderLayout.CENTER);
94
95 // the all important XML editor
96 editor = new NumberedJTextArea(Dictionary.get("ConfigFileEditor.Tooltip"));
97 editor.getDocument().addDocumentListener(this);
98
99 save_button = new GLIButton(Dictionary.get("General.Save"), Dictionary.get("ConfigFileEditor.Save_Tooltip"));
100 cancel_button = new GLIButton(Dictionary.get("General.Cancel"), Dictionary.get("ConfigFileEditor.Cancel_Tooltip")); // tooltip is the same
101 cancel_button.addActionListener(this);
102 save_button.addActionListener(this);
103
104 // LAYOUT
105 JPanel button_panel = new JPanel(new FlowLayout());
106 button_panel.setComponentOrientation(Dictionary.getOrientation());
107 button_panel.add(editor.undoButton);
108 button_panel.add(editor.redoButton);
109 button_panel.add(cancel_button);
110 button_panel.add(save_button);
111
112 JPanel content_pane = (JPanel) getContentPane();
113 content_pane.setComponentOrientation(Dictionary.getOrientation());
114 content_pane.setLayout(new BorderLayout());
115 content_pane.add(validation_msg_panel, BorderLayout.NORTH);
116 content_pane.add(new JScrollPane(editor), BorderLayout.CENTER); // make editor scrollable
117 content_pane.add(button_panel, BorderLayout.SOUTH);
118
119
120 // NOW WE CAN PREPARE THE ACTUAL CONTENT TO GO INTO THE XML EDITOR TEXTAREA
121 Document xmlDoc = null;
122 xmlDoc = XMLTools.parseXMLFile(config_file);
123
124 if(xmlDoc != null) {
125
126 // Save the collectionConfig.xml before loading it.
127 String[] nonEscapingTagNames = { StaticStrings.FORMAT_STR, StaticStrings.DISPLAYITEM_STR };
128 XMLTools.writeXMLFile(this.config_file, xmlDoc, nonEscapingTagNames); //prepends proc instruction
129
130 // now load the contents
131 editor_msgarea.setBackground(Color.white);
132 StringBuffer sb = new StringBuffer();
133 XMLTools.xmlNodeToString(sb, xmlDoc.getDocumentElement(), true, " ", 0);
134 editor.setText(sb.toString());
135 //editor.setText(elementToString(xmlDoc.getDocumentElement(), true)); // reading in file this way adds processing instruction, which the parser doesn't like.
136
137 } else { // parsing failed
138 // so read in file as text and display as text and show the validation box in red
139
140 // Won't re-save file that is already invalid before it's even been edited through this Editor
141 System.err.println("*** Warning: Parsing error in file " + config_file + ".");
142 System.err.println("*** Not saving ahead of editing.");
143
144 String xml_str = Utility.readFile(config_file);
145
146 // re-parse to get error msg to display in validation field
147
148 // but first get rid of the preprocessing instruction, as this will fail parsing
149 String processingInstruction = getProcessingInstruction(xml_str);
150 xml_str = xml_str.replace(processingInstruction, "").trim(); // also trim newline at start
151
152 if(!xml_str.equals("")) {
153
154 String msg = XMLTools.parse(xml_str); // re-parse
155 editor_msgarea.setBackground(Color.red);
156 editor_msgarea.setText(msg); // display the parsing error
157 save_button.setEnabled(false);
158
159 editor.setText(xml_str); // display the xml contents with error and all
160
161 } else {
162 editor.setText("");
163 editor_msgarea.setText("Empty collection config file");
164 }
165 }
166
167 // Final dialog setup & positioning.
168 setDefaultCloseOperation(DISPOSE_ON_CLOSE); // get rid of this dialog when it's closed (on dispose())
169 getRootPane().setDefaultButton(save_button);
170 Dimension screen_size = Configuration.screen_size;
171 setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
172 }
173
174 public void actionPerformed(ActionEvent e) {
175
176 if(e.getSource() == cancel_button) {
177 this.dispose(); // get rid of this dialog, we're done
178 }
179 else if(e.getSource() == save_button) {
180 // write out the XML to the collectionConfig.xml file and we're done.
181
182 // already know the xml in the textarea is valid, else the save_button would have been inactive
183 Document xml_file_doc = XMLTools.getDOM(editor.getText());
184 // This code from FormatConversionDialog.dispose()
185 // saves the XML, prepending the processing instruction (<?xml ... ?>)
186 String[] nonEscapingTagNames = { StaticStrings.FORMAT_STR, StaticStrings.DISPLAYITEM_STR };
187 XMLTools.writeXMLFile(this.config_file, xml_file_doc, nonEscapingTagNames);
188
189 this.dispose(); // get rid of this dialog, we're done
190
191 // close and reopen the collection in GLI
192 String current_collection_filepath = Gatherer.c_man.getCollection().getCollectionPath();
193 Gatherer.c_man.closeCollection();
194 Gatherer.c_man.loadCollection(current_collection_filepath);
195 }
196 }
197
198
199
200 // This method returns a proper processing instruction (starts with <?xml and ends with ?>)
201 // else the empty string is returned
202 public String getProcessingInstruction(String xmlStr) {
203 String processingInstruction = "";
204
205 xmlStr = xmlStr.trim();
206 if(xmlStr.startsWith("<?xml")) {
207 int endIndex = xmlStr.indexOf("?>"); // end of processing instruction
208
209 if(endIndex != -1) {
210 endIndex += 2;
211 processingInstruction = xmlStr.substring(0, endIndex);
212 }
213 }
214 return processingInstruction;
215 }
216
217
218 // THE FOLLOWING FUNCTIONS ARE LARGELY FROM Format4gs3Manager.java.EditorListener
219 public void changedUpdate(DocumentEvent e)
220 {
221 update();
222 }
223
224 public void insertUpdate(DocumentEvent e)
225 {
226 update();
227 updateUndo("insert");
228
229 }
230
231 public void removeUpdate(DocumentEvent e)
232 {
233 update();
234 updateUndo("remove");
235
236 }
237
238 private void updateUndo(String from)
239 {
240
241 editor.undoButton.setEnabled(true);
242 }
243
244 public void update()
245 {
246
247 String xml_str = editor.getText();
248
249 // Processing instructions "<?xml...?>" are no longer displayed in the editor (but
250 // they are written out to the file on save) so we don't need to deal with them here.
251
252 // can't parse with processing instruction <?xml...?>, so remove that
253 ///String processingInstruction = getProcessingInstruction(xml_str);
254 ///xml_str = xml_str.replace(processingInstruction, "");
255 // now can parse the XML portion without the processing instruction,
256 // while the original XML remains unchanged in the editor area
257 // If the processing instruction was incomplete, then xml_str would still
258 // include the incomplete processing instruction, and parsing below will catch the error.
259
260 String msg = XMLTools.parse(xml_str);
261 editor_msgarea.setText(msg);
262
263 if (msg.startsWith(XMLTools.WELLFORMED))
264 {
265 editor_msgarea.setBackground(Color.white);
266 save_button.setEnabled(true);
267 }
268 else
269 {
270 editor_msgarea.setBackground(Color.red);
271 save_button.setEnabled(false);
272 }
273 }
274
275}
Note: See TracBrowser for help on using the repository browser.