work on refresh after popup action
[fanfix.git] / src / be / nikiroo / fanfix_swing / gui / browser / BasicTab.java
CommitLineData
3cdf3fd8
NR
1package be.nikiroo.fanfix_swing.gui.browser;
2
3import java.awt.BorderLayout;
4import java.awt.Component;
5import java.awt.event.ActionEvent;
6import java.awt.event.ActionListener;
7import java.util.ArrayList;
8import java.util.List;
9import java.util.Map;
10
3cdf3fd8
NR
11import javax.swing.JTree;
12import javax.swing.SwingWorker;
3cdf3fd8
NR
13import javax.swing.event.TreeSelectionEvent;
14import javax.swing.event.TreeSelectionListener;
3cdf3fd8
NR
15import javax.swing.plaf.basic.BasicTreeUI;
16import javax.swing.tree.DefaultMutableTreeNode;
17import javax.swing.tree.DefaultTreeCellRenderer;
18import javax.swing.tree.DefaultTreeModel;
19import javax.swing.tree.TreeCellRenderer;
20import javax.swing.tree.TreePath;
21
3cdf3fd8 22import be.nikiroo.fanfix_swing.gui.SearchBar;
2a03ecc0 23import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel;
3cdf3fd8 24import be.nikiroo.fanfix_swing.gui.utils.TreeCellSpanner;
2a03ecc0 25import be.nikiroo.fanfix_swing.gui.utils.TreeSnapshot;
3cdf3fd8
NR
26import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
27import be.nikiroo.fanfix_swing.images.IconGenerator;
28import be.nikiroo.fanfix_swing.images.IconGenerator.Icon;
29import be.nikiroo.fanfix_swing.images.IconGenerator.Size;
30
2a03ecc0 31public abstract class BasicTab<T> extends ListenerPanel {
3cdf3fd8
NR
32 private int totalCount = 0;
33 private List<String> selectedElements = new ArrayList<String>();
34 private T data;
35 private String baseTitle;
36 private String listenerCommand;
37 private int index;
38
39 private JTree tree;
2a03ecc0 40 private DefaultMutableTreeNode root;
3cdf3fd8
NR
41 private SearchBar searchBar;
42
43 public BasicTab(int index, String listenerCommand) {
44 setLayout(new BorderLayout());
45
46 this.index = index;
47 this.listenerCommand = listenerCommand;
48
49 data = createEmptyData();
50 totalCount = 0;
51
2a03ecc0 52 root = new DefaultMutableTreeNode();
3cdf3fd8
NR
53
54 tree = new JTree(root);
55 tree.setUI(new BasicTreeUI());
56 TreeCellSpanner spanner = new TreeCellSpanner(tree, generateCellRenderer());
57 tree.setCellRenderer(spanner);
58 tree.setRootVisible(false);
59 tree.setShowsRootHandles(false);
60
61 tree.addTreeSelectionListener(new TreeSelectionListener() {
62 @Override
63 public void valueChanged(TreeSelectionEvent e) {
64 List<String> elements = new ArrayList<String>();
65 TreePath[] paths = tree.getSelectionPaths();
66 if (paths != null) {
67 for (TreePath path : paths) {
68 String key = path.getLastPathComponent().toString();
69 elements.add(keyToElement(key));
70 }
71 }
72
73 List<String> selectedElements = new ArrayList<String>();
74 for (String element : elements) {
75 if (!selectedElements.contains(element)) {
76 selectedElements.add(element);
77 }
78 }
79
80 BasicTab.this.selectedElements = selectedElements;
81
2a03ecc0 82 fireActionPerformed(BasicTab.this.listenerCommand);
3cdf3fd8
NR
83 }
84 });
85
86 add(UiHelper.scroll(tree), BorderLayout.CENTER);
87
88 searchBar = new SearchBar();
89 add(searchBar, BorderLayout.NORTH);
90 searchBar.addActionListener(new ActionListener() {
91 @Override
92 public void actionPerformed(ActionEvent e) {
2a03ecc0 93 reloadData();
3cdf3fd8
NR
94 }
95 });
96
2a03ecc0
NR
97 reloadData();
98 }
99
100 public void reloadData() {
101 final TreeSnapshot snapshot = new TreeSnapshot(tree);
3cdf3fd8
NR
102 SwingWorker<Map<String, List<String>>, Integer> worker = new SwingWorker<Map<String, List<String>>, Integer>() {
103 @Override
104 protected Map<String, List<String>> doInBackground() throws Exception {
2a03ecc0
NR
105 fillData(data);
106 return null;
3cdf3fd8
NR
107 }
108
109 @Override
110 protected void done() {
2a03ecc0
NR
111 try {
112 get();
113 } catch (Exception e) {
114 // TODO: error
115 }
116
117 // TODO: update is flickering...
118
3cdf3fd8
NR
119 root.removeAllChildren();
120 totalCount = loadData(root, data, searchBar.getText());
121 ((DefaultTreeModel) tree.getModel()).reload();
122
2a03ecc0
NR
123 snapshot.apply();
124
125 fireActionPerformed(listenerCommand);
3cdf3fd8
NR
126 }
127 };
128 worker.execute();
129 }
130
131 /**
132 * The currently selected elements, or an empty list.
133 *
134 * @return the sources (cannot be NULL)
135 */
136 public List<String> getSelectedElements() {
137 return selectedElements;
138 }
139
140 public int getTotalCount() {
141 return totalCount;
142 }
143
144 public String getBaseTitle() {
145 return baseTitle;
146 }
147
148 public void setBaseTitle(String baseTitle) {
149 this.baseTitle = baseTitle;
150 }
151
152 public String getTitle() {
153 String title = getBaseTitle();
154 String count = "";
155 if (totalCount > 0) {
156 int selected = selectedElements.size();
157 count = " (" + (selected > 0 ? selected + "/" : "") + totalCount + ")";
158 }
159
160 return title + count;
161 }
162
163 public int getIndex() {
164 return index;
165 }
166
167 public void unselect() {
168 tree.clearSelection();
169 }
170
3cdf3fd8
NR
171 protected boolean checkFilter(String filter, String value) {
172 return (filter == null || filter.isEmpty() || value.toLowerCase().contains(filter.toLowerCase()));
173 }
174
175 protected boolean checkFilter(String filter, List<String> list) {
176 for (String value : list) {
177 if (checkFilter(filter, value))
178 return true;
179 }
180 return false;
181 }
182
183 protected abstract T createEmptyData();
184
185 protected abstract void fillData(T data);
186
187 protected abstract String keyToElement(String key);
188
189 protected abstract String keyToDisplay(String key);
190
191 protected abstract int loadData(DefaultMutableTreeNode root, T data, String filter);
192
193 private TreeCellRenderer generateCellRenderer() {
194 DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() {
195 @Override
196 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
197 boolean leaf, int row, boolean hasFocus) {
198 if (value instanceof DefaultMutableTreeNode) {
199 if (((DefaultMutableTreeNode) value).getLevel() > 1) {
200 setLeafIcon(null);
201 setLeafIcon(IconGenerator.get(Icon.empty, Size.x4));
202 } else {
203 setLeafIcon(IconGenerator.get(Icon.empty, Size.x16));
204 }
205 }
206
207 String display = value == null ? "" : value.toString();
208 if (!display.isEmpty())
209 display = keyToDisplay(display);
210
211 return super.getTreeCellRendererComponent(tree, display, selected, expanded, leaf, row, hasFocus);
212 }
213 };
214
215 renderer.setClosedIcon(IconGenerator.get(Icon.arrow_right, Size.x16));
216 renderer.setOpenIcon(IconGenerator.get(Icon.arrow_down, Size.x16));
217 renderer.setLeafIcon(IconGenerator.get(Icon.empty, Size.x16));
218
219 return renderer;
220 }
221}