1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /*
19 * @author Paul Smith <psmith@apache.org>
20 *
21 */
22 package org.apache.log4j.chainsaw;
23
24 import com.thoughtworks.xstream.XStream;
25 import com.thoughtworks.xstream.io.xml.DomDriver;
26 import org.apache.log4j.chainsaw.prefs.LoadSettingsEvent;
27 import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
28 import org.apache.log4j.chainsaw.prefs.SettingsListener;
29 import org.apache.log4j.chainsaw.prefs.SettingsManager;
30
31 import javax.swing.*;
32 import java.awt.*;
33 import java.io.File;
34 import java.io.FileReader;
35 import java.io.FileWriter;
36
37
38 /**
39 * The only reason this class is needed is because
40 * of a stupid 'issue' with the JTabbedPane.
41 * <p>
42 * If the currently selected tab is the first tab,
43 * and we insert a new tab at the front, then as
44 * far as the JTabbedPane is concerned, NO STATE has
45 * changed, as the currently selected tab index is still
46 * the same (even though the TAB is different - go figure)
47 * and therefore no ChangeEvent is generated and sent
48 * to listeners. Thanks very much Sun!
49 * <p>
50 * For more information on the issue:
51 * http://developer.java.sun.com/developer/bugParade/bugs/4253819.html
52 *
53 * @author Paul Smith <psmith@apache.org>
54 * @author Scott Deboy <sdeboy@apache.org>
55 */
56
57 class ChainsawTabbedPane extends JTabbedPane implements SettingsListener {
58 public SavableTabSetting tabSetting;
59 public static final String WELCOME_TAB = "Welcome";
60 public static final String ZEROCONF = "Zeroconf";
61
62 /**
63 * Create the tabbed pane.
64 */
65 public ChainsawTabbedPane() {
66 super();
67 }
68
69 /**
70 * Returns true if this TabbedPane has an instance of the WelcomePanel
71 * in it
72 *
73 * @return true/false
74 */
75 boolean containsWelcomePanel() {
76 return indexOfTab("Welcome") > -1;
77 }
78
79 /**
80 * Our custom implementation of inserting a new tab,
81 * this method ALWAYS inserts it at the front because
82 * we get an ArrayIndexOutOfBoundsException otherwise
83 * under some JDK implementations.
84 * <p>
85 * This method also causes a fireStateChange() to be
86 * called so that listeners get notified of the event.
87 * See the class level comments for the reason why...
88 *
89 * @param name
90 * @param component
91 */
92 public void addANewTab(String name, JComponent component, Icon icon) {
93 super.insertTab(name, icon, component, null, getTabCount());
94
95 super.fireStateChanged();
96 if (!"chainsaw-log".equals(name)) {
97 EventQueue.invokeLater(() -> setSelectedTab(getTabCount() - 1));
98 }
99 }
100
101 public void setSelectedTab(int index) {
102 if (getTabCount() >= index) {
103 setSelectedIndex(index);
104 }
105
106 getSelectedComponent().setVisible(true);
107 getSelectedComponent().validate();
108 super.fireStateChanged();
109 }
110
111 public void addANewTab(
112 String name, JComponent component, Icon icon, String tooltip) {
113 super.insertTab(name, icon, component, tooltip, getTabCount());
114 super.fireStateChanged();
115 }
116
117 public void remove(Component component) {
118 super.remove(component);
119 super.fireStateChanged();
120 }
121
122 /**
123 * Saves the state of the currently active tabs to an XML file.
124 * Only considers the Welcome, Drag and Drop and chainsaw-log
125 * panels as they are the panel which are always running. Saves
126 * whether they are hidden or not....
127 */
128
129 public void saveSettings(SaveSettingsEvent event) {
130 File file = new File(SettingsManager.getInstance().getSettingsDirectory(), "tab-settings.xml");
131 XStream stream = new XStream(new DomDriver());
132 try {
133 FileWriter writer = new FileWriter(file);
134 int count = super.getTabCount();
135 String title;
136 SavableTabSetting setting = new SavableTabSetting();
137 for (int i = 0; i < count; i++) {
138 title = super.getTitleAt(i);
139 switch (title) {
140 case WELCOME_TAB:
141 setting.setWelcome(true);
142 break;
143 case "chainsaw-log":
144 setting.setChainsawLog(true);
145 break;
146 case ZEROCONF:
147 setting.setZeroconf(true);
148 break;
149 }
150 }
151
152 stream.toXML(setting, writer);
153 writer.close();
154
155 } catch (Exception e) {
156 file.delete();
157 e.printStackTrace();
158 }
159 }
160
161 /**
162 * Loads the saved tab setting by reading the XML file.
163 * If the file doesn't exist, all three panels should be
164 * shown as the default setting....
165 */
166
167 public void loadSettings(LoadSettingsEvent event) {
168 File file = new File(SettingsManager.getInstance().getSettingsDirectory(), "tab-settings.xml");
169 XStream stream = new XStream(new DomDriver());
170 try {
171 if (file.exists()) {
172 FileReader reader = new FileReader(file);
173 tabSetting = (SavableTabSetting) stream.fromXML(reader);
174 reader.close();
175 } else {
176 tabSetting = new SavableTabSetting();
177 tabSetting.setWelcome(true);
178 tabSetting.setChainsawLog(true);
179 tabSetting.setZeroconf(true);
180 }
181 } catch (Exception e) {
182 e.printStackTrace();
183 file.delete();
184 }
185 }
186 }