2 package be
.nikiroo
.utils
.ui
;
4 import java
.awt
.BorderLayout
;
5 import java
.awt
.Dimension
;
6 import java
.awt
.FlowLayout
;
7 import java
.awt
.event
.ActionEvent
;
8 import java
.awt
.event
.ActionListener
;
9 import java
.awt
.event
.ComponentAdapter
;
10 import java
.awt
.event
.ComponentEvent
;
11 import java
.util
.ArrayList
;
12 import java
.util
.List
;
14 import javax
.swing
.AbstractAction
;
15 import javax
.swing
.BoxLayout
;
16 import javax
.swing
.JPanel
;
17 import javax
.swing
.JPopupMenu
;
18 import javax
.swing
.JToggleButton
;
19 import javax
.swing
.SwingWorker
;
20 import javax
.swing
.event
.PopupMenuEvent
;
21 import javax
.swing
.event
.PopupMenuListener
;
23 public class BreadCrumbsBar
<T
> extends ListenerPanel
{
24 private class BreadCrumb
extends JPanel
{
25 private JToggleButton button
;
26 private JToggleButton down
;
28 public BreadCrumb(final DataNode
<T
> node
) {
29 this.setLayout(new BorderLayout());
32 button
= new JToggleButton(node
.toString());
33 button
.addActionListener(new ActionListener() {
35 public void actionPerformed(ActionEvent e
) {
36 button
.setSelected(false);
38 // TODO: allow clicking on root? option?
39 setSelectedNode(node
);
44 this.add(button
, BorderLayout
.CENTER
);
47 if (!node
.getChildren().isEmpty()) {
48 // TODO (see things with icons included in viewer)
49 down
= new JToggleButton(">");
50 final JPopupMenu popup
= new JPopupMenu();
52 for (final DataNode
<T
> child
: node
.getChildren()) {
53 popup
.add(new AbstractAction(child
.toString()) {
54 private static final long serialVersionUID
= 1L;
57 public void actionPerformed(ActionEvent e
) {
58 setSelectedNode(child
);
63 down
.addActionListener(new ActionListener() {
65 public void actionPerformed(ActionEvent ev
) {
66 if (down
.isSelected()) {
67 popup
.show(down
, 0, down
.getBounds().height
);
69 popup
.setVisible(false);
74 popup
.addPopupMenuListener(new PopupMenuListener() {
76 public void popupMenuWillBecomeVisible(PopupMenuEvent e
) {
80 public void popupMenuWillBecomeInvisible(PopupMenuEvent e
) {
81 down
.setSelected(false);
85 public void popupMenuCanceled(PopupMenuEvent e
) {
89 this.add(down
, BorderLayout
.EAST
);
94 static public final String CHANGE_ACTION
= "change";
96 private boolean vertical
;
97 private DataNode
<T
> node
;
98 private List
<BreadCrumb
> crumbs
= new ArrayList
<BreadCrumb
>();
100 public BreadCrumbsBar(final DataTree
<T
> tree
) {
101 vertical
= true; // to force an update
104 addComponentListener(new ComponentAdapter() {
106 public void componentResized(ComponentEvent e
) {
107 super.componentResized(e
);
108 synchronized (crumbs
) {
109 for (BreadCrumb crumb
: crumbs
) {
116 new SwingWorker
<DataNode
<T
>, Void
>() {
118 protected DataNode
<T
> doInBackground() throws Exception
{
120 return tree
.getRoot();
124 protected void done() {
130 if (node
.size() > 0) {
131 setSelectedNode(node
.getChildren().get(0));
136 } catch (Exception e
) {
143 public void setVertical(boolean vertical
) {
144 if (vertical
!= this.vertical
) {
145 synchronized (crumbs
) {
146 this.vertical
= vertical
;
148 for (BreadCrumb crumb
: crumbs
) {
153 this.setLayout(new BoxLayout(this, BoxLayout
.Y_AXIS
));
155 this.setLayout(new WrapLayout(WrapLayout
.LEADING
));
158 for (BreadCrumb crumb
: crumbs
) {
169 public DataNode
<T
> getSelectedNode() {
173 public void setSelectedNode(DataNode
<T
> node
) {
174 if (this.node
== node
) {
178 synchronized (crumbs
) {
179 // clear until common ancestor (can clear all!)
180 while (this.node
!= null && !this.node
.isParentOf(node
)) {
181 this.node
= this.node
.getParent();
182 this.remove(crumbs
.remove(crumbs
.size() - 1));
185 // switch root if needed and possible
186 if (this.node
== null && node
!= null) {
187 this.node
= node
.getRoot();
191 // re-create until node
192 while (node
!= null && this.node
!= node
) {
193 DataNode
<T
> ancestorOrNode
= node
;
194 for (DataNode
<T
> child
: this.node
.getChildren()) {
195 if (child
.isParentOf(node
))
196 ancestorOrNode
= child
;
199 this.node
= ancestorOrNode
;
207 fireActionPerformed(CHANGE_ACTION
);
210 private void addCrumb(DataNode
<T
> node
) {
211 BreadCrumb crumb
= new BreadCrumb(node
);
212 this.crumbs
.add(crumb
);
217 private void setCrumbSize(BreadCrumb crumb
) {
219 crumb
.setMaximumSize(new Dimension(this.getWidth(),
220 crumb
.getMinimumSize().height
));
222 crumb
.setMaximumSize(null);