1 package be
.nikiroo
.fanfix_swing
.gui
.browser
;
3 import java
.awt
.BorderLayout
;
4 import java
.awt
.Component
;
5 import java
.awt
.event
.ActionEvent
;
6 import java
.awt
.event
.ActionListener
;
7 import java
.util
.ArrayList
;
8 import java
.util
.Collection
;
9 import java
.util
.Collections
;
10 import java
.util
.Comparator
;
11 import java
.util
.List
;
14 import javax
.swing
.JTree
;
15 import javax
.swing
.SwingWorker
;
16 import javax
.swing
.event
.TreeSelectionEvent
;
17 import javax
.swing
.event
.TreeSelectionListener
;
18 import javax
.swing
.plaf
.basic
.BasicTreeUI
;
19 import javax
.swing
.tree
.DefaultMutableTreeNode
;
20 import javax
.swing
.tree
.DefaultTreeCellRenderer
;
21 import javax
.swing
.tree
.DefaultTreeModel
;
22 import javax
.swing
.tree
.TreeCellRenderer
;
23 import javax
.swing
.tree
.TreePath
;
25 import be
.nikiroo
.fanfix_swing
.gui
.SearchBar
;
26 import be
.nikiroo
.fanfix_swing
.gui
.utils
.ListenerPanel
;
27 import be
.nikiroo
.fanfix_swing
.gui
.utils
.TreeCellSpanner
;
28 import be
.nikiroo
.fanfix_swing
.gui
.utils
.TreeSnapshot
;
29 import be
.nikiroo
.fanfix_swing
.gui
.utils
.UiHelper
;
30 import be
.nikiroo
.fanfix_swing
.images
.IconGenerator
;
31 import be
.nikiroo
.fanfix_swing
.images
.IconGenerator
.Icon
;
32 import be
.nikiroo
.fanfix_swing
.images
.IconGenerator
.Size
;
34 public abstract class BasicTab
<T
> extends ListenerPanel
{
35 private int totalCount
= 0;
36 private List
<String
> selectedElements
= new ArrayList
<String
>();
38 private String baseTitle
;
39 private String listenerCommand
;
43 private DefaultMutableTreeNode root
;
44 private SearchBar searchBar
;
46 public BasicTab(int index
, String listenerCommand
) {
47 setLayout(new BorderLayout());
50 this.listenerCommand
= listenerCommand
;
52 data
= createEmptyData();
55 root
= new DefaultMutableTreeNode();
57 tree
= new JTree(root
);
58 tree
.setUI(new BasicTreeUI());
59 TreeCellSpanner spanner
= new TreeCellSpanner(tree
,
60 generateCellRenderer());
61 tree
.setCellRenderer(spanner
);
62 tree
.setRootVisible(false);
63 tree
.setShowsRootHandles(false);
65 tree
.addTreeSelectionListener(new TreeSelectionListener() {
67 public void valueChanged(TreeSelectionEvent e
) {
68 List
<String
> elements
= new ArrayList
<String
>();
69 TreePath
[] paths
= tree
.getSelectionPaths();
71 for (TreePath path
: paths
) {
72 String key
= path
.getLastPathComponent().toString();
73 elements
.add(keyToElement(key
));
77 List
<String
> selectedElements
= new ArrayList
<String
>();
78 for (String element
: elements
) {
79 if (!selectedElements
.contains(element
)) {
80 selectedElements
.add(element
);
84 BasicTab
.this.selectedElements
= selectedElements
;
86 fireActionPerformed(BasicTab
.this.listenerCommand
);
90 add(UiHelper
.scroll(tree
), BorderLayout
.CENTER
);
92 searchBar
= new SearchBar();
93 add(searchBar
, BorderLayout
.NORTH
);
94 searchBar
.addActionListener(new ActionListener() {
96 public void actionPerformed(ActionEvent e
) {
104 public void reloadData() {
105 final TreeSnapshot snapshot
= new TreeSnapshot(tree
) {
107 protected boolean isSamePath(TreePath oldPath
, TreePath newPath
) {
108 String oldString
= oldPath
.toString();
109 if (oldString
.endsWith("/]"))
110 oldString
= oldString
.substring(0, oldString
.length() - 2)
113 String newString
= newPath
.toString();
114 if (newString
.endsWith("/]"))
115 newString
= newString
.substring(0, newString
.length() - 2)
118 return oldString
.equals(newString
);
121 SwingWorker
<Map
<String
, List
<String
>>, Integer
> worker
= new SwingWorker
<Map
<String
, List
<String
>>, Integer
>() {
123 protected Map
<String
, List
<String
>> doInBackground()
130 protected void done() {
133 } catch (Exception e
) {
137 root
.removeAllChildren();
138 totalCount
= loadData(root
, data
, searchBar
.getText());
139 ((DefaultTreeModel
) tree
.getModel()).reload();
143 fireActionPerformed(listenerCommand
);
150 * The currently selected elements, or an empty list.
152 * @return the sources (cannot be NULL)
154 public List
<String
> getSelectedElements() {
155 return selectedElements
;
158 public int getTotalCount() {
162 public String
getBaseTitle() {
166 public void setBaseTitle(String baseTitle
) {
167 this.baseTitle
= baseTitle
;
170 public String
getTitle() {
171 String title
= getBaseTitle();
173 if (totalCount
> 0) {
174 int selected
= selectedElements
.size();
175 count
= " (" + (selected
> 0 ? selected
+ "/" : "") + totalCount
179 return title
+ count
;
182 public int getIndex() {
186 public void unselect() {
187 tree
.clearSelection();
190 protected boolean checkFilter(String filter
, String value
) {
191 return (filter
== null || filter
.isEmpty()
192 || value
.toLowerCase().contains(filter
.toLowerCase()));
195 protected boolean checkFilter(String filter
, List
<String
> list
) {
196 for (String value
: list
) {
197 if (checkFilter(filter
, value
))
203 protected abstract T
createEmptyData();
205 // beware: you should update it OR clean/re-add it, but previous data may
207 protected abstract void fillData(T data
);
209 protected abstract String
keyToElement(String key
);
211 protected abstract String
keyToDisplay(String key
);
213 protected abstract int loadData(DefaultMutableTreeNode root
, T data
,
216 protected void sort(List
<String
> values
) {
217 Collections
.sort(values
, new Comparator
<String
>() {
219 public int compare(String o1
, String o2
) {
220 return ("" + o1
).compareToIgnoreCase("" + o2
);
225 private TreeCellRenderer
generateCellRenderer() {
226 DefaultTreeCellRenderer renderer
= new DefaultTreeCellRenderer() {
228 public Component
getTreeCellRendererComponent(JTree tree
,
229 Object value
, boolean selected
, boolean expanded
,
230 boolean leaf
, int row
, boolean hasFocus
) {
231 if (value
instanceof DefaultMutableTreeNode
) {
232 if (((DefaultMutableTreeNode
) value
).getLevel() > 1) {
234 setLeafIcon(IconGenerator
.get(Icon
.empty
, Size
.x4
));
236 setLeafIcon(IconGenerator
.get(Icon
.empty
, Size
.x16
));
240 String display
= value
== null ?
"" : value
.toString();
241 display
= keyToDisplay(display
);
243 return super.getTreeCellRendererComponent(tree
, display
,
244 selected
, expanded
, leaf
, row
, hasFocus
);
248 renderer
.setClosedIcon(IconGenerator
.get(Icon
.arrow_right
, Size
.x16
));
249 renderer
.setOpenIcon(IconGenerator
.get(Icon
.arrow_down
, Size
.x16
));
250 renderer
.setLeafIcon(IconGenerator
.get(Icon
.empty
, Size
.x16
));