Fix #680.
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.news / src / net / sourceforge / phpeclipse / news / Item.java
1 package net.sourceforge.phpeclipse.news;
2
3 import java.text.DateFormat;
4 import java.text.SimpleDateFormat;
5 import java.util.Calendar;
6 import java.util.Date;
7 import java.util.GregorianCalendar;
8 import java.util.Locale;
9
10 import org.eclipse.swt.SWT;
11 import org.eclipse.swt.widgets.Table;
12 import org.eclipse.swt.widgets.TableItem;
13 import org.w3c.dom.Element;
14 import org.w3c.dom.Node;
15 import org.w3c.dom.NodeList;
16 import org.w3c.dom.Text;
17
18 /**
19  * @author jnegre - http://www.jnegre.org/
20  *
21  * (c)Copyright 2002 J�r�me N�gre
22  * 
23  */
24 public class Item {
25
26     protected static DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT);
27     protected static SimpleDateFormat pubDateParser = new SimpleDateFormat("EEE, d MMM yy hh:mm:ss z", new Locale("en","US"));
28
29     protected Channel channel;
30
31     protected String title;
32     protected String link;
33     protected String description;
34     protected String author;
35     protected String guid;
36     protected boolean isPermaLink = true;
37     protected String date;
38     
39     protected boolean readFlag = false;
40
41     /**
42      * Constructor for Item.
43      */
44     public Item(Channel channel, Element itemElement) {
45         this.channel = channel;
46         this.title = readValue("title", itemElement, 0);
47         this.link = readValue("link", itemElement, 0);
48         
49         String simpleDescription = readValue("description", itemElement, 0);
50         String contentEncoded = readValue("content:encoded", itemElement, 0);
51         this.description = contentEncoded!=null?contentEncoded:simpleDescription;
52         
53         this.author = readValue("author", itemElement, 0);
54         this.guid = readValue("guid", itemElement, 1);
55         String pubDate = readValue("pubDate", itemElement, 0);
56         String dcDate = readValue("dc:date", itemElement, 0);
57             
58         try {
59             Date theDate;
60             if(pubDate != null) {
61                 theDate = pubDateParser.parse(pubDate);
62             } else if(dcDate != null) {
63                 theDate = decodeDCDate(dcDate);
64             } else {
65                 theDate = new Date();
66             }
67             this.date = dateFormat.format(theDate);
68         } catch(Exception e) {
69             if(pubDate != null) {
70                 this.date = pubDate;
71             } else if(dcDate != null) {
72                 this.date = dcDate;
73             } else {
74                 this.date = e.toString();
75             }
76             Plugin.logInfo("Unable to parse date",e);
77         }
78     }
79
80     protected String readValue(String elementName, Element parent, int type) {
81         Element element = (Element)parent.getElementsByTagName(elementName).item(0);
82         if(element != null) {
83
84             switch(type) {
85                 case 1:
86                     if(element.hasAttribute("isPermaLink") && element.getAttribute("isPermaLink").equals("false")) {
87                         this.isPermaLink = false;
88                     }
89             }
90     
91             NodeList children = element.getChildNodes();
92             StringBuffer buffer = new StringBuffer();
93             for(int i=0; i<children.getLength(); i++) {
94                 Node node = children.item(i);
95                 if(node.getNodeType()==Node.TEXT_NODE || node.getNodeType()==Node.CDATA_SECTION_NODE) {
96                         buffer.append(((Text)node).getData());
97                 }
98             }
99             return buffer.toString().trim();
100         } else {
101             return null;
102         }
103     }
104
105     public String getUsableTitle() {
106         if(title != null) {
107             return title;
108         } else if (description != null) {
109             return description;
110         } else {
111             return "!! No title in feed !!";
112         }
113     }
114
115     public String getUsableLink() {
116         if(link != null) {
117             return link;
118         } else if (guid != null && isPermaLink) {
119             return guid;
120         } else {
121             return "about:blank";
122         }
123     }
124
125     public boolean isBanned() {
126         return Plugin.getDefault().isBannedTitle(title);
127     }
128
129     public TableItem toTableItem(Table table) {
130         TableItem tableItem = new TableItem(table, SWT.NONE);
131         fillTableItem(tableItem);
132         return tableItem;
133     }
134
135     public void fillTableItem(TableItem tableItem) {
136         tableItem.setText(new String[] {date,readFlag?"":"*",getUsableTitle()});
137         tableItem.setData(this);
138     }
139
140     /**
141      * Sets the readFlag and notifies the listeners
142      * that the status changed.
143      * @param readFlag The readFlag to set
144      */
145     public void setReadFlag(boolean readFlag) {
146         if(readFlag != this.readFlag) {
147             this.readFlag = readFlag;
148             channel.computeUnRead();
149         }
150     }
151
152     /**
153      * @see java.lang.Object#equals(Object)
154      */
155     public boolean equals(Object obj) {
156         return (obj instanceof Item)
157                 && ((Item)obj).getUID().equals(this.getUID());
158     }
159
160     protected static Date decodeDCDate(String string) throws Exception {
161         GregorianCalendar calendar = new GregorianCalendar(readInt(string,0,4),0,1,0,0,0);
162         calendar.set(Calendar.MILLISECOND,0);
163         calendar.set(Calendar.DST_OFFSET,0);
164         if(checkChar(string,4,'-')) {
165             calendar.set(Calendar.MONTH,readInt(string,5,2)-1);
166             if(checkChar(string,7,'-')) {
167                 calendar.set(Calendar.DATE,readInt(string,8,2));
168                 if(checkChar(string,10,'T')) {
169                     calendar.set(Calendar.HOUR_OF_DAY,readInt(string,11,2));
170                     calendar.set(Calendar.MINUTE,readInt(string,14,2));
171                     int length = string.length();
172                     int position = 16;
173                     
174                     //les secondes + millisecondes
175                     if(checkChar(string,16,':')) {
176                         calendar.set(Calendar.SECOND,readInt(string,17,2));
177                         position = 19;
178                         if(checkChar(string,position,'.')) {
179                             position += 1;
180                             StringBuffer millisecondBuffer = new StringBuffer("0.");
181                             while(position<length && Character.isDigit(string.charAt(position))) {
182                                 millisecondBuffer.append(string.charAt(position));
183                                 position += 1;
184                             }
185                             calendar.set(Calendar.MILLISECOND,(int)(Double.parseDouble(millisecondBuffer.toString())*1000));
186                         }
187
188                     }
189
190
191                     //TZD
192                     if(string.charAt(position) == 'Z') {
193                         calendar.set(Calendar.ZONE_OFFSET,0);
194                         if(length != position +1) {
195                             //trop de caract�res
196                             throw new Exception("Invalid format of dc:date (extra tokens)");
197                         }
198                     } else if(string.charAt(position) == '+' || string.charAt(position) == '-') {
199                         int sign = 0;
200                         sign = string.charAt(position) == '+'?1:-1;
201                         int hour = readInt(string,position+1,2);
202                         int minute = readInt(string,position+4,2);
203                         calendar.set(Calendar.ZONE_OFFSET,sign*(hour*60*60*1000+minute*60*1000));
204                         if(length != position +6) {
205                             //trop de caract�res
206                             throw new Exception("Invalid format of dc:date (extra tokens)");
207                         }
208                     } else {
209                         throw new Exception("Invalid format of dc:date (invalid TZD)");
210                     }
211                     
212                 }
213             }
214         }
215         return calendar.getTime();
216     }
217
218     private static int readInt(String buffer, int position, int length) {
219         int result = Integer.parseInt(buffer.substring(position,position+length));
220         return result;
221     }
222     
223     private static boolean checkChar(String buffer, int position, char expectedChar) {
224         if(buffer.length() > position && buffer.charAt(position) == expectedChar) {
225             return true;
226         } else {
227             return false;
228         }
229     }
230
231     /**
232      * @return the description of this item
233      */
234     public String getDescription() {
235         return description;
236     }
237     /**
238      * @return the author of this item
239      */
240     public String getAuthor() {
241         return author;
242     }
243
244     /**
245      * Returns the date.
246      * @return String
247      */
248     public String getDate() {
249         return date;
250     }
251
252     /**
253      * Returns the readFlag.
254      * @return boolean
255      */
256     public boolean isReadFlag() {
257         return readFlag;
258     }
259
260     /**
261      * Returns the channel.
262      * @return Channel
263      */
264     public Channel getChannel() {
265         return channel;
266     }
267
268     /**
269      * Returns a unique ID used to remember which
270      * items were read in the ChannelStore
271      * @return
272      */
273     public String getUID() {
274         return getUsableLink() + ") ~ (" + getUsableTitle();
275     }
276     
277 }