1 /*
2 Copyright 2002-2006 Martin van den Bemt
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 package org.xulux.guilayer.swing.widgets;
17
18 import java.awt.Component;
19 import java.awt.Container;
20 import java.awt.event.HierarchyEvent;
21 import java.awt.event.HierarchyListener;
22 import java.util.Iterator;
23
24 import javax.swing.Icon;
25 import javax.swing.JComponent;
26 import javax.swing.JTabbedPane;
27 import javax.swing.SwingUtilities;
28
29 import org.xulux.api.gui.IWidget;
30 import org.xulux.api.gui.IXuluxListener;
31 import org.xulux.gui.ContainerWidget;
32 import org.xulux.guilayer.swing.util.SwingUtils;
33
34 /**
35 * A panel that contains tabs..
36 *
37 *
38 * @todo Dig deeper into tabPanels..
39 * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
40 * @version $Id: TabPanel.java,v 1.1 2005/12/18 12:58:18 mvdb Exp $
41 */
42 public class TabPanel extends ContainerWidget {
43
44 /**
45 * The native tabbedPane
46 */
47 private JTabbedPane tabPanel;
48
49 /**
50 * The tabCount
51 */
52 private int tabCount;
53 /**
54 * The tabid key that is used internally
55 * by nyx. Made it public so people can use
56 * it if they want to in their rules.
57 */
58 public static final String TABID = "nyx-tab-id";
59
60 /**
61 * Which tab has initialfocus
62 */
63 private String initialFocus;
64 /**
65 * The repaintcomponent class
66 */
67 private RepaintComponent repaintComponent;
68 /**
69 * the repaintthreads
70 */
71 private Thread repaintThread;
72
73 /**
74 * @param name the name of the tabPanel
75 */
76 public TabPanel(String name) {
77 super(name);
78 }
79
80 /**
81 * @see org.xulux.gui.XuluxWidget#destroy()
82 */
83 public void destroy() {
84 super.destroy();
85 if (tabPanel == null) {
86 return;
87 }
88 if (repaintComponent != null) {
89 tabPanel.removeHierarchyListener(repaintComponent);
90 repaintComponent = null;
91 }
92 Container container = tabPanel.getParent();
93 tabPanel.setVisible(false);
94 tabPanel.removeAll();
95 if (container != null) {
96 container.remove(tabPanel);
97 }
98 tabPanel = null;
99 }
100
101 /**
102 * @see org.xulux.nyx.gui.XuluxWidget#focus()
103 * @todo This is bad coding
104 */
105 public void focus() {
106 Object object = getPart().getSession().getValue("nyx.focusrequest");
107 if (object != null) {
108 IWidget w = (IWidget) object;
109 System.out.println("tabcount : " + w.getProperty(TABID));
110 w = findChildAndParentForFocus(w);
111 this.tabPanel.setSelectedComponent((JComponent) w.getNativeWidget());
112 }
113 this.tabPanel.requestFocus();
114 }
115
116 /**
117 * Tries to find the widget of the parent of the widget passed
118 * and which is also a child of this widget
119 * @param w the widget
120 * @return null when it is not found.
121 */
122 private IWidget findChildAndParentForFocus(IWidget w) {
123 while (w != null) {
124 if (getChildWidgets().contains(w)) {
125 return w;
126 } else {
127 w = w.getParent();
128 }
129 }
130 return null;
131 }
132
133 /**
134 * @see org.xulux.nyx.gui.XuluxWidget#getNativeWidget()
135 */
136 public Object getNativeWidget() {
137 initialize();
138 return this.tabPanel;
139 }
140
141 /**
142 * @see org.xulux.nyx.gui.XuluxWidget#initialize()
143 */
144 public void initialize() {
145 if (initialized) {
146 return;
147 }
148 // we default to XYLayout for now..
149 initialized = true;
150 tabPanel = new JTabbedPane();
151 // repaintComponent = new RepaintComponent();
152 // tabPanel.addHierarchyListener(repaintComponent);
153 // repaintThread = new Thread(repaintComponent);
154 // repaintThread.start();
155 // System.err.println("Still running");
156 initializeChildren();
157 refresh();
158 processInit();
159 }
160
161 /**
162 * @see org.xulux.nyx.gui.XuluxWidget#refresh()
163 */
164 public void refresh() {
165 isRefreshing = true;
166 initialize();
167 // tabPanel.setVisible(isVisible());
168 isRefreshing = false;
169 }
170
171 /**
172 * Adds a widget to the tabPanel if the widget
173 * is a panel. For now no support for other
174 * widget types. Need to dig in deep into
175 * panels to see what can be usefull here
176 * @todo Tooltips don't seem to work in jdk1.3
177 * @see org.xulux.nyx.gui.ContainerWidget#addToParent(org.xulux.nyx.gui.XuluxWidget)
178 */
179 public void addToParent(IWidget widget) {
180
181 if (widget instanceof Panel || widget instanceof Tab) {
182 System.out.println("Adding panel " + widget);
183 String tabTitle = widget.getProperty("title");
184 String tabTip = widget.getProperty("tip");
185 String tabIcon = widget.getProperty("icon");
186 Icon icon = null;
187 if (tabIcon != null) {
188 try {
189 icon = SwingUtils.getIcon(tabIcon, this);
190 } catch (Exception e) {
191 System.out.println("Icon resource " + tabIcon + " cannot be found");
192 }
193 }
194 // always add the parent to the added widget..
195 widget.setParent(this);
196 tabPanel.addTab(tabTitle, icon, (Component) widget.getNativeWidget(), tabTip);
197 // just in case, but this doesn't seem to
198 // work either. Who know jdk1.4 does..
199 tabPanel.setToolTipTextAt(tabCount, tabTip);
200 // add the tabId to the property of the widget.
201 widget.setLazyProperty(TABID, String.valueOf(tabCount));
202 // Set the selectedIndex to the first tab that is not disabled.
203 if (initialFocus == null && widget.isEnabled() && widget.isVisible()) {
204 initialFocus = String.valueOf(tabCount);
205 tabPanel.setSelectedIndex(tabCount);
206 }
207 //widget.refresh();
208 tabCount++;
209 } else {
210 // do not yet allow any addition of other widgets.
211 // tabPanel.add((Component)widget.getNativeWidget(), widget);
212 System.out.println("Only panel widgets are allowed on top of a tabPanel, skipping widget " + widget);
213 }
214 }
215 /**
216 * @see org.xulux.nyx.gui.XuluxWidget#getGuiValue()
217 */
218 public Object getGuiValue() {
219 return null;
220 }
221
222 /**
223 * @see org.xulux.nyx.gui.XuluxWidget#canContainValue()
224 */
225 public boolean canContainValue() {
226 return false;
227 }
228
229 /**
230 * @see org.xulux.nyx.gui.XuluxWidget#isValueEmpty()
231 */
232 public boolean isValueEmpty() {
233 return true;
234 }
235
236 /**
237 * @see org.xulux.nyx.gui.XuluxWidget#addXuluxListener(org.xulux.nyx.gui.XuluxListener)
238 */
239 public void addXuluxListener(IXuluxListener listener) {
240 }
241
242 /**
243 * Fixes painting issues with the tabPanel.
244 * Eg buttons from another panel would shine through
245 * the first panel. After selecting the panel with the shine
246 * through buttons on it, the problems would never appear again.
247 * The selection of other tabs needs to be done in seperate runnables,
248 * since else the painting doesn't complete of other components.
249 * Probably calling the listeners with fireStatChanged will do,
250 * but couldn't figure that out yet..
251 *
252 * @todo : dig in this deeper, probably fixable some other way!
253 */
254 public class RepaintComponent implements Runnable, HierarchyListener {
255 /**
256 * The index
257 */
258 private int index = 0;
259 /**
260 * if the component is running
261 */
262 private boolean isRunning;
263
264 /**
265 * the constructor
266 */
267 public RepaintComponent() {
268 }
269
270 /**
271 * @see java.lang.Runnable#run()
272 */
273 public void run() {
274 if (getPart() == null) {
275 return;
276 }
277 while (!tabPanel.isShowing()) {
278 //System.err.println("isShowing ? "+tabPanel.isShowing());
279 boolean sleep = true;
280 if (sleep) {
281 try {
282 Thread.sleep(1000);
283 } catch (InterruptedException ie) {
284 // please repaint everything..
285 sleep = false;
286 break;
287 }
288 }
289 }
290 int selected = tabPanel.getSelectedIndex();
291 for (int i = 0; i < tabPanel.getTabCount(); i++) {
292 selectIndex(i);
293 }
294 selectIndex(selected);
295 //tabPanel.setVisible(true);
296 tabPanel.validate();
297 tabPanel.repaint();
298 }
299
300 /**
301 * Select the specified index
302 * @param index the index
303 */
304 public void selectIndex(final int index) {
305 try {
306 SwingUtilities.invokeAndWait(new Runnable() {
307
308 /**
309 * @see java.lang.Runnable#run()
310 */
311 public void run() {
312 tabPanel.setSelectedIndex(index);
313 }
314 });
315 } catch (Exception e) {
316 e.printStackTrace(System.out);
317 }
318 }
319
320 /**
321 * @see java.awt.event.HierarchyListener#hierarchyChanged(java.awt.event.HierarchyEvent)
322 */
323 public void hierarchyChanged(HierarchyEvent e) {
324 if (isRunning) {
325 return;
326 }
327 Iterator it = getPart().getWidgets().iterator();
328 while (it.hasNext()) {
329 IWidget w = (IWidget) it.next();
330 if (e.getChanged().equals(w.getNativeWidget())) {
331 break;
332 }
333 }
334
335 if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
336 repaintThread.interrupt();
337 }
338 }
339
340 }
341 }