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 | * <BR><BR>
|
---|
9 | *
|
---|
10 | * Author: John Thompson, Greenstone Digital Library, University of Waikato
|
---|
11 | *
|
---|
12 | * <BR><BR>
|
---|
13 | *
|
---|
14 | * Copyright (C) 1999 New Zealand Digital Library Project
|
---|
15 | *
|
---|
16 | * <BR><BR>
|
---|
17 | *
|
---|
18 | * This program is free software; you can redistribute it and/or modify
|
---|
19 | * it under the terms of the GNU General Public License as published by
|
---|
20 | * the Free Software Foundation; either version 2 of the License, or
|
---|
21 | * (at your option) any later version.
|
---|
22 | *
|
---|
23 | * <BR><BR>
|
---|
24 | *
|
---|
25 | * This program is distributed in the hope that it will be useful,
|
---|
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
28 | * GNU General Public License for more details.
|
---|
29 | *
|
---|
30 | * <BR><BR>
|
---|
31 | *
|
---|
32 | * You should have received a copy of the GNU General Public License
|
---|
33 | * along with this program; if not, write to the Free Software
|
---|
34 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
35 | *########################################################################
|
---|
36 | */
|
---|
37 | package org.greenstone.gatherer.gui;
|
---|
38 |
|
---|
39 | import java.awt.*;
|
---|
40 | import java.awt.event.*;
|
---|
41 | import java.io.File;
|
---|
42 | import java.net.*;
|
---|
43 | import java.util.*;
|
---|
44 | import javax.swing.*;
|
---|
45 | import javax.swing.border.*;
|
---|
46 | import javax.swing.event.*;
|
---|
47 | import javax.swing.tree.*;
|
---|
48 | import org.greenstone.gatherer.Configuration;
|
---|
49 | import org.greenstone.gatherer.Dictionary;
|
---|
50 | import org.greenstone.gatherer.Gatherer;
|
---|
51 | import org.greenstone.gatherer.WGet;
|
---|
52 | import org.greenstone.gatherer.file.FileNode;
|
---|
53 | import org.greenstone.gatherer.gui.tree.WorkspaceTree;
|
---|
54 | import org.greenstone.gatherer.util.StaticStrings;
|
---|
55 | import org.greenstone.gatherer.util.Utility;
|
---|
56 |
|
---|
57 | /**
|
---|
58 | * @author John Thompson, Greenstone Digital Library, University of Waikato
|
---|
59 | * @version 2.1
|
---|
60 | */
|
---|
61 | public class MirrorPane
|
---|
62 | extends JPanel {
|
---|
63 |
|
---|
64 | /** The threshold for when the advanced options get added */
|
---|
65 | static private final int THRESHOLD = Configuration.SYSTEMS_MODE;
|
---|
66 |
|
---|
67 | private boolean download_button_enabled = false;
|
---|
68 | private boolean ready = false;
|
---|
69 | private int current_mode;
|
---|
70 | private JButton clear_cache_button;
|
---|
71 | private JButton download_button;
|
---|
72 | private JCheckBox higher_checkbox;
|
---|
73 | private JCheckBox requisite_checkbox;
|
---|
74 | private JCheckBox same_host_checkbox;
|
---|
75 | private JScrollPane list_scroll;
|
---|
76 | private JComboBox depth_combobox;
|
---|
77 | private JPanel options_pane;
|
---|
78 | private JTextField url_field;
|
---|
79 | private Vector depth_model;
|
---|
80 | private WGet getter;
|
---|
81 |
|
---|
82 | public MirrorPane() {
|
---|
83 | super();
|
---|
84 | // Create a new wget thread
|
---|
85 | getter = new WGet();
|
---|
86 | getter.start();
|
---|
87 | // And retrieve its list of pending jobs
|
---|
88 | list_scroll = getter.getDownloadJobList();
|
---|
89 |
|
---|
90 | current_mode = Configuration.getMode();
|
---|
91 | // String user_dir = System.getProperty("user.dir"); // ****
|
---|
92 | // System.err.println("**** user dir = "+user_dir);
|
---|
93 | // Create
|
---|
94 | JPanel edit_pane = new JPanel();
|
---|
95 | JPanel details_pane = new JPanel();
|
---|
96 | options_pane = new JPanel();
|
---|
97 |
|
---|
98 | JPanel url_pane = new JPanel();
|
---|
99 | JLabel url_label = new JLabel();
|
---|
100 | Dictionary.registerText(url_label, "Mirroring.Source_URL");
|
---|
101 | url_field = new JTextField();
|
---|
102 | Dictionary.registerTooltip(url_field, "Mirroring.Source_URL_Tooltip");
|
---|
103 |
|
---|
104 | depth_model = new Vector();
|
---|
105 | depth_model.add(new DepthEntry(0, Dictionary.get("Mirroring.Download_Depth.Zero")));
|
---|
106 | /* @todo - add to dictionary */
|
---|
107 | depth_model.add(new DepthEntry(1, String.valueOf(1)));
|
---|
108 | /* @todo - add to dictionary */
|
---|
109 | depth_model.add(new DepthEntry(2, String.valueOf(2)));
|
---|
110 | /* @todo - add to dictionary */
|
---|
111 | depth_model.add(new DepthEntry(3, String.valueOf(3)));
|
---|
112 | /* @todo - add to dictionary */
|
---|
113 | depth_model.add(new DepthEntry(4, String.valueOf(4)));
|
---|
114 | /* @todo - add to dictionary */
|
---|
115 | depth_model.add(new DepthEntry(5, String.valueOf(5)));
|
---|
116 | depth_model.add(new DepthEntry(-1, Dictionary.get("Mirroring.Download_Depth.Unlimited")));
|
---|
117 | JPanel depth_pane = new JPanel();
|
---|
118 | JLabel depth_label = new JLabel();
|
---|
119 | Dictionary.registerText(depth_label, "Mirroring.Download_Depth");
|
---|
120 | depth_combobox = new JComboBox(depth_model);
|
---|
121 | Dictionary.registerTooltip(depth_combobox, "Mirroring.Download_Depth_Tooltip");
|
---|
122 |
|
---|
123 | requisite_checkbox = new JCheckBox();
|
---|
124 | Dictionary.registerText(requisite_checkbox, "Mirroring.Download_Embedded");
|
---|
125 |
|
---|
126 |
|
---|
127 | higher_checkbox = new JCheckBox();
|
---|
128 | Dictionary.registerText(higher_checkbox, "Mirroring.Higher_Directories");
|
---|
129 | higher_checkbox.addActionListener(new CheckboxClickListener());
|
---|
130 |
|
---|
131 | same_host_checkbox = new JCheckBox();
|
---|
132 | same_host_checkbox.setSelected(true);
|
---|
133 | Dictionary.registerText(same_host_checkbox, "Mirroring.Same_Host");
|
---|
134 |
|
---|
135 | JPanel button_pane = new JPanel();
|
---|
136 |
|
---|
137 | JButton preferences_button = new GLIButton();
|
---|
138 | preferences_button.setEnabled(true);
|
---|
139 | preferences_button.setMnemonic(KeyEvent.VK_P);
|
---|
140 | Dictionary.registerBoth(preferences_button, "Mirroring.Preferences", "Mirroring.Preferences_Tooltip");
|
---|
141 |
|
---|
142 | clear_cache_button = new GLIButton();
|
---|
143 | clear_cache_button.setEnabled(true);
|
---|
144 | clear_cache_button.setMnemonic(KeyEvent.VK_C);
|
---|
145 | Dictionary.registerBoth(clear_cache_button, "Mirroring.ClearCache", "Mirroring.ClearCache_Tooltip");
|
---|
146 |
|
---|
147 | download_button = new GLIButton();
|
---|
148 | download_button.setEnabled(true);
|
---|
149 | download_button.setMnemonic(KeyEvent.VK_D);
|
---|
150 | Dictionary.registerBoth(download_button, "Mirroring.Download", "Mirroring.Download_Tooltip");
|
---|
151 | // Connect
|
---|
152 | clear_cache_button.addActionListener(new ClearCacheListener());
|
---|
153 | download_button.addActionListener(new DownloadButtonListener());
|
---|
154 | preferences_button.addActionListener(new PreferencesButtonActionListener());
|
---|
155 |
|
---|
156 | // Layout
|
---|
157 | url_pane.setLayout(new BorderLayout(5,0));
|
---|
158 | url_pane.add(url_label, BorderLayout.WEST);
|
---|
159 | url_pane.add(url_field, BorderLayout.CENTER);
|
---|
160 |
|
---|
161 | depth_pane.setLayout(new GridLayout(1,3));
|
---|
162 | depth_pane.add(depth_label);
|
---|
163 | depth_pane.add(new JPanel());
|
---|
164 | depth_pane.add(depth_combobox);
|
---|
165 |
|
---|
166 | details_pane.setLayout(new GridLayout(2,1,0,5));
|
---|
167 | details_pane.setBorder(BorderFactory.createEmptyBorder(2,2,5,2));
|
---|
168 | details_pane.add(url_pane);
|
---|
169 | details_pane.add(depth_pane);
|
---|
170 |
|
---|
171 | options_pane.setLayout(new GridLayout(3,1,0,5));
|
---|
172 |
|
---|
173 | options_pane.add(higher_checkbox);
|
---|
174 | options_pane.add(same_host_checkbox);
|
---|
175 | if (current_mode >= THRESHOLD) {
|
---|
176 | options_pane.add(requisite_checkbox);
|
---|
177 | }
|
---|
178 |
|
---|
179 | button_pane.setLayout(new GridLayout(3,1));
|
---|
180 | button_pane.add(preferences_button);
|
---|
181 | button_pane.add(clear_cache_button);
|
---|
182 | button_pane.add(download_button);
|
---|
183 |
|
---|
184 | edit_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2,0,0,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("Mirroring.Download_Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
|
---|
185 | edit_pane.setLayout(new BorderLayout());
|
---|
186 | edit_pane.add(details_pane, BorderLayout.NORTH);
|
---|
187 | edit_pane.add(button_pane, BorderLayout.EAST);
|
---|
188 | edit_pane.add(options_pane, BorderLayout.CENTER);
|
---|
189 |
|
---|
190 | setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
---|
191 | setLayout(new BorderLayout());
|
---|
192 | add(edit_pane, BorderLayout.NORTH);
|
---|
193 | add(list_scroll, BorderLayout.CENTER);
|
---|
194 | }
|
---|
195 |
|
---|
196 | public void afterDisplay() {
|
---|
197 | ready = true;
|
---|
198 | }
|
---|
199 |
|
---|
200 |
|
---|
201 | /** This method is called whenever the Mirror pane is brought into focus and is a good time to display a warning message if WGet is not available or of an older, problematic, version.
|
---|
202 | */
|
---|
203 | public void gainFocus() {
|
---|
204 | if(!ready) {
|
---|
205 | return;
|
---|
206 | }
|
---|
207 | // Lets see what warning message we should display, if any.
|
---|
208 | String wget_version_str = Configuration.getWGetVersion();
|
---|
209 | if(wget_version_str.equals(StaticStrings.NO_WGET_STR)) {
|
---|
210 | // If there was no WGet available then downloading is disabled entirely
|
---|
211 | download_button_enabled = false;
|
---|
212 | // And we tell the user why.
|
---|
213 | Gatherer.missingWGET();
|
---|
214 | }
|
---|
215 | else if(wget_version_str.equals(StaticStrings.WGET_OLD_STR)) {
|
---|
216 | // Downloading is enabled
|
---|
217 | download_button_enabled = true;
|
---|
218 | // But we display a preventable warning message about the path problems.
|
---|
219 | Gatherer.oldWGET();
|
---|
220 | }
|
---|
221 | // Otherwise version must be ok
|
---|
222 | else {
|
---|
223 | download_button_enabled = true;
|
---|
224 | }
|
---|
225 | // It is also a good time to determine if the download should be enabled - ie if its allowed to be enabled and a valid URL is present in the field.
|
---|
226 | download_button.setEnabled(download_button_enabled);
|
---|
227 | }
|
---|
228 |
|
---|
229 | public void modeChanged(int mode) {
|
---|
230 | int old_mode = current_mode;
|
---|
231 | current_mode = mode;
|
---|
232 | if (old_mode >= THRESHOLD && current_mode >= THRESHOLD) {
|
---|
233 | return;
|
---|
234 | }
|
---|
235 | if (old_mode < THRESHOLD && current_mode < THRESHOLD) {
|
---|
236 | return;
|
---|
237 | }
|
---|
238 | if (current_mode >= THRESHOLD) {
|
---|
239 | options_pane.add(requisite_checkbox);
|
---|
240 | }
|
---|
241 | else {
|
---|
242 | options_pane.remove(requisite_checkbox);
|
---|
243 | requisite_checkbox.setSelected(false);
|
---|
244 | }
|
---|
245 | }
|
---|
246 |
|
---|
247 |
|
---|
248 | public void refresh(int refresh_reason, boolean ready)
|
---|
249 | {
|
---|
250 | }
|
---|
251 |
|
---|
252 |
|
---|
253 | /** A DepthEntry contains a depth value, as an int, and a representitive text string. This allows for a more meaningful appearance than '0' for instance. */
|
---|
254 | private class DepthEntry
|
---|
255 | implements Comparable {
|
---|
256 | private int value;
|
---|
257 | private String text;
|
---|
258 | /** Default constructor.
|
---|
259 | * @param value the depth value as an int
|
---|
260 | * @param text how this entry show represent itself as a String
|
---|
261 | */
|
---|
262 | public DepthEntry(int value, String text) {
|
---|
263 | this.text = text;
|
---|
264 | this.value = value;
|
---|
265 | }
|
---|
266 | /** Determines the natural ordering of this DepthEntry and some other object
|
---|
267 | * @param object the Object to test for ordering
|
---|
268 | * @return >0 if the object is before this one, 0 if they are equal, or <0 if the object is after this one
|
---|
269 | */
|
---|
270 | public int compareTo(Object object) {
|
---|
271 | // If the object is a DepthEntry then this is easy pesy.
|
---|
272 | if(object instanceof DepthEntry) {
|
---|
273 | int target_value = ((DepthEntry) object).getValue();
|
---|
274 | return value - target_value;
|
---|
275 | }
|
---|
276 | // If the object is a String, then we should try parsing an int from it
|
---|
277 | if(object instanceof String) {
|
---|
278 | try {
|
---|
279 | int target_value = Integer.parseInt((String)object);
|
---|
280 | return value - target_value;
|
---|
281 | }
|
---|
282 | catch(Exception exception) {
|
---|
283 | }
|
---|
284 | }
|
---|
285 | // Otherwise we'll try a string comparison between our text and the toString of the object
|
---|
286 | return text.compareTo(object.toString());
|
---|
287 | }
|
---|
288 |
|
---|
289 | /** Determine if this DepthEntry is equal to some other object. Given that there is significant processing involved we push the resposiblility for this onto compareTo, so we only have the complex code once.
|
---|
290 | * @param object the Object to test for equality
|
---|
291 | * @return true if the object is equal to this depth entry, false otherwise
|
---|
292 | */
|
---|
293 | public boolean equals(Object object) {
|
---|
294 | return (compareTo(object) == 0);
|
---|
295 | }
|
---|
296 |
|
---|
297 | public int getValue() {
|
---|
298 | return value;
|
---|
299 | }
|
---|
300 |
|
---|
301 | public String toString() {
|
---|
302 | return text;
|
---|
303 | }
|
---|
304 | }
|
---|
305 |
|
---|
306 | private class ClearCacheListener
|
---|
307 | implements ActionListener {
|
---|
308 | public void actionPerformed(ActionEvent event) {
|
---|
309 | // Retrieve the cache folder and delete it.
|
---|
310 | Utility.delete(Utility.getCacheDir());
|
---|
311 | // ...and refresh the node in the workspace tree to show it's all gone
|
---|
312 | Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.DOWNLOADED_FILES_CHANGED);
|
---|
313 | }
|
---|
314 | }
|
---|
315 |
|
---|
316 | private class CheckboxClickListener
|
---|
317 | implements ActionListener {
|
---|
318 | public void actionPerformed(ActionEvent event) {
|
---|
319 | if (higher_checkbox.isSelected()) {
|
---|
320 | same_host_checkbox.setEnabled(false);
|
---|
321 | } else {
|
---|
322 | same_host_checkbox.setEnabled(true);
|
---|
323 | }
|
---|
324 | }
|
---|
325 | }
|
---|
326 |
|
---|
327 | private class DownloadButtonListener
|
---|
328 | implements ActionListener {
|
---|
329 |
|
---|
330 | public void actionPerformed(ActionEvent event) {
|
---|
331 | // Retrieve the current url and confirm it is valid
|
---|
332 | String url_str = url_field.getText();
|
---|
333 | URL url = null;
|
---|
334 | try {
|
---|
335 | url = new URL(url_str);
|
---|
336 | }
|
---|
337 | catch(MalformedURLException error) {
|
---|
338 | JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Mirroring.Invalid_URL"), Dictionary.get("Mirroring.Invalid_URL_Title"), JOptionPane.ERROR_MESSAGE);
|
---|
339 | }
|
---|
340 |
|
---|
341 | // Otherwise construct a new download job
|
---|
342 | Object depth_object = depth_combobox.getSelectedItem();
|
---|
343 | int depth_value = 0;
|
---|
344 | if(depth_object instanceof DepthEntry) {
|
---|
345 | depth_value = ((DepthEntry)depth_object).getValue();
|
---|
346 | }
|
---|
347 | else if(depth_object instanceof String) {
|
---|
348 | String depth_string = (String) depth_object;
|
---|
349 | try {
|
---|
350 | depth_value = Integer.parseInt(depth_string);
|
---|
351 | // Create a new entry for the purposes of comparison, and if needs be, addition
|
---|
352 | DepthEntry new_entry = new DepthEntry(depth_value, depth_string);
|
---|
353 | // Try to select the correct item from the combobox
|
---|
354 | depth_combobox.setSelectedItem(null);
|
---|
355 | depth_combobox.setSelectedItem(new_entry);
|
---|
356 | // We can see if that worked, and if it didn't add the entry
|
---|
357 | if(depth_combobox.getSelectedItem() == null) {
|
---|
358 | depth_combobox.addItem(new_entry);
|
---|
359 | depth_combobox.setSelectedItem(new_entry);
|
---|
360 | }
|
---|
361 | new_entry = null;
|
---|
362 | }
|
---|
363 | catch(Exception exception) {
|
---|
364 | /* @todo - add to dictionary */
|
---|
365 | JOptionPane.showMessageDialog(Gatherer.g_man, "Mirroring.Mirror_Depth.Invalid_Depth", "Mirroring.Mirror_Depth.Invalid_Depth_Title", JOptionPane.ERROR_MESSAGE);
|
---|
366 | return;
|
---|
367 | }
|
---|
368 | depth_string = null;
|
---|
369 | }
|
---|
370 | depth_object = null;
|
---|
371 |
|
---|
372 | File destination_file = Utility.getCacheDir();
|
---|
373 | destination_file.mkdirs(); // If they aren't already
|
---|
374 | String destination_filename = destination_file.getAbsolutePath();
|
---|
375 | if(!destination_filename.endsWith(File.separator)) {
|
---|
376 | destination_filename = destination_filename + File.separator;
|
---|
377 | }
|
---|
378 |
|
---|
379 | if(url != null) {
|
---|
380 | getter.newDownloadJob(higher_checkbox.isSelected(), (higher_checkbox.isSelected()? false : !same_host_checkbox.isSelected()), !requisite_checkbox.isSelected(), url, depth_value, destination_filename);
|
---|
381 | }
|
---|
382 | }
|
---|
383 | }
|
---|
384 |
|
---|
385 | private class PreferencesButtonActionListener
|
---|
386 | implements ActionListener {
|
---|
387 | public void actionPerformed(ActionEvent event) {
|
---|
388 | new Preferences(Preferences.CONNECTION_PREFS);
|
---|
389 | }
|
---|
390 | }
|
---|
391 | }
|
---|