1
24 package org.crosswire.bibledesktop.book;
25
26 import java.awt.BorderLayout;
27 import java.awt.Component;
28 import java.awt.Frame;
29 import java.awt.GridBagConstraints;
30 import java.awt.GridBagLayout;
31 import java.awt.Insets;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.awt.event.KeyEvent;
35 import java.io.IOException;
36 import java.io.ObjectInputStream;
37
38 import javax.swing.BorderFactory;
39 import javax.swing.Icon;
40 import javax.swing.JButton;
41 import javax.swing.JComponent;
42 import javax.swing.JDialog;
43 import javax.swing.JLabel;
44 import javax.swing.JList;
45 import javax.swing.JOptionPane;
46 import javax.swing.JPanel;
47 import javax.swing.JTextField;
48 import javax.swing.JTree;
49 import javax.swing.KeyStroke;
50 import javax.swing.WindowConstants;
51 import javax.swing.event.DocumentEvent;
52 import javax.swing.event.DocumentListener;
53 import javax.swing.event.ListSelectionEvent;
54 import javax.swing.event.ListSelectionListener;
55 import javax.swing.event.TreeSelectionEvent;
56 import javax.swing.event.TreeSelectionListener;
57 import javax.swing.tree.TreePath;
58
59 import org.crosswire.bibledesktop.BDMsg;
60 import org.crosswire.bibledesktop.passage.RangeListModel;
61 import org.crosswire.bibledesktop.passage.WholeBibleTreeModel;
62 import org.crosswire.bibledesktop.passage.WholeBibleTreeNode;
63 import org.crosswire.common.swing.ActionFactory;
64 import org.crosswire.common.swing.CWAction;
65 import org.crosswire.common.swing.CWLabel;
66 import org.crosswire.common.swing.CWScrollPane;
67 import org.crosswire.common.swing.GuiUtil;
68 import org.crosswire.jsword.passage.NoSuchKeyException;
69 import org.crosswire.jsword.passage.Passage;
70 import org.crosswire.jsword.passage.PassageEvent;
71 import org.crosswire.jsword.passage.PassageKeyFactory;
72 import org.crosswire.jsword.passage.PassageListener;
73 import org.crosswire.jsword.passage.RestrictionType;
74 import org.crosswire.jsword.passage.VerseRange;
75 import org.crosswire.jsword.versification.Versification;
76 import org.crosswire.jsword.versification.system.Versifications;
77
78
85 public class PassageSelectionPane extends JPanel {
86
89 public PassageSelectionPane() {
90 icoGood = GuiUtil.getIcon(GOOD_ICON);
91 icoBad = GuiUtil.getIcon(BAD_ICON);
92
93 init();
94 }
95
96
99 private void init() {
100 actions = new ActionFactory(this);
101 CWAction action;
102
103 JLabel lblAll = CWLabel.createJLabel(BDMsg.gettext("All Verses"));
105 JLabel lblSel = CWLabel.createJLabel(BDMsg.gettext("Selected Verses"));
107 action = actions.addAction("DeleteVerse", BDMsg.gettext("Remove <"));
109 action.setTooltip(BDMsg.gettext("Delete verses from the list selected."));
111 JButton deleteButton = new JButton(action);
112 action = actions.addAction("AddVerse", BDMsg.gettext("Add >"));
114 action.setTooltip(BDMsg.gettext("Add verses to list selected."));
116 JButton addButton = new JButton(action);
117
118 this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
119 this.setLayout(new GridBagLayout());
120 this.add(lblAll, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(5, 10, 5, 5), 0, 0));
121 this.add(createScrolledTree(lblAll), new GridBagConstraints(0, 1, 1, 4, 0.5, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 10, 10, 2), 0, 0));
122 this.add(new JPanel(), new GridBagConstraints(1, 1, 1, 1, 0.0, 0.5, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
123 this.add(deleteButton, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
124 this.add(addButton, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
125 this.add(new JPanel(), new GridBagConstraints(1, 4, 1, 1, 0.0, 0.5, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
126 this.add(lblSel, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(5, 5, 5, 10), 0, 0));
127 this.add(createScrolledList(lblSel), new GridBagConstraints(2, 1, 1, 4, 0.5, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 2, 10, 10), 0, 0));
128 this.add(createMessageLabel(), new GridBagConstraints(0, 5, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 5, 10), 0, 0));
129 this.add(createDisplayPanel(), new GridBagConstraints(0, 6, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 10), 0, 0));
130 GuiUtil.applyDefaultOrientation(this);
131 }
132
133
136 private Component createScrolledTree(JLabel label) {
137 treAll = new JTree();
138 treAll.setModel(new WholeBibleTreeModel());
139 treAll.setShowsRootHandles(true);
140 treAll.setRootVisible(false);
141 treAll.putClientProperty("JTree.lineStyle", "Angled");
142 treAll.addTreeSelectionListener(new TreeSelectionListener() {
143 public void valueChanged(TreeSelectionEvent ev) {
144 treeSelected();
145 }
146 });
147
148 label.setLabelFor(treAll);
149
150 return new CWScrollPane(treAll);
151 }
152
153
156 private Component createScrolledList(JLabel label) {
157 model = new RangeListModel(RestrictionType.CHAPTER);
158 lstSel = new JList(model);
159 lstSel.addListSelectionListener(new ListSelectionListener() {
160 public void valueChanged(ListSelectionEvent ev) {
161 listSelected();
162 }
163 });
164
165 label.setLabelFor(lstSel);
166
167 return new CWScrollPane(lstSel);
168 }
169
170
173 private Component createDisplayPanel() {
174 txtDisplay = new JTextField();
175 txtDisplay.getDocument().addDocumentListener(new CustomDocumentEvent());
176
177 JLabel lblDisplay = CWLabel.createJLabel(BDMsg.gettext("Verses"));
180 lblDisplay.setLabelFor(txtDisplay);
181
182 JPanel panel = new JPanel();
183 panel.setLayout(new BorderLayout());
184 panel.add(txtDisplay, BorderLayout.CENTER);
185 panel.add(lblDisplay, BorderLayout.LINE_START);
186 return panel;
187 }
188
189
192 private Component createMessageLabel() {
193 lblMessage = new JLabel();
194
195 return lblMessage;
196 }
197
198
201 protected void copyListToText() {
202 if (changing) {
203 return;
204 }
205
206 changing = true;
207 txtDisplay.setText(ref.getName());
208 updateMessageSummary();
209 changing = false;
210 }
211
212
215 protected void copyTextToList() {
216 if (changing) {
217 return;
218 }
219
220 changing = true;
221 String refstr = txtDisplay.getText();
222
223 try {
224 Versification v11n = Versifications.instance().getDefaultVersification();
226 Passage temp = (Passage) keyf.getKey(v11n, refstr);
227 ref.clear();
228 ref.addAll(temp);
229 model.setPassage(ref);
230
231 setValidPassage(true);
232 updateMessageSummary();
233 } catch (NoSuchKeyException ex) {
234 setValidPassage(false);
235 updateMessage(ex);
236 }
237 changing = false;
238 }
239
240
245 private void setValidPassage(boolean valid) {
246 lstSel.setEnabled(valid);
247 treAll.setEnabled(valid);
248 actions.findAction("AddVerse").setEnabled(valid);
249 actions.findAction("DeleteVerse").setEnabled(valid);
250 }
251
252
257 private void updateMessage(NoSuchKeyException ex) {
258 lblMessage.setText(BDMsg.gettext("Error: {0}", ex.getMessage()));
261 lblMessage.setIcon(icoBad);
262 }
263
264
267 private void updateMessageSummary() {
268 lblMessage.setText(BDMsg.gettext("Summary: {0}", ref.getOverview()));
272 lblMessage.setIcon(icoGood);
273 }
274
275
284 public String showInDialog(Component parent, String title, boolean modal, String refstr) {
285 try {
286 Versification v11n = Versifications.instance().getDefaultVersification();
288 ref = (Passage) keyf.getKey(v11n, refstr);
289
290 txtDisplay.setText(refstr);
291
292 ref.addPassageListener(new CustomPassageListener());
293 updateMessageSummary();
294 } catch (NoSuchKeyException ex) {
295 setValidPassage(false);
296 updateMessage(ex);
297 }
298
299 treeSelected();
301 listSelected();
302
303 Frame root = JOptionPane.getFrameForComponent(parent);
304 dlgMain = new JDialog(root);
305
306 JPanel pnlAction = new JPanel();
307 KeyStroke esc = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
308 bailout = true;
309
310 CWAction action = actions.addAction("Done", BDMsg.gettext("OK"));
312 action.setTooltip(BDMsg.gettext("Close this window."));
314 JButton btnGo = new JButton(action);
315
316 pnlAction.setLayout(new BorderLayout());
317 pnlAction.setBorder(BorderFactory.createEmptyBorder(5, 5, 15, 20));
318 pnlAction.add(btnGo, BorderLayout.LINE_END);
319
320 ActionListener closer = new ActionListener() {
321 public void actionPerformed(ActionEvent ev) {
322 dlgMain.dispose();
323 }
324 };
325
326 dlgMain.getContentPane().setLayout(new BorderLayout());
327 dlgMain.getContentPane().add(this, BorderLayout.CENTER);
328 dlgMain.getContentPane().add(pnlAction, BorderLayout.SOUTH);
329 dlgMain.getRootPane().setDefaultButton(btnGo);
330 dlgMain.getRootPane().registerKeyboardAction(closer, esc, JComponent.WHEN_IN_FOCUSED_WINDOW);
331 dlgMain.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
332 dlgMain.setTitle(title);
333 dlgMain.setModal(modal);
334
335 GuiUtil.applyDefaultOrientation(dlgMain);
336 GuiUtil.restrainedPack(dlgMain, 0.5f, 0.75f);
337 GuiUtil.centerOnScreen(dlgMain);
338 dlgMain.setVisible(true);
339
340 if (bailout) {
341 return null;
342 }
343 return txtDisplay.getText();
344 }
345
346
349 public void doAddVerse() {
350 TreePath[] selected = treAll.getSelectionPaths();
351 if (selected != null) {
352 for (int i = 0; i < selected.length; i++) {
353 WholeBibleTreeNode node = (WholeBibleTreeNode) selected[i].getLastPathComponent();
354 VerseRange range = node.getVerseRange();
355 ref.add(range);
356 }
357 model.setPassage(ref);
358 }
359 }
360
361
364 public void doDeleteVerse() {
365 Object[] selected = lstSel.getSelectedValues();
366 if (selected != null) {
367 for (int i = 0; i < selected.length; i++) {
368 VerseRange range = (VerseRange) selected[i];
369 ref.remove(range);
370 }
371 model.setPassage(ref);
372 }
373 }
374
375
378 public void doDone() {
379 bailout = false;
380 dlgMain.dispose();
381 }
382
383
386 final void treeSelected() {
387 TreePath[] selected = treAll.getSelectionPaths();
388 actions.findAction("AddVerse").setEnabled(selected != null && selected.length > 0);
389 }
390
391
394 final void listSelected() {
395 Object[] selected = lstSel.getSelectedValues();
396 actions.findAction("DeleteVerse").setEnabled(selected != null && selected.length > 0);
397 }
398
399
406 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
407 icoGood = GuiUtil.getIcon(GOOD_ICON);
409 icoBad = GuiUtil.getIcon(BAD_ICON);
410 keyf = PassageKeyFactory.instance();
411 actions = new ActionFactory(this);
412 is.defaultReadObject();
413 }
414
415 private static final String GOOD_ICON = "toolbarButtonGraphics/general/About24.gif";
416 private static final String BAD_ICON = "toolbarButtonGraphics/general/Stop24.gif";
417
418
421 protected transient PassageKeyFactory keyf = PassageKeyFactory.instance();
422
423
426 protected boolean bailout;
427
428
431 private boolean changing;
432
433
436 private Passage ref;
437
438
441 private transient ActionFactory actions;
442
443
446 private transient Icon icoGood;
447 private transient Icon icoBad;
448 private JTree treAll;
449 private JList lstSel;
450 private RangeListModel model;
451 private JTextField txtDisplay;
452 private JLabel lblMessage;
453 protected JDialog dlgMain;
454
455
458 private static final long serialVersionUID = 3546920298944673072L;
459
460
463 class CustomDocumentEvent implements DocumentListener {
464
467 public void insertUpdate(DocumentEvent ev) {
468 copyTextToList();
469 }
470
471
474 public void removeUpdate(DocumentEvent ev) {
475 copyTextToList();
476 }
477
478
481 public void changedUpdate(DocumentEvent ev) {
482 copyTextToList();
483 }
484 }
485
486
489 class CustomPassageListener implements PassageListener {
490
493 public void versesAdded(PassageEvent ev) {
494 copyListToText();
495 }
496
497
500 public void versesRemoved(PassageEvent ev) {
501 copyListToText();
502 }
503
504
507 public void versesChanged(PassageEvent ev) {
508 copyListToText();
509 }
510 }
511 }
512