1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.ui;
39
40 import ffx.utilities.Keyword;
41
42 import java.awt.Color;
43 import java.awt.Component;
44 import java.awt.Dimension;
45 import java.awt.FlowLayout;
46 import java.awt.GridBagConstraints;
47 import java.awt.GridBagLayout;
48 import java.awt.Point;
49 import java.awt.event.ActionEvent;
50 import java.awt.event.ActionListener;
51 import java.awt.event.MouseEvent;
52 import java.awt.event.MouseListener;
53 import java.util.ArrayList;
54 import java.util.Objects;
55 import java.util.logging.Level;
56 import java.util.logging.Logger;
57 import javax.swing.JButton;
58 import javax.swing.JCheckBox;
59 import javax.swing.JComboBox;
60 import javax.swing.JLabel;
61 import javax.swing.JPanel;
62 import javax.swing.JTextArea;
63 import javax.swing.JTextField;
64 import javax.swing.JViewport;
65 import javax.swing.border.EmptyBorder;
66 import javax.swing.event.ChangeEvent;
67 import javax.swing.event.ChangeListener;
68 import javax.swing.event.DocumentEvent;
69 import javax.swing.event.DocumentListener;
70
71
72
73
74
75
76 @SuppressWarnings("unchecked")
77 public final class KeywordComponent
78 implements MouseListener, ActionListener, ChangeListener, DocumentListener {
79
80 private static final Logger logger = Logger.getLogger(KeywordComponent.class.getName());
81
82
83
84
85 private static boolean isModified = false;
86
87 private static final Dimension labelDimension;
88 private static final Dimension entryDimension;
89
90 static {
91 JTextField textField = new JTextField(20);
92 labelDimension = textField.getPreferredSize();
93 textField = new JTextField(25);
94 entryDimension = textField.getPreferredSize();
95 }
96
97 private final FlowLayout flowLayout;
98
99
100
101 private final String keyword;
102
103
104
105 private final String keywordGroup;
106
107
108
109 private final ArrayList<Component> keywordValues;
110
111 private JPanel keywordGUI = null;
112
113
114
115 private final SwingRepresentation swingRepresentation;
116
117 private String[] options;
118 private final String keywordDescription;
119 private final JTextArea output;
120 private boolean active;
121 private boolean init = false;
122
123
124
125
126
127
128
129
130
131
132
133 KeywordComponent(
134 String keyword,
135 String keywordGroup,
136 SwingRepresentation swingRepresentation,
137 String keywordDescription,
138 JTextArea jTextArea) {
139 flowLayout = new FlowLayout(FlowLayout.LEFT, 5, 5);
140 this.keyword = keyword;
141 this.keywordGroup = keywordGroup;
142 keywordValues = new ArrayList<>();
143 this.swingRepresentation = swingRepresentation;
144 this.keywordDescription = keywordDescription;
145 output = jTextArea;
146 active = false;
147 flowLayout.setHgap(2);
148 flowLayout.setVgap(1);
149 }
150
151
152
153
154
155
156
157
158
159
160
161 KeywordComponent(
162 String keyword,
163 String keywordGroup,
164 SwingRepresentation swingRepresentation,
165 String keywordDescription,
166 JTextArea jTextArea,
167 String[] options) {
168 this(keyword, keywordGroup, swingRepresentation, keywordDescription, jTextArea);
169 this.options = options;
170 }
171
172
173
174
175
176
177
178
179 static void fillPanel(
180 JPanel jPanel, GridBagLayout gridBagLayout, GridBagConstraints gridBagConstraints) {
181 JLabel jfill = new JLabel(" ");
182 gridBagConstraints.weightx = 1;
183 gridBagConstraints.weighty = 1;
184 gridBagConstraints.fill = GridBagConstraints.BOTH;
185 gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
186 gridBagConstraints.gridheight = GridBagConstraints.REMAINDER;
187 gridBagLayout.setConstraints(jfill, gridBagConstraints);
188 jPanel.add(jfill);
189 }
190
191
192
193
194
195
196 static boolean isKeywordModified() {
197 return isModified;
198 }
199
200
201
202
203
204
205 static void setKeywordModified(boolean b) {
206 isModified = b;
207 }
208
209
210
211
212 @Override
213 @SuppressWarnings("unchecked")
214 public void actionPerformed(ActionEvent evt) {
215 synchronized (this) {
216 isModified = true;
217 if (evt.getSource() instanceof JButton) {
218 JButton button = (JButton) evt.getSource();
219 if (button.getText().equalsIgnoreCase("Add")) {
220 JTextField text = (JTextField) keywordValues.get(3);
221 String s = text.getText();
222 if (s != null && !s.trim().isEmpty()) {
223 JComboBox<String> jcb = (JComboBox<String>) keywordValues.get(1);
224 jcb.addItem(s);
225 text.setText("");
226 active = true;
227 }
228 } else if (button.getText().equalsIgnoreCase("Remove")) {
229 JComboBox<String> jcb = (JComboBox<String>) keywordValues.get(1);
230 if (jcb.getItemCount() > 0) {
231 jcb.removeItemAt(jcb.getSelectedIndex());
232 }
233 if (jcb.getItemCount() == 0) {
234 active = false;
235 }
236 }
237 } else if (evt.getSource() instanceof JComboBox) {
238 JComboBox<String> jcb = (JComboBox<String>) evt.getSource();
239 String selected = (String) jcb.getSelectedItem();
240 if (selected == null) {
241 active = false;
242 } else {
243 active = !selected.equalsIgnoreCase("DEFAULT");
244 }
245 }
246 }
247 }
248
249
250
251
252 @Override
253 public void changedUpdate(DocumentEvent evt) {
254 isModified = true;
255 }
256
257
258
259
260
261
262
263 @Override
264 public boolean equals(Object object) {
265 if (this == object) {
266 return true;
267 } else if (object == null || getClass() != object.getClass()) {
268 return false;
269 }
270 KeywordComponent other = (KeywordComponent) object;
271 return keyword.equalsIgnoreCase(other.keyword);
272 }
273
274
275
276
277
278
279 public String getKeyword() {
280 return keyword;
281 }
282
283
284
285
286 @Override
287 public int hashCode() {
288 return Objects.hash(keyword.hashCode());
289 }
290
291
292
293
294 @Override
295 public void insertUpdate(DocumentEvent evt) {
296 isModified = true;
297 }
298
299
300
301
302
303
304 public boolean isActive() {
305 return active;
306 }
307
308
309
310
311 @Override
312 public void mouseClicked(MouseEvent evt) {
313 synchronized (this) {
314 active = toString() != null;
315 output.setText(keyword + ": " + keywordDescription);
316 JViewport jsp = (JViewport) output.getParent();
317 jsp.setViewPosition(new Point(20, 20));
318 }
319 }
320
321
322
323
324 @Override
325 public void mouseEntered(MouseEvent evt) {
326 mouseClicked(evt);
327 }
328
329
330
331
332 @Override
333 public void mouseExited(MouseEvent evt) {
334 mouseClicked(evt);
335 }
336
337
338
339
340 @Override
341 public void mousePressed(MouseEvent evt) {
342 }
343
344
345
346
347 @Override
348 public void mouseReleased(MouseEvent evt) {
349 }
350
351
352
353
354 @Override
355 public void removeUpdate(DocumentEvent evt) {
356 isModified = true;
357 }
358
359
360
361
362 @Override
363 public void stateChanged(ChangeEvent evt) {
364 isModified = true;
365 }
366
367
368
369
370
371
372 @Override
373 public String toString() {
374 synchronized (this) {
375 if (!active || !init) {
376 return null;
377 }
378 StringBuilder s;
379
380
381 String spaces = " ";
382 if (!keyword.equalsIgnoreCase("TORSION")) {
383 s = new StringBuilder(keyword + spaces.substring(0, 18 - keyword.length()));
384 } else {
385 s = new StringBuilder(keyword);
386 }
387 for (Component c : keywordValues) {
388 if (c instanceof JCheckBox) {
389 JCheckBox cb = (JCheckBox) c;
390 if (keywordValues.size() == 1) {
391 if (!cb.isSelected()) {
392 return null;
393 }
394 } else if (cb.getText().equalsIgnoreCase(keyword)) {
395 if (!cb.isSelected()) {
396 s = new StringBuilder();
397 }
398 } else {
399 if (cb.isSelected()) {
400 if (!s.isEmpty()) {
401 s.append("\n").append(keyword).append(" ").append(cb.getText());
402 } else {
403 s.append(keyword).append(" ").append(cb.getText());
404 }
405 }
406 }
407 } else if (c instanceof JTextField) {
408 JTextField tf = (JTextField) c;
409 if (tf.getText().isEmpty()) {
410 return null;
411 }
412 String v = tf.getText();
413 if (v.length() < 8) {
414 s.append(v).append(spaces, 0, 8 - v.length());
415 } else {
416 s.append(v);
417 }
418 break;
419 } else if (c instanceof JComboBox) {
420 JComboBox<String> cb = (JComboBox<String>) c;
421 if (swingRepresentation == SwingRepresentation.EDITCOMBOBOX) {
422 int count = cb.getItemCount();
423 if (count == 0) {
424 return null;
425 }
426 String[] entries = new String[count];
427 for (int i = 0; i < count; i++) {
428 entries[i] = cb.getItemAt(i);
429 }
430 java.util.Arrays.sort(entries);
431 StringBuilder sb = new StringBuilder();
432 for (int i = 0; i < count; i++) {
433 sb.append(keyword).append(spaces.substring(0, 18 - keyword.length()));
434 sb.append(entries[i].toUpperCase());
435 if (i < count - 1) {
436 sb.append("\n");
437 }
438 }
439 s = sb;
440 } else {
441 String selection = (String) cb.getSelectedItem();
442 if (selection.startsWith("DEFAULT")) {
443 return null;
444 } else if (!selection.equalsIgnoreCase("PRESENT")) {
445 s.append(" ").append(selection);
446 }
447 }
448 break;
449 }
450 }
451 if (s.isEmpty()) {
452 return null;
453 }
454 return s.toString();
455 }
456 }
457
458 private void checkBoxesInit() {
459 checkBoxInit();
460 for (String s : options) {
461 checkBoxInit(s);
462 }
463 }
464
465 private void checkBoxInit() {
466 JCheckBox cb = new JCheckBox(keyword, false);
467 cb.setPreferredSize(labelDimension);
468 cb.setMaximumSize(labelDimension);
469 cb.addMouseListener(this);
470 cb.addChangeListener(this);
471 keywordValues.add(cb);
472 }
473
474 private void checkBoxInit(String label) {
475 JCheckBox cb = new JCheckBox(label, false);
476 cb.addMouseListener(this);
477 cb.addChangeListener(this);
478 keywordValues.add(cb);
479 }
480
481
482
483
484 void clearKeywordComponent() {
485 synchronized (this) {
486 active = false;
487 if (!init) {
488 return;
489 }
490 if (swingRepresentation == SwingRepresentation.CHECKBOX) {
491 ((JCheckBox) keywordValues.get(0)).setSelected(false);
492 } else if (swingRepresentation == SwingRepresentation.CHECKBOXES) {
493 for (Component keywordValue : keywordValues) {
494 ((JCheckBox) keywordValue).setSelected(false);
495 }
496 } else if (swingRepresentation == SwingRepresentation.COMBOBOX) {
497 JComboBox<String> jcb = (JComboBox<String>) keywordValues.get(1);
498 jcb.setSelectedItem("DEFAULT");
499 } else if (swingRepresentation == SwingRepresentation.EDITCOMBOBOX) {
500 ((JComboBox) keywordValues.get(1)).removeAllItems();
501 } else if (swingRepresentation == SwingRepresentation.TEXTFIELD) {
502 ((JTextField) keywordValues.get(1)).setText("");
503 } else {
504 logger.severe("Keyword Component: Unknown Keyword Type");
505 logger.severe("Force Field X can not continue...");
506 System.exit(-1);
507 }
508 }
509 }
510
511 private void comboBoxInit() {
512 JLabel jl = new JLabel(keyword);
513 jl.addMouseListener(this);
514 jl.setPreferredSize(labelDimension);
515 jl.setMaximumSize(labelDimension);
516 keywordValues.add(jl);
517 JComboBox<String> cb = new JComboBox<>();
518 cb.setEditable(false);
519 cb.addMouseListener(this);
520 cb.addActionListener(this);
521 cb.setPreferredSize(entryDimension);
522 cb.setMaximumSize(entryDimension);
523 for (String s : options) {
524 cb.addItem(s);
525 }
526 cb.setSelectedItem("DEFAULT");
527 keywordValues.add(cb);
528 }
529
530 private void editComboBoxInit() {
531 JLabel jl = new JLabel(keyword);
532 keywordValues.add(jl);
533 jl.addMouseListener(this);
534 jl.setPreferredSize(labelDimension);
535 jl.setMaximumSize(labelDimension);
536 JComboBox<String> cb = new JComboBox<>();
537 cb.setEditable(false);
538 cb.addActionListener(this);
539 cb.setPreferredSize(entryDimension);
540 cb.setMaximumSize(entryDimension);
541 keywordValues.add(cb);
542 JButton remove = new JButton("Remove");
543 remove.addActionListener(this);
544 keywordValues.add(remove);
545 JTextField textField = new JTextField();
546 textField.setPreferredSize(entryDimension);
547 textField.setMaximumSize(entryDimension);
548 keywordValues.add(textField);
549 JButton add = new JButton("Add");
550 add.addActionListener(this);
551 keywordValues.add(add);
552 }
553
554
555
556
557
558
559 void getKeywordData(Keyword keywordData) {
560 synchronized (this) {
561 if (keywordData == null || !active) {
562 return;
563 }
564 for (Component c : keywordValues) {
565 if (c instanceof JTextField) {
566 JTextField tf = (JTextField) c;
567 if (!tf.getText().isEmpty()) {
568 keywordData.append(tf.getText());
569 }
570 break;
571 } else if (c instanceof JComboBox) {
572 JComboBox<String> cb = (JComboBox<String>) c;
573 if (swingRepresentation == SwingRepresentation.COMBOBOX) {
574 String s = (String) cb.getSelectedItem();
575 if ("DEFAULT".equals(s)) {
576 logger.log(Level.WARNING, "Keyword should not be active: {0}", toString());
577 return;
578 }
579 keywordData.append(s);
580 } else {
581 int num = cb.getItemCount();
582 for (int i = 0; i < num; i++) {
583 String s = cb.getItemAt(i);
584 keywordData.append(s);
585 }
586 }
587 break;
588 } else if (c instanceof JCheckBox) {
589 JCheckBox cb = (JCheckBox) c;
590 String text = cb.getText();
591 if (cb.isSelected()) {
592 keywordData.append(text);
593 }
594 }
595 }
596 }
597 }
598
599
600
601
602
603
604 String getKeywordDescription() {
605 return keywordDescription;
606 }
607
608
609
610
611
612
613 String getKeywordGroup() {
614 return keywordGroup;
615 }
616
617
618
619
620
621
622
623 JPanel getKeywordGUI() {
624 synchronized (this) {
625 if (keywordGUI == null) {
626 if (!init) {
627 initSwingComponents();
628 }
629 if (swingRepresentation == SwingRepresentation.MULTIPOLE) {
630 keywordGUI.add(keywordValues.get(0));
631 } else {
632 keywordGUI = new JPanel(flowLayout);
633 for (Component c : keywordValues) {
634 keywordGUI.add(c);
635 }
636 }
637 }
638 return keywordGUI;
639 }
640 }
641
642 private void initSwingComponents() {
643 if (swingRepresentation == SwingRepresentation.CHECKBOX) {
644 checkBoxInit();
645 } else if (swingRepresentation == SwingRepresentation.CHECKBOXES) {
646 checkBoxesInit();
647 } else if (swingRepresentation == SwingRepresentation.COMBOBOX) {
648 comboBoxInit();
649 } else if (swingRepresentation == SwingRepresentation.EDITCOMBOBOX) {
650 editComboBoxInit();
651 } else if (swingRepresentation == SwingRepresentation.TEXTFIELD) {
652 textFieldInit();
653 } else {
654 return;
655 }
656 init = true;
657 }
658
659
660
661
662
663
664
665 @SuppressWarnings("unchecked")
666 void loadKeywordEntry(String s) {
667 synchronized (this) {
668 if (!init) {
669 initSwingComponents();
670 }
671 for (Component c : keywordValues) {
672 if (c instanceof JCheckBox) {
673 JCheckBox cb = (JCheckBox) c;
674 if (s != null && s.equalsIgnoreCase(cb.getText())) {
675 cb.setSelected(true);
676 } else if (s == null) {
677 cb.setSelected(false);
678 }
679 } else if (c instanceof JTextField) {
680 JTextField tf = (JTextField) c;
681 tf.setText(s);
682 break;
683 } else if (c instanceof JComboBox && s != null) {
684 JComboBox<String> cb = (JComboBox<String>) c;
685 if (swingRepresentation == SwingRepresentation.EDITCOMBOBOX) {
686 cb.addItem(s);
687 } else {
688 cb.setSelectedItem(s);
689 }
690 break;
691 }
692 }
693 active = toString() != null;
694 }
695 }
696
697 private void textFieldInit() {
698 JLabel jl = new JLabel(keyword);
699 jl.addMouseListener(this);
700 jl.setPreferredSize(labelDimension);
701 jl.setMaximumSize(labelDimension);
702 keywordValues.add(jl);
703 JTextField tf;
704 tf = new JTextField("");
705 tf.setColumns(25);
706 tf.setActionCommand(keyword);
707 tf.addMouseListener(this);
708 tf.getDocument().addDocumentListener(this);
709 if (keyword.equalsIgnoreCase("PARAMETERS") || keyword.equalsIgnoreCase("FORCEFIELD")) {
710 tf.setEditable(false);
711 EmptyBorder b = new EmptyBorder(1, 1, 1, 1);
712 tf.setBorder(b);
713 tf.setForeground(Color.BLUE);
714 }
715 tf.setPreferredSize(entryDimension);
716 tf.setMaximumSize(entryDimension);
717 keywordValues.add(tf);
718 }
719
720 public enum SwingRepresentation {
721 TEXTFIELD,
722 CHECKBOX,
723 CHECKBOXES,
724 EDITCOMBOBOX,
725 COMBOBOX,
726 MULTIPOLE
727 }
728 }