View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.plugin.news;
21  
22  import javax.swing.AbstractAction;
23  import javax.swing.Action;
24  import javax.swing.BorderFactory;
25  import javax.swing.JLabel;
26  import javax.swing.JPanel;
27  import javax.swing.JScrollPane;
28  import javax.swing.SwingConstants;
29  
30  import java.awt.BorderLayout;
31  import java.awt.Color;
32  import java.awt.FlowLayout;
33  import java.awt.GridBagConstraints;
34  import java.awt.GridBagLayout;
35  import java.awt.event.ActionEvent;
36  import java.io.File;
37  import java.io.IOException;
38  import java.util.LinkedList;
39  import java.util.List;
40  
41  import org.apache.log4j.Logger;
42  import org.xnap.XNap;
43  import org.xnap.gui.StatusBar;
44  import org.xnap.gui.component.EraseButton;
45  import org.xnap.gui.component.HTMLEditorPane;
46  import org.xnap.gui.component.HistoryComboBox;
47  import org.xnap.gui.component.XNapButton;
48  import org.xnap.gui.component.XNapIconButton;
49  import org.xnap.gui.util.GUIHelper;
50  import org.xnap.gui.util.GridBagHelper;
51  import org.xnap.gui.util.IconHelper;
52  import org.xnap.util.Formatter;
53  
54  /***
55   */
56  public class NewsPanel extends JPanel {
57  
58      //--- Constant(s) ---
59  
60      //--- Data field(s) ---
61  
62  	private static Logger logger = Logger.getLogger(NewsPanel.class);   
63  
64  	private List newsItems = new LinkedList();
65  	private HTMLEditorPane pane;
66  	private JPanel locationPanel;
67  	private JPanel actionPanel;
68  	private List actionItems = new LinkedList();
69  	private int cursorPos;
70  	private StringBuffer content;
71  
72  	private HistoryComboBox jcbSearch;
73  	
74      private Action backAction = new BackAction();
75      private Action forwardAction = new ForwardAction();
76      private Action reloadAction = new ReloadAction();
77  	private Action stopAction = new StopAction();
78  	private Action queryAction = new QueryAction();
79  
80      //--- Constructor(s) ---
81      
82      public NewsPanel() 
83      {
84  		setLayout(new GridBagLayout());
85  
86  		// logo
87  		JLabel jlLogo = new JLabel(IconHelper.getScaledLogo(48));
88  		// set a small border on top
89  		jlLogo.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
90  		jlLogo.setHorizontalAlignment(SwingConstants.RIGHT);
91  		GridBagHelper.add(this, jlLogo);
92  
93  		// html pane
94  		pane = new HTMLEditorPane();
95  		content = new StringBuffer();
96  		HTMLEditorPane.addHeader(content);
97  		content.append("<table margin=\"5\"><tr><td>");
98  		cursorPos = content.length();
99  		content.append("</td></tr></table>");
100 		HTMLEditorPane.addFooter(content);	
101 		GridBagHelper.addPanel(this, new JScrollPane(pane));
102 		
103 		// location panel
104 		JPanel locationPanel = new JPanel(new GridBagLayout());
105 		GridBagHelper.add(this, locationPanel);
106 		
107 		EraseButton jbErase = new EraseButton();
108 		GridBagHelper.addComponent(locationPanel, jbErase, GridBagConstraints.WEST);
109 
110 		locationPanel.add(new JLabel(XNap.tr("Location", 1)));
111 		
112 		jcbSearch = new HistoryComboBox(20);
113 		jcbSearch.setText("news:");
114 		jcbSearch.setPreferences("news");
115 		GUIHelper.bindEnterKeyLocally(jcbSearch.getTextField(), queryAction);
116 		jbErase.setTextField(jcbSearch.getTextField());
117 		GridBagHelper.addComponent(locationPanel, jcbSearch, GridBagConstraints.WEST);
118 		
119 		GridBagHelper.addComponent(locationPanel, new XNapIconButton(queryAction));
120 		GridBagHelper.addComponent(locationPanel, new XNapIconButton(backAction));
121 		GridBagHelper.addComponent(locationPanel, new XNapIconButton(forwardAction));
122 		GridBagHelper.addComponent(locationPanel, new XNapIconButton(reloadAction));
123 		GridBagHelper.addComponent(locationPanel, new XNapIconButton(stopAction));
124 		
125 		// actions
126 		actionPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
127 		GridBagHelper.add(locationPanel, actionPanel);
128 	}
129 
130     //--- Method(s) ---
131 
132 	public void add(NewsItem item)
133 	{
134 		if (!newsItems.contains(item)) {
135 			newsItems.add(item);
136 
137 			String message
138 				= "<b>" + item.getTitle() + "</b> - <i>"
139 				+ item.getAuthor() + "</i> - <i>" 
140 				+ Formatter.formatDate(item.getDate()) + "</i>"
141 				+ "<p>" + item.getDescription() + "</p>"
142 				+ "<hr size=1><br>";
143 			insert(message);
144 
145 			Action[] actions = item.getActions();
146 			if (actions != null) {
147 				for (int i = 0; i < actions.length; i++) {
148 					if (!actionItems.contains(actions[i])) {
149 						actionItems.add(actions[i]);
150 						actionPanel.add(new XNapButton(actions[i]));
151 					}
152 				}
153 			}
154 
155 // 			logger.debug("news item added: " + item.toString());
156 // 			this.add(new NewsItemPanel(item));
157 // 			this.add(new JSeparator());
158 // 			this.add(Box.createVerticalStrut(10));
159 		} 
160 		else {
161 			logger.debug("news item already exists ("+item.toString()+").");
162 		}
163 	}
164 
165 	public void insert(String text)
166 	{
167 		content.insert(cursorPos, text);
168 		cursorPos += text.length();
169 		if (actionPanel.isVisible()) {
170 			pane.setText(content.toString());
171 			pane.setCaretPosition(0);
172 		}
173 	}
174 
175 	public boolean open(String location)
176 	{
177     	if (location.length() > 0) {
178     		if (location.startsWith("news:")) {
179     			pane.setText(content.toString());
180     			actionPanel.setVisible(true);
181     			return true;
182     		}
183     		
184     		if (location.indexOf(":") == -1) {
185     			// prepend missing protocol
186     			location = (location.startsWith(File.separator)) 
187 					? "file:"
188 					: "http://"
189 					+ location;
190     		}
191     		
192         	try {
193 				pane.setPage(location);
194     			actionPanel.setVisible(false);
195     			StatusBar.setText(XNap.tr("Retrieving {0}", location));
196     			return true;
197 			}
198 			catch (IOException e) {
199 				StatusBar.setText(e.getLocalizedMessage());
200 			}
201     	}
202     	return false;
203 	}
204 
205 	public class NewsItemPanel extends JPanel {
206 		
207 		public NewsItemPanel(NewsItem item)
208 		{
209 			setLayout(new BorderLayout());
210 			setBackground(Color.white);
211 
212 			String title
213 				= "<html><b>" + item.getTitle() + "</b> - <i>"
214 				+ item.getAuthor() + "</i> - <i>" 
215 				+ Formatter.formatDate(item.getDate()) + "</i>";
216 
217 			JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
218 			buttonPanel.setBackground(Color.white);
219 			Action[] actions = item.getActions();
220 			if (actions != null) {
221 				for (int i = 0; i < actions.length; i++) {
222 					buttonPanel.add(new XNapButton(actions[i]));
223 				}
224 			}
225 
226 			JLabel titleLabel = new JLabel(title);
227 
228 			JLabel descriptionLabel 
229 				= new JLabel(GUIHelper.tt(item.getDescription(), 450));
230 			descriptionLabel.setBorder(GUIHelper.createEmptyBorder(10));
231 
232 			this.add(titleLabel, BorderLayout.NORTH);
233 			this.add(descriptionLabel, BorderLayout.CENTER);
234 			this.add(buttonPanel, BorderLayout.SOUTH);
235 		}
236 
237 	}
238 
239 	//--- Inner Classes ---
240 
241 // 	/***
242 //      * Compares {@link NewsItem} objects by date.
243 //      */
244 //     public static class NewsItemComparator implements Comparator
245 //     {
246 
247 // 		public int compare(Object o1, Object o2) 
248 // 		{
249 // 			return ((NewsItem)o1).getDate().compare
250 // 				(((NewsItem)o2).getDate());
251 // 		}
252 
253 // 	}
254 
255     /***
256      * 
257      */
258     private class QueryAction extends AbstractAction {
259 
260         public QueryAction() 
261 		{
262             //putValue(Action.NAME, XNap.tr("Go"));
263             putValue(Action.SHORT_DESCRIPTION, XNap.tr("Perform search"));
264 			putValue(IconHelper.XNAP_ICON, "key_enter.png");
265         }
266 
267         public void actionPerformed(ActionEvent event) 
268 		{
269         	String location = jcbSearch.getText().trim();
270         	if (open(location)) {
271 				jcbSearch.addDistinctItemAtTop(location);
272         	}
273 		}
274 
275     }
276 
277     /***
278      * Goes back in the browsing history
279      */
280     private class BackAction extends AbstractAction 
281 	{
282         public BackAction() 
283 		{
284             putValue(Action.NAME, XNap.tr("Back"));
285             putValue(Action.SHORT_DESCRIPTION, XNap.tr("Go back"));
286 			putValue(IconHelper.XNAP_ICON, "1leftarrow.png");
287         }
288 
289         public void actionPerformed(ActionEvent event) 
290 		{
291         	int i = jcbSearch.getSelectedIndex();
292         	if (i != -1 && i < jcbSearch.getItemCount() - 1) {
293         		jcbSearch.setSelectedIndex(i + 1);
294         		open((String)jcbSearch.getItemAt(i + 1));
295         	}
296 		}
297     } 
298 
299     /***
300      * Goes forward in the browsing history
301      */
302     private class ForwardAction extends AbstractAction 
303 	{
304         public ForwardAction() 
305 		{
306             putValue(Action.NAME, XNap.tr("Forward"));
307             putValue(Action.SHORT_DESCRIPTION, XNap.tr("Go forward"));
308 			putValue(IconHelper.XNAP_ICON, "1rightarrow.png");
309         }
310 
311         public void actionPerformed(ActionEvent event) 
312 		{
313         	int i = jcbSearch.getSelectedIndex();
314         	if (i > 0) {
315         		jcbSearch.setSelectedIndex(i - 1);
316         		open((String)jcbSearch.getItemAt(i - 1));
317         	}
318 		}
319     } 
320 
321     /***
322      * Reloads the current document
323      */
324     private class ReloadAction extends AbstractAction 
325 	{
326         public ReloadAction() 
327 		{
328             putValue(Action.NAME, XNap.tr("Reload"));
329             putValue(Action.SHORT_DESCRIPTION,
330 					 XNap.tr("Reload current document"));
331 			putValue(IconHelper.XNAP_ICON, "reload.png");
332         }
333 
334         public void actionPerformed(ActionEvent event) 
335 		{
336         	int i = jcbSearch.getSelectedIndex();
337         	if (i != -1) {
338         		open((String)jcbSearch.getItemAt(i));
339         	}
340 		}
341     } 
342     /***
343      * Stops loading the current document
344      */
345     private class StopAction extends AbstractAction 
346 	{
347         public StopAction() 
348 		{
349             putValue(Action.NAME, XNap.tr("Stop"));
350             putValue(Action.SHORT_DESCRIPTION,
351 					 XNap.tr("Stop loading the document"));
352 			putValue(IconHelper.XNAP_ICON, "stop.png");
353 			
354 			// FIX: currently not supported
355 			setEnabled(false);
356         }
357 
358         public void actionPerformed(ActionEvent event) 
359 		{
360 		}
361     } 
362 
363 }