2 package be
.nikiroo
.utils
.ui
;
4 import java
.awt
.BorderLayout
;
5 import java
.awt
.Dimension
;
6 import java
.awt
.event
.ActionEvent
;
7 import java
.awt
.event
.ActionListener
;
8 import java
.awt
.event
.ComponentAdapter
;
9 import java
.awt
.event
.ComponentEvent
;
10 import java
.util
.ArrayList
;
11 import java
.util
.List
;
13 import javax
.swing
.AbstractAction
;
14 import javax
.swing
.BoxLayout
;
15 import javax
.swing
.JPanel
;
16 import javax
.swing
.JPopupMenu
;
17 import javax
.swing
.JToggleButton
;
18 import javax
.swing
.SwingWorker
;
19 import javax
.swing
.event
.PopupMenuEvent
;
20 import javax
.swing
.event
.PopupMenuListener
;
22 public class BreadCrumbsBar
<T
> extends ListenerPanel
{
23 private class BreadCrumb
extends JPanel
{
24 private JToggleButton button
;
25 private JToggleButton down
;
27 public BreadCrumb(final DataNode
<T
> node
) {
28 this.setLayout(new BorderLayout());
31 button
= new JToggleButton(node
.toString());
32 button
.addActionListener(new ActionListener() {
34 public void actionPerformed(ActionEvent e
) {
35 button
.setSelected(false);
37 // TODO: allow clicking on root? option?
38 setSelectedNode(node
);
43 this.add(button
, BorderLayout
.CENTER
);
46 if (!node
.getChildren().isEmpty()) {
47 // TODO (see things with icons included in viewer)
48 down
= new JToggleButton(">");
49 final JPopupMenu popup
= new JPopupMenu();
51 for (final DataNode
<T
> child
: node
.getChildren()) {
52 popup
.add(new AbstractAction(child
.toString()) {
53 private static final long serialVersionUID
= 1L;
56 public void actionPerformed(ActionEvent e
) {
57 setSelectedNode(child
);
62 down
.addActionListener(new ActionListener() {
64 public void actionPerformed(ActionEvent ev
) {
65 if (down
.isSelected()) {
66 popup
.show(down
, 0, down
.getBounds().height
);
68 popup
.setVisible(false);
73 popup
.addPopupMenuListener(new PopupMenuListener() {
75 public void popupMenuWillBecomeVisible(PopupMenuEvent e
) {
79 public void popupMenuWillBecomeInvisible(PopupMenuEvent e
) {
80 down
.setSelected(false);
84 public void popupMenuCanceled(PopupMenuEvent e
) {
88 this.add(down
, BorderLayout
.EAST
);
93 static public final String CHANGE_ACTION
= "change";
95 private boolean vertical
;
96 private DataNode
<T
> node
;
97 private List
<BreadCrumb
> crumbs
= new ArrayList
<BreadCrumb
>();
99 public BreadCrumbsBar(final DataTree
<T
> tree
) {
100 vertical
= true; // to force an update
103 addComponentListener(new ComponentAdapter() {
105 public void componentResized(ComponentEvent e
) {
106 super.componentResized(e
);
107 synchronized (crumbs
) {
108 for (BreadCrumb crumb
: crumbs
) {
115 new SwingWorker
<DataNode
<T
>, Void
>() {
117 protected DataNode
<T
> doInBackground() throws Exception
{
119 return tree
.getRoot();
123 protected void done() {
129 if (node
.size() > 0) {
130 setSelectedNode(node
.getChildren().get(0));
135 } catch (Exception e
) {
142 public void setVertical(boolean vertical
) {
143 if (vertical
!= this.vertical
) {
144 synchronized (crumbs
) {
145 this.vertical
= vertical
;
147 for (BreadCrumb crumb
: crumbs
) {
152 this.setLayout(new BoxLayout(this, BoxLayout
.Y_AXIS
));
154 this.setLayout(new WrapLayout(WrapLayout
.LEADING
));
157 for (BreadCrumb crumb
: crumbs
) {
168 public DataNode
<T
> getSelectedNode() {
172 public void setSelectedNode(DataNode
<T
> node
) {
173 if (this.node
== node
) {
177 synchronized (crumbs
) {
178 // clear until common ancestor (can clear all!)
179 while (this.node
!= null && !this.node
.isParentOf(node
)) {
180 this.node
= this.node
.getParent();
181 this.remove(crumbs
.remove(crumbs
.size() - 1));
184 // switch root if needed and possible
185 if (this.node
== null && node
!= null) {
186 this.node
= node
.getRoot();
190 // re-create until node
191 while (node
!= null && this.node
!= node
) {
192 DataNode
<T
> ancestorOrNode
= node
;
193 for (DataNode
<T
> child
: this.node
.getChildren()) {
194 if (child
.isParentOf(node
))
195 ancestorOrNode
= child
;
198 this.node
= ancestorOrNode
;
206 fireActionPerformed(CHANGE_ACTION
);
209 private void addCrumb(DataNode
<T
> node
) {
210 BreadCrumb crumb
= new BreadCrumb(node
);
211 this.crumbs
.add(crumb
);
216 private void setCrumbSize(BreadCrumb crumb
) {
218 crumb
.setMaximumSize(new Dimension(this.getWidth(),
219 crumb
.getMinimumSize().height
));
221 crumb
.setMaximumSize(null);