1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.aequo.gui;
14
15 import java.awt.Adjustable;
16 import java.awt.BorderLayout;
17 import java.awt.Color;
18 import java.awt.Component;
19 import java.awt.Container;
20 import java.awt.Dimension;
21 import java.awt.Point;
22 import java.awt.event.AdjustmentEvent;
23 import java.awt.event.AdjustmentListener;
24 import java.awt.event.FocusEvent;
25 import java.awt.event.FocusListener;
26 import java.beans.PropertyChangeEvent;
27 import java.beans.PropertyChangeListener;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 import javax.swing.AbstractButton;
32 import javax.swing.Action;
33 import javax.swing.JComponent;
34 import javax.swing.JFrame;
35 import javax.swing.JMenu;
36 import javax.swing.JMenuBar;
37 import javax.swing.JMenuItem;
38 import javax.swing.JPanel;
39 import javax.swing.JPopupMenu;
40 import javax.swing.JScrollBar;
41 import javax.swing.JScrollPane;
42 import javax.swing.JViewport;
43 import javax.swing.KeyStroke;
44 import javax.swing.event.ChangeEvent;
45 import javax.swing.event.ChangeListener;
46 import javax.swing.event.ListDataEvent;
47 import javax.swing.event.ListDataListener;
48
49 import org.abstracthorizon.aequo.CompareEntry;
50 import org.abstracthorizon.aequo.CompareModel;
51 import org.abstracthorizon.aequo.DefaultCompareModel;
52 import org.abstracthorizon.aequo.GlobalContext;
53 import org.abstracthorizon.aequo.action.BaseAction;
54 import org.abstracthorizon.aequo.text.TextCompareEntry;
55
56
57
58
59
60
61
62
63
64 public abstract class AbstractComparePanel<T, CompareEntryType extends CompareEntry<T>> extends JPanel {
65
66
67 protected GlobalContext context;
68
69
70 protected JComponent leftList;
71
72
73 protected JComponent rightList;
74
75
76 protected JPanel leftPanel;
77
78
79 protected JPanel rightPanel;
80
81
82 protected BottomPanel bottomLeftPanel;
83
84
85 protected BottomPanel bottomRightPanel;
86
87
88 protected JScrollPane leftScrollPane;
89
90
91 protected JScrollPane rightScrollPane;
92
93
94 protected JScrollBar horizontalBar;
95
96
97 protected Map<Byte, Color> foreGrounds = new HashMap<Byte, Color>();
98
99
100 protected Map<Byte, Color> backGrounds = new HashMap<Byte, Color>();
101
102
103 protected CompareModel<T, CompareEntryType> compareModel = new DefaultCompareModel<T, CompareEntryType>(2);
104
105
106 protected Map<String, BaseAction> actionsCache = new HashMap<String, BaseAction>();
107
108
109 protected JPopupMenu leftPopupMenu;
110
111
112 protected JPopupMenu rightPopupMenu;
113
114
115
116
117
118 public AbstractComparePanel(GlobalContext context) {
119 this(context, new DefaultCompareModel<T, CompareEntryType>(2));
120 }
121
122
123
124
125
126
127 public AbstractComparePanel(GlobalContext context, CompareModel<T, CompareEntryType> compareModel) {
128 super(new BorderLayout());
129 this.compareModel = compareModel;
130 this.context = context;
131 }
132
133
134
135
136
137 public GlobalContext getGlobalContext() {
138 return context;
139 }
140
141
142
143
144
145 public Component getLeftList() {
146 return leftList;
147 }
148
149
150
151
152
153 public Component getRightList() {
154 return rightList;
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168 public void initialise() {
169
170 createActions();
171
172 setUpColors();
173
174 createPanels();
175
176 createLists();
177
178 createScrollPanes();
179
180
181
182
183 }
184
185
186
187
188
189 public CompareModel<T, CompareEntryType> getCompareModel() {
190 return compareModel;
191 }
192
193
194
195
196 protected void setUpColors() {
197 foreGrounds.put(CompareEntry.EMPTY, Color.BLACK);
198 backGrounds.put(CompareEntry.EMPTY, Color.LIGHT_GRAY);
199
200 foreGrounds.put(CompareEntry.EQUAL, Color.BLACK);
201 backGrounds.put(CompareEntry.EQUAL, Color.WHITE);
202
203 foreGrounds.put(CompareEntry.LESS, Color.BLACK);
204 backGrounds.put(CompareEntry.LESS, new Color(255, 180, 180));
205
206 foreGrounds.put(CompareEntry.GREATER, Color.BLACK);
207 backGrounds.put(CompareEntry.GREATER, new Color(255, 180, 180));
208
209 foreGrounds.put(CompareEntry.DIFFERENT, Color.BLACK);
210 backGrounds.put(CompareEntry.DIFFERENT, new Color(255, 180, 180));
211
212 foreGrounds.put(TextCompareEntry.SIMILAR, Color.BLACK);
213 backGrounds.put(TextCompareEntry.SIMILAR, new Color(255, 208, 208));
214
215 foreGrounds.put(TextCompareEntry.CHANGED, Color.BLACK);
216 backGrounds.put(TextCompareEntry.CHANGED, new Color(255, 255, 180));
217 }
218
219
220
221
222 protected void createPanels() {
223 leftPanel = new JPanel(new BorderLayout());
224 rightPanel = new JPanel(new BorderLayout());
225
226 bottomLeftPanel = new BottomPanel();
227 bottomRightPanel = new BottomPanel();
228
229 bottomLeftPanel.setOtherPanel(bottomRightPanel);
230 bottomRightPanel.setOtherPanel(bottomLeftPanel);
231
232 leftPanel.add(bottomLeftPanel, BorderLayout.SOUTH);
233 rightPanel.add(bottomRightPanel, BorderLayout.SOUTH);
234 }
235
236
237
238
239 protected void createLists() {
240 leftList = createLeftComponent();
241 rightList = createRightComponent();
242
243 leftPopupMenu = createActionMenu(0);
244 rightPopupMenu = createActionMenu(1);
245
246 leftList.addFocusListener(new ListFocusListener(0));
247 rightList.addFocusListener(new ListFocusListener(1));
248 }
249
250
251
252
253
254 protected abstract JComponent createLeftComponent();
255
256
257
258
259
260 protected abstract JComponent createRightComponent();
261
262
263
264
265 protected void createScrollPanes() {
266 leftScrollPane = new JScrollPane(leftList);
267 rightScrollPane = new JScrollPane(rightList);
268
269 leftScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
270 rightScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
271 leftScrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
272 rightScrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
273
274
275 leftPanel.add(leftScrollPane, BorderLayout.CENTER);
276 rightPanel.add(rightScrollPane, BorderLayout.CENTER);
277
278 leftScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
279 public void adjustmentValueChanged(AdjustmentEvent e) {
280 rightScrollPane.getVerticalScrollBar().setValue(e.getAdjustable().getValue());
281 }
282 });
283
284 rightScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
285 public void adjustmentValueChanged(AdjustmentEvent e) {
286 leftScrollPane.getVerticalScrollBar().setValue(e.getAdjustable().getValue());
287 }
288 });
289 }
290
291
292
293
294
295
296 protected JPopupMenu createActionMenu(int column) {
297 JPopupMenu menu = new JPopupMenu();
298 menu.addPropertyChangeListener("visible", new PropertyChangeListener() {
299 public void propertyChange(PropertyChangeEvent e) {
300 JPopupMenu menu = (JPopupMenu)e.getSource();
301 updateActions(menu);
302 }
303
304 public void updateActions(Container container) {
305 for (Component component : container.getComponents()) {
306 if (component instanceof AbstractButton) {
307 AbstractButton abstractButton = (AbstractButton)component;
308 Action a = abstractButton.getAction();
309
310 boolean oldValue = component.isEnabled();
311 boolean newValue = a.isEnabled();
312 if (oldValue != newValue) {
313 component.setEnabled(newValue);
314 }
315 } else if (component instanceof Container) {
316 updateActions((Container)component);
317 }
318 }
319 }
320
321 });
322 return menu;
323 }
324
325
326
327
328
329 public void createMenu(JMenuBar menuBar) {
330 }
331
332
333
334
335 protected void createActions() {
336 }
337
338
339
340
341
342
343
344
345
346 protected JMenu obtainMenu(String name, Container menuBar) {
347 int count = menuBar.getComponentCount();
348 for (int i = 0; i < count; i++) {
349 Component c = menuBar.getComponent(i);
350 if (c instanceof JMenu) {
351 JMenu menu = (JMenu)c;
352 String menuName = menu.getText();
353 if (name.equals(menuName)) {
354 return menu;
355 }
356 }
357 }
358 JMenu menu = new JMenu(name);
359 menuBar.add(menu, 1);
360 return menu;
361 }
362
363
364
365
366 protected void addHorizontalBar() {
367 horizontalBar = new JScrollBar(JScrollBar.HORIZONTAL);
368
369 horizontalBar.setMinimum(0);
370 horizontalBar.setValue(0);
371
372 horizontalBar.addAdjustmentListener(new AdjustmentListener() {
373 public void adjustmentValueChanged(AdjustmentEvent e) {
374 Adjustable a = e.getAdjustable();
375 JViewport leftViewport = leftScrollPane.getViewport();
376 JViewport rightViewport = rightScrollPane.getViewport();
377
378 Point leftPoint = leftViewport.getViewPosition();
379 Point rightPoint = rightViewport.getViewPosition();
380
381 leftPoint = new Point(a.getValue(), leftPoint.y);
382 rightPoint = new Point(a.getValue(), rightPoint.y);
383
384 leftViewport.setViewPosition(leftPoint);
385 rightViewport.setViewPosition(rightPoint);
386
387 }
388 });
389
390 compareModel.addListDataListener(new ListDataListener() {
391
392 public void contentsChanged(ListDataEvent e) {
393 updateScrollBar(horizontalBar, leftScrollPane, rightScrollPane);
394 }
395
396 public void intervalAdded(ListDataEvent e) {
397 updateScrollBar(horizontalBar, leftScrollPane, rightScrollPane);
398 }
399
400 public void intervalRemoved(ListDataEvent e) {
401 updateScrollBar(horizontalBar, leftScrollPane, rightScrollPane);
402 }
403
404 });
405
406 bottomRightPanel.add(horizontalBar, BorderLayout.CENTER);
407
408 updateScrollBar(horizontalBar, leftScrollPane, rightScrollPane);
409 }
410
411
412
413
414
415
416 protected BaseAction createCachedAction(String name) {
417 BaseAction action = (BaseAction)createAction(name);
418 if (action != null) {
419 actionsCache.put(name, action);
420 } else {
421 throw new NullPointerException(name);
422 }
423 return action;
424 }
425
426
427
428
429
430 protected void createCachedColumnActions(String name) {
431 BaseAction action = (BaseAction)createAction(name, 0);
432 if (action != null) {
433 actionsCache.put(name, action);
434 } else {
435 throw new NullPointerException(name);
436 }
437 }
438
439
440
441
442
443
444
445 protected Action createAction(String name, int column) {
446 try {
447 Action a = instantiateAction(name);
448 updateAction(a, column);
449 return a;
450 } catch (Exception e) {
451 ErrorDialog.showError(null, "Trying to instantiate action for " + name, e);
452 }
453 return null;
454 }
455
456
457
458
459
460
461 protected Action createAction(String name) {
462 try {
463 Action a = instantiateAction(name);
464 updateAction(a);
465 return a;
466 } catch (Exception e) {
467 e.printStackTrace();
468 ErrorDialog.showError(null, "Trying to instantiate action for " + name, e);
469 }
470 return null;
471 }
472
473 @SuppressWarnings("unchecked")
474
475
476
477
478 protected Action instantiateAction(String name) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
479 Class c = null;
480 if (name.indexOf('.') > 0) {
481
482 try {
483 c = Class.forName(name);
484 } catch (Exception ignore) {
485 }
486 }
487 if (c == null) {
488 try {
489 String n = getClass().getPackage().getName() + ".action." + name;
490 c = Class.forName(n);
491 } catch (Exception ignore) {
492 }
493 }
494 if (c == null) {
495 try {
496 String n = "org.abstracthorizon.aequo.action." + name;
497 c = Class.forName(n);
498 } catch (Exception ignore) {
499 }
500 }
501 if (c != null) {
502 Action a = (Action)c.newInstance();
503 return a;
504 } else {
505 throw new IllegalStateException("Cannot find class " + name);
506 }
507 }
508
509
510
511
512
513
514 protected void updateAction(Action a, int column) {
515 updateAction(a);
516 if (a instanceof BaseAction) {
517 BaseAction baseAction = (BaseAction)a;
518 baseAction.setColumn(column);
519 }
520 }
521
522
523
524
525
526 protected void updateAction(Action a) {
527 if (a instanceof BaseAction) {
528 BaseAction baseAction = (BaseAction)a;
529 baseAction.setGlobalContext(getGlobalContext());
530 }
531 }
532
533
534
535
536
537 protected void updateMenu(Component[] components) {
538 for (Component c : components) {
539 if (c instanceof JMenuItem) {
540 JMenuItem item = (JMenuItem)c;
541 if (item.getAction() instanceof BaseAction) {
542 BaseAction action = (BaseAction)item.getAction();
543 item.setEnabled(action.isEnabled());
544 KeyStroke accelerator = (KeyStroke)action.getValue(Action.ACCELERATOR_KEY);
545 item.setAccelerator(accelerator);
546 Integer mnemonic = (Integer)action.getValue(Action.MNEMONIC_KEY);
547 if (mnemonic != null) {
548 int m = mnemonic.intValue();
549 item.setMnemonic((char)m);
550 }
551 }
552 }
553 }
554 }
555
556
557
558
559
560 protected void updateCachedActionsColumn(int column) {
561 for (BaseAction action : actionsCache.values()) {
562 action.setColumn(column);
563 }
564 }
565
566
567
568
569
570 protected JFrame getEnclosingFrame() {
571 Component c = this;
572 while ((c != null) && !(c instanceof JFrame)) {
573 c = c.getParent();
574 }
575 return (JFrame)c;
576 }
577
578
579
580
581
582
583
584 protected static void updateScrollBar(JScrollBar scrollBar, JScrollPane leftScrollPane, JScrollPane rightScrollPane) {
585 int max = 0;
586
587 int leftWidth = leftScrollPane.getComponent(0).getPreferredSize().width;
588 int rightWidth = rightScrollPane.getComponent(0).getPreferredSize().width;
589
590 if (leftWidth > max) {
591 max = leftWidth;
592 }
593 if (rightWidth > max) {
594 max = rightWidth;
595 }
596
597
598 if (scrollBar.getValue() > max) {
599 scrollBar.setValue(max);
600 }
601 if (scrollBar.getMaximum() != max) {
602 leftWidth = leftScrollPane.getViewport().getWidth();
603 rightWidth = rightScrollPane.getViewport().getWidth();
604 if (leftWidth < rightWidth) {
605 leftWidth = rightWidth;
606 }
607
608 scrollBar.setMaximum(max - leftWidth);
609 }
610 }
611
612
613
614
615 protected static class BottomPanel extends JPanel {
616
617 protected BottomPanel other;
618
619 public BottomPanel() {
620 super(new BorderLayout());
621 }
622
623 public void setOtherPanel(BottomPanel other) {
624 this.other = other;
625 }
626
627 public BottomPanel getOtherPanel() {
628 return other;
629 }
630
631 protected int getInternalPreferredHeight() {
632 return super.getPreferredSize().height;
633 }
634
635 public Dimension getPreferredSize() {
636 Dimension d = super.getPreferredSize();
637 int otherHeight = other.getInternalPreferredHeight();
638 if (otherHeight > d.height) {
639 d = new Dimension(d.width, otherHeight);
640 super.setPreferredSize(d);
641 }
642
643 return d;
644 }
645 }
646
647
648
649
650
651
652 public class MenuChangeListener implements ChangeListener {
653
654 public void stateChanged(ChangeEvent e) {
655 JMenu menu = (JMenu)e.getSource();
656 if (menu.isSelected()) {
657 updateMenu(menu.getMenuComponents());
658 }
659 }
660 }
661
662
663
664
665
666
667
668 public class ListFocusListener implements FocusListener {
669
670 protected int column;
671
672 public ListFocusListener(int column) {
673 this.column = column;
674 }
675
676 public void focusGained(FocusEvent e) {
677 if (!e.isTemporary()) {
678 updateCachedActionsColumn(column);
679 }
680 }
681
682 public void focusLost(FocusEvent e) {
683 if (!e.isTemporary()) {
684 updateCachedActionsColumn(-1);
685 }
686 }
687 }
688
689 }