RSS news reader; initially copied from "all the news"
authorjsurfer <jsurfer>
Sat, 9 Oct 2004 14:03:31 +0000 (14:03 +0000)
committerjsurfer <jsurfer>
Sat, 9 Oct 2004 14:03:31 +0000 (14:03 +0000)
38 files changed:
archive/net.sourceforge.phpeclipse.news/.classpath [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/.cvsignore [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/.project [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/.settings/org.eclipse.core.resources.prefs [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/about.html [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/build.properties [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/default_feeds.properties [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/clear.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/external_browser.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/headlines.png [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/led_dark_green.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/led_light_green.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/led_red.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/led_yellow.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/leds.xcf [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/link.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/news.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/icons/refresh.gif [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/lib/xmlrpc-1.2-b1.jar [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/plugin.xml [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Channel.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/IconManager.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Item.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Messages.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Perspective.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Plugin.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/RssListener.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/UpdateThread.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/messages.properties [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/BanListEditor.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/ChannelStore.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/ListEncoder.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/PreferencePage.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/SiteListEditor.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/search/SearchDialog.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/ExplorerView.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/HeadlineView.java [new file with mode: 0644]
archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/NewsTreeViewerProvider.java [new file with mode: 0644]

diff --git a/archive/net.sourceforge.phpeclipse.news/.classpath b/archive/net.sourceforge.phpeclipse.news/.classpath
new file mode 100644 (file)
index 0000000..0845836
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src/"/>
+       <classpathentry kind="lib" path="lib/xmlrpc-1.2-b1.jar"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/archive/net.sourceforge.phpeclipse.news/.cvsignore b/archive/net.sourceforge.phpeclipse.news/.cvsignore
new file mode 100644 (file)
index 0000000..c865ab9
--- /dev/null
@@ -0,0 +1,7 @@
+build.xml
+org.jnegre.allthenews_*.*.*.jar
+bin
+allthenews.jar
+allthenewssrc.zip
+patch_*.txt
+todo.txt
diff --git a/archive/net.sourceforge.phpeclipse.news/.project b/archive/net.sourceforge.phpeclipse.news/.project
new file mode 100644 (file)
index 0000000..aecfda3
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>net.sourceforge.phpeclipse.news</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.team.cvs.core.cvsnature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.pde.PluginNature</nature>
+       </natures>
+</projectDescription>
diff --git a/archive/net.sourceforge.phpeclipse.news/.settings/org.eclipse.core.resources.prefs b/archive/net.sourceforge.phpeclipse.news/.settings/org.eclipse.core.resources.prefs
new file mode 100644 (file)
index 0000000..4e795ad
--- /dev/null
@@ -0,0 +1,3 @@
+#Tue Oct 05 18:40:07 CEST 2004\r
+eclipse.preferences.version=1\r
+encoding//src/net/sourceforge/phpeclipse/news/messages.properties=8859_1\r
diff --git a/archive/net.sourceforge.phpeclipse.news/about.html b/archive/net.sourceforge.phpeclipse.news/about.html
new file mode 100644 (file)
index 0000000..d16f631
--- /dev/null
@@ -0,0 +1,238 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+       <head>
+               <title>Common Public License - v 1.0</title>
+               <meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+       </head>
+<body vLink=#800000 bgColor=#ffffff>
+<p align=center><b>Common Public License - v 1.0</b> 
+<p><b></b><font size=3></font>
+<p><font size=3></font><font size=2>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER 
+THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR 
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS 
+AGREEMENT.</font> 
+<p><font size=2></font>
+<p><font size=2><b>1. DEFINITIONS</b></font> 
+<p><font size=2>"Contribution" means:</font> 
+
+<ul><font size=2>a) in the case of the initial Contributor, the initial code 
+  and documentation distributed under this Agreement, and<br clear=left>b) in 
+  the case of each subsequent Contributor:</font></ul>
+<ul><font size=2>i) changes to the Program, and</font></ul>
+<ul><font size=2>ii) additions to the Program;</font></ul>
+<ul><font size=2>where such changes and/or additions to the Program originate 
+  from and are distributed by that particular Contributor. </font><font size=2>A 
+  Contribution 'originates' from a Contributor if it was added to the Program by 
+  such Contributor itself or anyone acting on such Contributor's behalf. 
+  </font><font size=2>Contributions do not include additions to the Program 
+  which: (i) are separate modules of software distributed in conjunction with 
+  the Program under their own license agreement, and (ii) are not derivative 
+  works of the Program. </font></ul>
+<p><font size=2></font>
+<p><font size=2>"Contributor" means any person or entity that distributes the 
+Program.</font> 
+<p><font size=2></font><font size=2></font>
+<p><font size=2>"Licensed Patents " mean patent claims licensable by a 
+Contributor which are necessarily infringed by the use or sale of its 
+Contribution alone or when combined with the Program. </font>
+
+<p><font size=2></font><font size=2></font>
+<p><font size=2></font><font size=2>"Program" means the Contributions 
+distributed in accordance with this Agreement.</font> 
+<p><font size=2></font>
+<p><font size=2>"Recipient" means anyone who receives the Program under this 
+Agreement, including all Contributors.</font> 
+<p><font size=2><b></b></font>
+<p><font size=2><b>2. GRANT OF RIGHTS</b></font> 
+<ul><font size=2></font><font size=2>a) </font><font size=2>Subject to the 
+  terms of this Agreement, each Contributor hereby grants</font><font size=2> 
+  Recipient a non-exclusive, worldwide, royalty-free copyright license 
+  to</font><font color=#ff0000 size=2> </font><font size=2>reproduce, prepare 
+  derivative works of, publicly display, publicly perform, distribute and 
+  sublicense the Contribution of such Contributor, if any, and such derivative 
+  works, in source code and object code form.</font></ul>
+<ul><font size=2></font></ul>
+
+<ul><font size=2></font><font size=2>b) Subject to the terms of this 
+  Agreement, each Contributor hereby grants </font><font size=2>Recipient a 
+  non-exclusive, worldwide,</font><font color=#008000 size=2> </font><font 
+  size=2>royalty-free patent license under Licensed Patents to make, use, sell, 
+  offer to sell, import and otherwise transfer the Contribution of such 
+  Contributor, if any, in source code and object code form. This patent license 
+  shall apply to the combination of the Contribution and the Program if, at the 
+  time the Contribution is added by the Contributor, such addition of the 
+  Contribution causes such combination to be covered by the Licensed Patents. 
+  The patent license shall not apply to any other combinations which include the 
+  Contribution. No hardware per se is licensed hereunder. </font></ul>
+<ul><font size=2></font></ul>
+<ul><font size=2>c) Recipient understands that although each Contributor 
+  grants the licenses to its Contributions set forth herein, no assurances are 
+  provided by any Contributor that the Program does not infringe the patent or 
+  other intellectual property rights of any other entity. Each Contributor 
+  disclaims any liability to Recipient for claims brought by any other entity 
+  based on infringement of intellectual property rights or otherwise. As a 
+  condition to exercising the rights and licenses granted hereunder, each 
+  Recipient hereby assumes sole responsibility to secure any other intellectual 
+  property rights needed, if any. For example, if a third party patent license 
+  is required to allow Recipient to distribute the Program, it is Recipient's 
+  responsibility to acquire that license before distributing the 
+Program.</font></ul>
+<ul><font size=2></font></ul>
+<ul><font size=2>d) Each Contributor represents that to its knowledge it has 
+  sufficient copyright rights in its Contribution, if any, to grant the 
+  copyright license set forth in this Agreement. </font></ul>
+<ul><font size=2></font></ul>
+<p><font size=2><b>3. REQUIREMENTS</b></font> 
+<p><font size=2><b></b>A Contributor may choose to distribute the Program in 
+object code form under its own license agreement, provided that:</font> 
+<ul><font size=2>a) it complies with the terms and conditions of this 
+  Agreement; and</font></ul>
+
+<ul><font size=2>b) its license agreement:</font></ul>
+<ul><font size=2>i) effectively disclaims</font><font face="Times New Roman" 
+  size=2> on behalf of all Contributors all warranties and conditions, express 
+  and implied, including warranties or conditions of title and non-infringement, 
+  and implied warranties or conditions of merchantability and fitness for a 
+  particular purpose; </font></ul>
+<ul><font face="Times New Roman" size=2>ii) effectively excludes on behalf of 
+  all Contributors all liability for damages, including direct, indirect, 
+  special, incidental and consequential damages, such as lost profits; 
+</font></ul>
+<ul><font face="Times New Roman" size=2>iii)</font><font size=2> states that 
+  any provisions which differ from this Agreement are offered by that 
+  Contributor alone and not by any other party; and</font></ul>
+<ul><font size=2>iv) states that source code for the Program is available from 
+  such Contributor, and informs licensees how to obtain it in a reasonable 
+  manner on or through a medium customarily used for software 
+  exchange.</font><font color=#0000ff size=2> </font><font color=#ff0000 
+  size=2></font></ul>
+<ul><font color=#ff0000 size=2></font><font size=2></font></ul>
+<p><font size=2>When the Program is made available in source code form:</font> 
+
+<ul><font size=2>a) it must be made available under this Agreement; and 
+</font></ul>
+<ul><font size=2>b) a copy of this Agreement must be included with each copy 
+  of the Program. </font></ul>
+<p><font size=2></font><font color=#0000ff size=2><strike></strike></font>
+<p><font color=#0000ff size=2><strike></strike></font><font size=2>Contributors 
+may not remove or alter any copyright notices contained within the Program. 
+</font>
+<p><font size=2></font>
+<p><font size=2>Each Contributor must identify itself as the originator of its 
+Contribution, if any, in a manner that reasonably allows subsequent Recipients 
+to identify the originator of the Contribution. </font>
+<p><font size=2></font>
+<p><font size=2><b>4. COMMERCIAL DISTRIBUTION</b></font> 
+<p><font size=2>Commercial distributors of software may accept certain 
+responsibilities with respect to end users, business partners and the like. 
+While this license is intended to facilitate the commercial use of the Program, 
+the Contributor who includes the Program in a commercial product offering should 
+do so in a manner which does not create potential liability for other 
+Contributors. Therefore, if a Contributor includes the Program in a commercial 
+product offering, such Contributor ("Commercial Contributor") hereby agrees to 
+defend and indemnify every other Contributor ("Indemnified Contributor") against 
+any losses, damages and costs (collectively "Losses") arising from claims, 
+lawsuits and other legal actions brought by a third party against the 
+Indemnified Contributor to the extent caused by the acts or omissions of such 
+Commercial Contributor in connection with its distribution of the Program in a 
+commercial product offering. The obligations in this section do not apply to any 
+claims or Losses relating to any actual or alleged intellectual property 
+infringement. In order to qualify, an Indemnified Contributor must: a) promptly 
+notify the Commercial Contributor in writing of such claim, and b) allow the 
+Commercial Contributor to control, and cooperate with the Commercial Contributor 
+in, the defense and any related settlement negotiations. The Indemnified 
+Contributor may participate in any such claim at its own expense.</font> 
+<p><font size=2></font>
+<p><font size=2>For example, a Contributor might include the Program in a 
+commercial product offering, Product X. That Contributor is then a Commercial 
+Contributor. If that Commercial Contributor then makes performance claims, or 
+offers warranties related to Product X, those performance claims and warranties 
+are such Commercial Contributor's responsibility alone. Under this section, the 
+Commercial Contributor would have to defend claims against the other 
+Contributors related to those performance claims and warranties, and if a court 
+requires any other Contributor to pay any damages as a result, the Commercial 
+Contributor must pay those damages.</font> 
+
+<p><font size=2></font><font color=#0000ff size=2></font>
+<p><font color=#0000ff size=2></font><font size=2><b>5. NO WARRANTY</b></font> 
+<p><font size=2>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS 
+PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
+EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 
+CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 
+PARTICULAR PURPOSE. Each Recipient is</font><font size=2> solely responsible for 
+determining the appropriateness of using and distributing </font><font 
+size=2>the Program</font><font size=2> and assumes all risks associated with its 
+exercise of rights under this Agreement</font><font size=2>, including but not 
+limited to the risks and costs of program errors, compliance with applicable 
+laws, damage to or loss of data, </font><font size=2>programs or equipment, and 
+unavailability or interruption of operations</font><font size=2>. </font><font 
+size=2></font>
+<p><font size=2></font>
+<p><font size=2></font><font size=2><b>6. DISCLAIMER OF LIABILITY</b></font> 
+<p><font size=2></font><font size=2>EXCEPT AS EXPRESSLY SET FORTH IN THIS 
+AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR 
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+
+</font><font face="Times New Roman" size=2>(INCLUDING WITHOUT LIMITATION LOST 
+PROFITS),</font><font size=2> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR 
+THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 
+OF SUCH DAMAGES.</font> 
+<p><font size=2></font><font size=2></font>
+<p><font size=2><b>7. GENERAL</b></font> 
+<p><font size=2></font><font size=2>If any provision of this Agreement is 
+invalid or unenforceable under applicable law, it shall not affect the validity 
+or enforceability of the remainder of the terms of this Agreement, and without 
+further action by the parties hereto, such provision shall be reformed to the 
+minimum extent necessary to make such provision valid and enforceable.</font> 
+<p><font size=2></font>
+<p><font size=2>If Recipient institutes patent litigation against a Contributor 
+with respect to a patent applicable to software (including a cross-claim or 
+counterclaim in a lawsuit), then any patent licenses granted by that Contributor 
+to such Recipient under this Agreement shall terminate as of the date such 
+litigation is filed. In addition, if Recipient institutes patent litigation 
+against any entity (including a cross-claim or counterclaim in a lawsuit) 
+alleging that the Program itself (excluding combinations of the Program with 
+other software or hardware) infringes such Recipient's patent(s), then such 
+Recipient's rights granted under Section 2(b) shall terminate as of the date 
+such litigation is filed. </font><font size=2></font>
+<p><font size=2></font>
+<p><font size=2>All Recipient's rights under this Agreement shall terminate if 
+it fails to comply with any of the material terms or conditions of this 
+Agreement and does not cure such failure in a reasonable period of time after 
+becoming aware of such noncompliance. If all Recipient's rights under this 
+Agreement terminate, Recipient agrees to cease use and distribution of the 
+Program as soon as reasonably practicable. However, Recipient's obligations 
+under this Agreement and any licenses granted by Recipient relating to the 
+Program shall continue and survive. </font><font size=2></font>
+<p><font size=2></font>
+<p><font size=2></font><font face="Times New Roman" size=2>Everyone is permitted 
+to copy and distribute copies of this Agreement, but in order to avoid 
+inconsistency the Agreement is copyrighted and may only be modified in the 
+following manner. The Agreement Steward reserves the right to </font><font 
+size=2>publish new versions (including revisions) of this Agreement from time to 
+
+</font><font face="Times New Roman" size=2>time. No one other than the Agreement 
+Steward has the right to modify this Agreement. IBM is the initial Agreement 
+Steward. IBM may assign the responsibility to serve as the Agreement Steward to 
+a suitable separate entity. </font><font size=2>Each new version of the 
+Agreement will be given a distinguishing version number. The Program (including 
+Contributions) may always be distributed subject to the version of the Agreement 
+under which it was received. In addition, after a new version of the Agreement 
+is published, Contributor may elect to distribute the Program (including its 
+Contributions) under the new </font><font face="Times New Roman" size=2>version. 
+</font><font size=2>Except as expressly stated in Sections 2(a) and 2(b) above, 
+Recipient receives no rights or licenses to the intellectual property of any 
+Contributor under this Agreement, whether expressly, </font><font size=2>by 
+implication, estoppel or otherwise</font><font size=2>.</font><font size=2> All 
+rights in the Program not expressly granted under this Agreement are 
+reserved.</font> 
+<p><font size=2></font>
+<p><font size=2>This Agreement is governed by the laws of the State of New York 
+and the intellectual property laws of the United States of America. No party to 
+this Agreement will bring a legal action under this Agreement more than one year 
+after the cause of action arose. Each party waives its rights to a jury trial in 
+any resulting litigation.</font> 
+<p><font size=2></font><font size=2></font>
+<p><font size=2></font></p></body></html>
\ No newline at end of file
diff --git a/archive/net.sourceforge.phpeclipse.news/build.properties b/archive/net.sourceforge.phpeclipse.news/build.properties
new file mode 100644 (file)
index 0000000..6262ab8
--- /dev/null
@@ -0,0 +1,11 @@
+bin.includes = icons/,\
+               plugin.xml,\
+               allthenewssrc.zip,\
+               about.html,\
+               lib/,\
+               allthenews.jar,\
+               default_feeds.properties,\
+               changes.txt
+src.includes = src/
+source.allthenews.jar = src/
+bin.excludes = icons/*.xcf
diff --git a/archive/net.sourceforge.phpeclipse.news/default_feeds.properties b/archive/net.sourceforge.phpeclipse.news/default_feeds.properties
new file mode 100644 (file)
index 0000000..474b96a
--- /dev/null
@@ -0,0 +1,16 @@
+#This is the list of default feeds.
+#The format is url=title
+#Beware that characters such as : or = must be escaped in urls
+
+http\://www.phpeclipse.de/tiki-forums_rss.php=PHPeclipse - User Forums
+http\://www.phpeclipse.de/tiki-forum_rss_de.php=PHPeclipse - deutsches Benutzer Forum
+http\://www.phpeclipse.de/tiki-wiki_rss.php=PHPeclipse - Wiki
+http\://www.eclipseproject.de/backend.php=EclipseProject.de - News
+http\://www.eclipseproject.de/backendforum1.php=EclipseProject.de - Eclipse als IDE nutzen
+http\://www.eclipseproject.de/backendforum4.php=EclipseProject.de - Eclipse Plugins benutzen
+http\://www.eclipseproject.de/backendforum2.php=EclipseProject.de - Eclipse Plugins entwickeln
+http\://www.eclipseproject.de/backendforum8.php=EclipseProject.de - SWT/JFace/RCP
+http\://www.php.net/news.rss=php.net News
+http\://www.jsurfer.org/backend.php=JSurfer.org
+http\://today.java.net/pub/q/java_today_rss?x-ver\=1.0=Java.net
+http\://eclipse-plugins.2y.net/eclipse/plugins_backend.jsp?what\=newandupdated=EclipsePlugins
\ No newline at end of file
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/clear.gif b/archive/net.sourceforge.phpeclipse.news/icons/clear.gif
new file mode 100644 (file)
index 0000000..2558326
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/clear.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/external_browser.gif b/archive/net.sourceforge.phpeclipse.news/icons/external_browser.gif
new file mode 100644 (file)
index 0000000..220c134
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/external_browser.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/headlines.png b/archive/net.sourceforge.phpeclipse.news/icons/headlines.png
new file mode 100644 (file)
index 0000000..9b38600
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/headlines.png differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/led_dark_green.gif b/archive/net.sourceforge.phpeclipse.news/icons/led_dark_green.gif
new file mode 100644 (file)
index 0000000..5f0ca90
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/led_dark_green.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/led_light_green.gif b/archive/net.sourceforge.phpeclipse.news/icons/led_light_green.gif
new file mode 100644 (file)
index 0000000..a755dfd
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/led_light_green.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/led_red.gif b/archive/net.sourceforge.phpeclipse.news/icons/led_red.gif
new file mode 100644 (file)
index 0000000..7941b10
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/led_red.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/led_yellow.gif b/archive/net.sourceforge.phpeclipse.news/icons/led_yellow.gif
new file mode 100644 (file)
index 0000000..eafb8d9
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/led_yellow.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/leds.xcf b/archive/net.sourceforge.phpeclipse.news/icons/leds.xcf
new file mode 100644 (file)
index 0000000..8aaa3ee
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/leds.xcf differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/link.gif b/archive/net.sourceforge.phpeclipse.news/icons/link.gif
new file mode 100644 (file)
index 0000000..2b78f04
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/link.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/news.gif b/archive/net.sourceforge.phpeclipse.news/icons/news.gif
new file mode 100644 (file)
index 0000000..3d2b8e5
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/news.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/icons/refresh.gif b/archive/net.sourceforge.phpeclipse.news/icons/refresh.gif
new file mode 100644 (file)
index 0000000..9f6c9b1
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/icons/refresh.gif differ
diff --git a/archive/net.sourceforge.phpeclipse.news/lib/xmlrpc-1.2-b1.jar b/archive/net.sourceforge.phpeclipse.news/lib/xmlrpc-1.2-b1.jar
new file mode 100644 (file)
index 0000000..cc67714
Binary files /dev/null and b/archive/net.sourceforge.phpeclipse.news/lib/xmlrpc-1.2-b1.jar differ
diff --git a/archive/net.sourceforge.phpeclipse.news/plugin.xml b/archive/net.sourceforge.phpeclipse.news/plugin.xml
new file mode 100644 (file)
index 0000000..b503f7f
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin
+   id="net.sourceforge.phpeclipse.news"
+   name="PHPeclipse RSS News"
+   version="3.0.3"
+   provider-name="phpeclipse.de"
+   class="net.sourceforge.phpeclipse.news.Plugin">
+
+   <runtime>
+      <library name="rssnews.jar"/>
+      <library name="lib/xmlrpc-1.2-b1.jar"/>
+   </runtime>
+   <requires>
+      <import plugin="org.eclipse.core.runtime.compatibility"/>
+      <import plugin="org.eclipse.ui"/>
+      <import plugin="net.sourceforge.phpeclipse.webbrowser"/>
+   </requires>
+
+
+   <extension
+         point="org.eclipse.ui.views">
+      <category
+            name="PHPeclipse RSS News"
+            id="net.sourceforge.phpeclipse.news.viewcategory">
+      </category>
+      <view
+            name="News Explorer"
+            icon="icons\news.gif"
+            category="net.sourceforge.phpeclipse.news.viewcategory"
+            class="net.sourceforge.phpeclipse.news.view.ExplorerView"
+            id="net.sourceforge.phpeclipse.news.view.explorer">
+      </view>
+      <view
+            name="Headlines"
+            icon="icons\headlines.png"
+            category="net.sourceforge.phpeclipse.news.viewcategory"
+            class="net.sourceforge.phpeclipse.news.view.HeadlineView"
+            id="net.sourceforge.phpeclipse.news.view.headline">
+      </view>
+   </extension>
+   <extension
+         point="org.eclipse.ui.perspectives">
+      <perspective
+            name="PHPeclipse RSS News"
+            icon="icons\news.gif"
+            class="net.sourceforge.phpeclipse.news.Perspective"
+            id="net.sourceforge.phpeclipse.news.perspective">
+      </perspective>
+   </extension>
+   <extension
+         point="org.eclipse.ui.preferencePages">
+      <page
+            name="PHPeclipse RSS News"
+            category="net.sourceforge.phpeclipse.preference.PHPEclipsePreferencePage"
+            class="net.sourceforge.phpeclipse.news.pref.PreferencePage"
+            id="net.sourceforge.phpeclipse.news.preference">
+      </page>
+   </extension>
+
+</plugin>
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Channel.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Channel.java
new file mode 100644 (file)
index 0000000..8b22c55
--- /dev/null
@@ -0,0 +1,194 @@
+package net.sourceforge.phpeclipse.news;
+
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.eclipse.core.runtime.Preferences;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * @author jnegre - http://www.jnegre.org/
+ *
+ * (c)Copyright 2002 Jérôme Nègre
+ * 
+ */
+public class Channel {
+
+    private final String url;
+    private final String title;
+
+    private boolean refreshing = false;
+    private String errorMessage = null;
+    private boolean unread = false;
+    
+    private ArrayList items = new ArrayList();
+    private HashSet readUids = null;
+
+    /**
+     * Constructor for Channel.
+     */
+    public Channel(String title, String url) {
+       this(title, url, null);
+    }
+
+    public Channel(String title, String url, HashSet readUids) {
+        this.title = title;
+        this.url = url;
+        this.readUids = readUids;
+    }
+
+
+    public void update() {
+        update(Plugin.getDefault().getPluginPreferences());
+    }
+
+
+    public void update(Preferences prefs) {
+            ArrayList newItems = new ArrayList();
+            String newErrorMessage = null;
+        try {
+            
+            URLConnection conn = new URL(url).openConnection();
+            conn.setRequestProperty("User-Agent", Plugin.userAgent);
+            if(prefs.getBoolean(Plugin.FORCE_CACHE_PREFERENCE)) {
+               conn.setRequestProperty("Pragma", "no-cache");
+                       conn.setRequestProperty("Cache-Control", "no-cache");
+            }
+            InputStream stream = conn.getInputStream();
+            
+            /* workaround a bug of crimson (it seems to ignore the encoding
+             * if it does not get it the first time it reads bytes from
+             * the stream. We use a PushbackInputStream to be sure that the
+             * encoding declaration is in the buffer)
+             */
+            PushbackInputStream pbStream = new PushbackInputStream(stream,64);
+            byte[] buffer = new byte[64];
+            int pos = 0;
+            while(pos != 64) {
+               pos += pbStream.read(buffer, pos, 64-pos);
+            }
+            pbStream.unread(buffer);
+            //end workaround
+            
+            DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+            InputSource inputSource = new InputSource(pbStream);
+            Document doc = parser.parse(inputSource);
+            pbStream.close();
+            NodeList itemNodes = doc.getElementsByTagName("item");
+            for (int i = 0; i < itemNodes.getLength(); i++) {
+                Item aNewItem = new Item(this, (Element) itemNodes.item(i));
+                if(aNewItem.isBanned()) continue;
+                if(readUids!=null && readUids.remove(aNewItem.getUID())) {
+                       aNewItem.setReadFlag(true);
+                }
+                int indexOld = items.indexOf(aNewItem);
+                if(indexOld != -1) {
+                    newItems.add(items.get(indexOld));
+                } else {
+                    newItems.add(aNewItem);
+                }
+                
+            }
+            this.readUids = null;
+        } catch(UnknownHostException e) {
+          // no connection to internet
+        } catch(Exception e) {
+            newErrorMessage = e.toString();
+            Plugin.logInfo("Error in channel update",e);
+        }
+        
+        synchronized(this) {
+            this.errorMessage = newErrorMessage;
+            if(newErrorMessage == null) {
+                this.items = newItems;
+                computeUnRead();
+            }
+        }
+    }
+
+    /**
+     * Returns the url.
+     * @return String
+     */
+    public String getUrl() {
+        return url;
+    }
+
+    /**
+     * Returns the errorMessage.
+     * @return String
+     */
+    public synchronized String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * Returns the items.
+     * @return ArrayList
+     */
+    public synchronized ArrayList getItems() {
+        return new ArrayList(items);
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return "Channel at "+url;
+    }
+
+    /**
+     * Returns the title.
+     * @return String
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * Returns the refreshing.
+     * @return boolean
+     */
+    public boolean isRefreshing() {
+        return refreshing;
+    }
+
+    /**
+     * Sets the refreshing.
+     * @param refreshing The refreshing to set
+     */
+    public void setRefreshing(boolean refreshing) {
+        this.refreshing = refreshing;
+    }
+
+    /**
+     * Returns the unread.
+     * @return boolean
+     */
+    public boolean isUnread() {
+        return unread;
+    }
+
+    public synchronized void computeUnRead() {
+        this.unread = false;
+        for (int i = 0; i < items.size(); i++) {
+            this.unread = this.unread || !((Item)items.get(i)).isReadFlag();
+        }
+    }
+    
+    public String getUID() {
+       return "CHA" + url;
+    }
+
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/IconManager.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/IconManager.java
new file mode 100644 (file)
index 0000000..2294108
--- /dev/null
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2004 Jérôme Nègre.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.jnegre.org/cpl1_0.html
+ * 
+ * Contributors:
+ *     Jérôme Nègre - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Created on 12 juin 2004
+ */
+package net.sourceforge.phpeclipse.news;
+
+import java.net.URL;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * @author Jérôme Nègre
+ */
+public class IconManager {
+       //the root folder containing the icons
+       private static final String ICON_FOLDER = "icons/";
+       
+       //real file locations
+       private static final String LOC_LED_DARK_GREEN = "led_dark_green.gif";
+       private static final String LOC_LED_LIGHT_GREEN = "led_light_green.gif";
+       private static final String LOC_LED_RED = "led_red.gif";
+       private static final String LOC_LED_YELLOW = "led_yellow.gif";
+       private static final String LOC_LINK = "link.gif";
+       private static final String LOC_REFRESH = "refresh.gif";
+       private static final String LOC_EXTERNAL_BROWSER = "external_browser.gif";
+
+       //list of all icon files to put in the ImageRegistry
+       private static final String[] LOCATIONS = new String[]{
+                       LOC_LED_DARK_GREEN,
+                       LOC_LED_LIGHT_GREEN,
+                       LOC_LED_RED,
+                       LOC_LED_YELLOW,
+                       LOC_LINK,
+                       LOC_REFRESH,
+                       LOC_EXTERNAL_BROWSER
+       };
+
+       //public names
+       public static final String ICON_STATUS_ERROR   = LOC_LED_RED;
+       public static final String ICON_STATUS_UNREAD  = LOC_LED_LIGHT_GREEN;
+       public static final String ICON_STATUS_READ    = LOC_LED_DARK_GREEN;
+       public static final String ICON_STATUS_REFRESH = LOC_LED_YELLOW;
+       
+       public static final String ICON_ACTION_REFRESH = LOC_REFRESH;
+       public static final String ICON_ACTION_LINK = LOC_LINK;
+       public static final String ICON_ACTION_EXTERNAL_BROWSER = LOC_EXTERNAL_BROWSER;
+       
+       /**
+        * Populates an image registry with all the locations
+        * @param registry
+        */
+       protected static void populateImageRegistry(ImageRegistry registry) {
+               for(int i=0; i<LOCATIONS.length; i++) {
+                       registry.put(LOCATIONS[i],createImageDescriptor(LOCATIONS[i]));
+               }
+       }
+
+       /**
+        * Creates the ImageDescriptor of a file given its path in the
+        * ICON_FOLDER.
+        * @param relativePath
+        * @return the ImageDescriptor
+        */
+    private static ImageDescriptor createImageDescriptor(String relativePath) {
+               try {
+                       URL url = new URL(Plugin.getDefault().getDescriptor().getInstallURL(),
+                                       ICON_FOLDER + relativePath);
+                       return ImageDescriptor.createFromURL(url);
+               } catch (java.net.MalformedURLException e) {
+                       return ImageDescriptor.getMissingImageDescriptor();
+               }
+       }
+       
+       public static ImageDescriptor getImageDescriptor(String key) {
+               return Plugin.getDefault().getImageRegistry().getDescriptor(key);
+       }
+       
+       public static Image getImage(String key) {
+               return Plugin.getDefault().getImageRegistry().get(key);
+       }
+       
+       /**
+        * This class should not be instanciated
+        */
+       private IconManager() {
+               //NOP
+       }
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Item.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Item.java
new file mode 100644 (file)
index 0000000..bce05ec
--- /dev/null
@@ -0,0 +1,273 @@
+package net.sourceforge.phpeclipse.news;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+/**
+ * @author jnegre - http://www.jnegre.org/
+ *
+ * (c)Copyright 2002 Jérôme Nègre
+ * 
+ */
+public class Item {
+
+    protected static DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT);
+    protected static SimpleDateFormat pubDateParser = new SimpleDateFormat("EEE, d MMM yy hh:mm:ss z", new Locale("en","US"));
+
+    protected Channel channel;
+
+    protected String title;
+    protected String link;
+    protected String description;
+    protected String author;
+    protected String guid;
+    protected boolean isPermaLink = true;
+    protected String date;
+    
+    protected boolean readFlag = false;
+
+    /**
+     * Constructor for Item.
+     */
+    public Item(Channel channel, Element itemElement) {
+        this.channel = channel;
+        this.title = readValue("title", itemElement, 0);
+        this.link = readValue("link", itemElement, 0);
+        this.description = readValue("description", itemElement, 0);
+        this.author = readValue("author", itemElement, 0);
+        this.guid = readValue("guid", itemElement, 1);
+        String pubDate = readValue("pubDate", itemElement, 0);
+        String dcDate = readValue("dc:date", itemElement, 0);
+            
+        try {
+            Date theDate;
+            if(pubDate != null) {
+                theDate = pubDateParser.parse(pubDate);
+            } else if(dcDate != null) {
+                theDate = decodeDCDate(dcDate);
+            } else {
+                theDate = new Date();
+            }
+            this.date = dateFormat.format(theDate);
+        } catch(Exception e) {
+            if(pubDate != null) {
+               this.date = pubDate;
+            } else if(dcDate != null) {
+               this.date = dcDate;
+            } else {
+               this.date = e.toString();
+            }
+            Plugin.logInfo("Unable to parse date",e);
+        }
+    }
+
+    protected String readValue(String elementName, Element parent, int type) {
+        Element element = (Element)parent.getElementsByTagName(elementName).item(0);
+        if(element != null) {
+
+            switch(type) {
+                case 1:
+                    if(element.hasAttribute("isPermaLink") && element.getAttribute("isPermaLink").equals("false")) {
+                        this.isPermaLink = false;
+                    }
+            }
+    
+            NodeList children = element.getChildNodes();
+            StringBuffer buffer = new StringBuffer();
+            for(int i=0; i<children.getLength(); i++) {
+               Node node = children.item(i);
+               if(node.getNodeType()==Node.TEXT_NODE || node.getNodeType()==Node.CDATA_SECTION_NODE) {
+                       buffer.append(((Text)node).getData());
+               }
+            }
+            return buffer.toString().trim();
+        } else {
+            return null;
+        }
+    }
+
+    public String getUsableTitle() {
+        if(title != null) {
+            return title;
+        } else if (description != null) {
+            return description;
+        } else {
+            return "!! No title in feed !!";
+        }
+    }
+
+    public String getUsableLink() {
+        if(link != null) {
+            return link;
+        } else if (guid != null && isPermaLink) {
+            return guid;
+        } else {
+            return "about:blank";
+        }
+    }
+
+    public boolean isBanned() {
+        return Plugin.getDefault().isBannedTitle(title);
+    }
+
+    public TableItem toTableItem(Table table) {
+        TableItem tableItem = new TableItem(table, SWT.NONE);
+        fillTableItem(tableItem);
+        return tableItem;
+    }
+
+    public void fillTableItem(TableItem tableItem) {
+        tableItem.setText(new String[] {date,readFlag?"":"*",getUsableTitle()});
+        tableItem.setData(this);
+    }
+
+    /**
+     * Sets the readFlag and notifies the listeners
+     * that the status changed.
+     * @param readFlag The readFlag to set
+     */
+    public void setReadFlag(boolean readFlag) {
+        if(readFlag != this.readFlag) {
+            this.readFlag = readFlag;
+            channel.computeUnRead();
+        }
+    }
+
+    /**
+     * @see java.lang.Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        return (obj instanceof Item)
+                && ((Item)obj).getUID().equals(this.getUID());
+    }
+
+    protected static Date decodeDCDate(String string) throws Exception {
+        GregorianCalendar calendar = new GregorianCalendar(readInt(string,0,4),0,1,0,0,0);
+        calendar.set(Calendar.MILLISECOND,0);
+        calendar.set(Calendar.DST_OFFSET,0);
+        if(checkChar(string,4,'-')) {
+            calendar.set(Calendar.MONTH,readInt(string,5,2)-1);
+            if(checkChar(string,7,'-')) {
+                calendar.set(Calendar.DATE,readInt(string,8,2));
+                if(checkChar(string,10,'T')) {
+                    calendar.set(Calendar.HOUR_OF_DAY,readInt(string,11,2));
+                    calendar.set(Calendar.MINUTE,readInt(string,14,2));
+                    int length = string.length();
+                    int position = 16;
+                    
+                    //les secondes + millisecondes
+                    if(checkChar(string,16,':')) {
+                        calendar.set(Calendar.SECOND,readInt(string,17,2));
+                        position = 19;
+                        if(checkChar(string,position,'.')) {
+                            position += 1;
+                            StringBuffer millisecondBuffer = new StringBuffer("0.");
+                            while(position<length && Character.isDigit(string.charAt(position))) {
+                                millisecondBuffer.append(string.charAt(position));
+                                position += 1;
+                            }
+                            calendar.set(Calendar.MILLISECOND,(int)(Double.parseDouble(millisecondBuffer.toString())*1000));
+                        }
+
+                    }
+
+
+                    //TZD
+                    if(string.charAt(position) == 'Z') {
+                        calendar.set(Calendar.ZONE_OFFSET,0);
+                        if(length != position +1) {
+                            //trop de caractères
+                            throw new Exception("Invalid format of dc:date (extra tokens)");
+                        }
+                    } else if(string.charAt(position) == '+' || string.charAt(position) == '-') {
+                        int sign = 0;
+                        sign = string.charAt(position) == '+'?1:-1;
+                        int hour = readInt(string,position+1,2);
+                        int minute = readInt(string,position+4,2);
+                        calendar.set(Calendar.ZONE_OFFSET,sign*(hour*60*60*1000+minute*60*1000));
+                        if(length != position +6) {
+                            //trop de caractères
+                            throw new Exception("Invalid format of dc:date (extra tokens)");
+                        }
+                    } else {
+                        throw new Exception("Invalid format of dc:date (invalid TZD)");
+                    }
+                    
+                }
+            }
+        }
+        return calendar.getTime();
+    }
+
+    private static int readInt(String buffer, int position, int length) {
+        int result = Integer.parseInt(buffer.substring(position,position+length));
+        return result;
+    }
+    
+    private static boolean checkChar(String buffer, int position, char expectedChar) {
+        if(buffer.length() > position && buffer.charAt(position) == expectedChar) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @return the description of this item
+     */
+    public String getDescription() {
+        return description;
+    }
+    /**
+     * @return the author of this item
+     */
+    public String getAuthor() {
+        return author;
+    }
+
+    /**
+     * Returns the date.
+     * @return String
+     */
+    public String getDate() {
+        return date;
+    }
+
+    /**
+     * Returns the readFlag.
+     * @return boolean
+     */
+    public boolean isReadFlag() {
+        return readFlag;
+    }
+
+    /**
+     * Returns the channel.
+     * @return Channel
+     */
+    public Channel getChannel() {
+        return channel;
+    }
+
+    /**
+     * Returns a unique ID used to remember which
+     * items were read in the ChannelStore
+     * @return
+     */
+    public String getUID() {
+       return getUsableLink() + ") ~ (" + getUsableTitle();
+    }
+    
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Messages.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Messages.java
new file mode 100644 (file)
index 0000000..023315b
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2004 Jérôme Nègre.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.jnegre.org/cpl1_0.html
+ * 
+ * Contributors:
+ *     Jérôme Nègre - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * Created on 27 juil. 2004
+ */
+package net.sourceforge.phpeclipse.news;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * @author Jérôme Nègre
+ */
+public class Messages {
+       private static final String BUNDLE_NAME = "net.sourceforge.phpeclipse.news.messages";//$NON-NLS-1$
+
+       private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+                       .getBundle(BUNDLE_NAME);
+
+       private Messages() {
+       }
+
+       public static String getString(String key) {
+               try {
+                       return RESOURCE_BUNDLE.getString(key);
+               } catch (MissingResourceException e) {
+                       return '!' + key + '!';
+               }
+       }
+}
\ No newline at end of file
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Perspective.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Perspective.java
new file mode 100644 (file)
index 0000000..a037d19
--- /dev/null
@@ -0,0 +1,31 @@
+package net.sourceforge.phpeclipse.news;
+
+import net.sourceforge.phpeclipse.webbrowser.views.BrowserView;
+
+import org.eclipse.ui.IFolderLayout;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+//import org.eclipse.update.internal.ui.UpdatePerspective;
+/**
+ * @author Laurent Fourrier, Jérôme Nègre
+ *  
+ */
+public class Perspective implements IPerspectiveFactory {
+  /**
+   * @see org.eclipse.ui.IPerspectiveFactory#createInitialLayout(IPageLayout)
+   */
+  public void createInitialLayout(IPageLayout layout) {
+    String editorArea = layout.getEditorArea();
+    layout.setEditorAreaVisible(false);
+    //         IFolderLayout bottom = layout.createFolder("bottom",
+    //                         IPageLayout.BOTTOM, 0.70f, editorArea);
+    //         bottom.addView("net.sourceforge.phpeclipse.news.view.headline");
+    IFolderLayout bottom = layout.createFolder("bottom", IPageLayout.BOTTOM, 0.50f, editorArea);
+    bottom.addView(BrowserView.ID_BROWSER);
+    IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, 0.30f, editorArea);
+    left.addView("net.sourceforge.phpeclipse.news.view.explorer");
+    IFolderLayout right = layout.createFolder("right", IPageLayout.RIGHT, 0.70f, editorArea);
+    right.addView("net.sourceforge.phpeclipse.news.view.headline");
+  }
+}
\ No newline at end of file
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Plugin.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/Plugin.java
new file mode 100644 (file)
index 0000000..424e081
--- /dev/null
@@ -0,0 +1,248 @@
+package net.sourceforge.phpeclipse.news;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import net.sourceforge.phpeclipse.news.pref.ChannelStore;
+import net.sourceforge.phpeclipse.news.pref.ListEncoder;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+public class Plugin extends AbstractUIPlugin {
+
+  public static final String BACKENDS_SECTION = "backends";
+
+  public static final String REFRESH_INTERVAL_PREFERENCE = "net.sourceforge.phpeclipse.news.refreshinterval";
+
+  /** @deprecated */
+  public static final String BACKENDS_PREFERENCE = "net.sourceforge.phpeclipse.news.backends";
+
+  public static final String BROWSER_PREFERENCE = "net.sourceforge.phpeclipse.news.browser";
+
+  public static final String BANNED_ITEMS_PREFERENCE = "net.sourceforge.phpeclipse.news.banneditems";
+
+  public static final String FORCE_CACHE_PREFERENCE = "net.sourceforge.phpeclipse.news.forcecache";
+
+  //Default values
+  public static final int DEFAULT_REFRESH_INTERVAL = 60;
+
+  public static final String DEFAULT_BROWSER = "C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE";
+
+  public static final String DEFAULT_BANNED_ITEMS = "";
+
+  public static final boolean DEFAULT_FORCE_CACHE = false;
+
+  //User-Agent
+  public static String userAgent;
+
+  protected UpdateThread updateThread;
+
+  protected ArrayList views = new ArrayList();
+
+  protected Timer timer;
+
+  protected ArrayList channelList;
+
+  protected Object channelLock = new Object();
+
+  protected ArrayList banList = new ArrayList();
+
+  /**
+   * List of RssListeners to notify
+   */
+  private ArrayList rssListeners = new ArrayList();
+
+  /**
+   * Constructor for Plugin
+   */
+  public Plugin(IPluginDescriptor descriptor) {
+    super(descriptor);
+
+    //set the user-agent ID
+    StringBuffer buffer = new StringBuffer();
+    buffer.append("AllTheNews/").append(descriptor.getVersionIdentifier()).append(" (").append(System.getProperty("os.name"))
+        .append("; ").append(System.getProperty("os.arch")).append("; http://www.jnegre.org/)");
+    userAgent = buffer.toString();
+
+    singleton = this;
+
+    //init the channel store
+    ChannelStore.init(this);
+
+    updateBanList();
+    updateChannelList();
+    setTimer();
+  }
+
+  protected static Plugin singleton;
+
+  public static Plugin getDefault() {
+    return singleton;
+  }
+
+  public static void logError(String message, Throwable t) {
+    getDefault().getLog()
+        .log(new Status(IStatus.ERROR, getDefault().getDescriptor().getUniqueIdentifier(), IStatus.OK, message, t));
+  }
+
+  public static void logInfo(String message, Throwable t) {
+    getDefault().getLog().log(new Status(IStatus.INFO, getDefault().getDescriptor().getUniqueIdentifier(), IStatus.OK, message, t));
+  }
+
+  /*
+   * @see AbstractUIPlugin#initializeDefaultPreferences(IPreferenceStore)
+   */
+  protected void initializeDefaultPreferences(IPreferenceStore store) {
+    store.setDefault(REFRESH_INTERVAL_PREFERENCE, DEFAULT_REFRESH_INTERVAL);
+    store.setDefault(BROWSER_PREFERENCE, DEFAULT_BROWSER);
+    store.setDefault(BANNED_ITEMS_PREFERENCE, DEFAULT_BANNED_ITEMS);
+    store.setDefault(FORCE_CACHE_PREFERENCE, DEFAULT_FORCE_CACHE);
+  }
+
+  protected ImageRegistry createImageRegistry() {
+    ImageRegistry registry = super.createImageRegistry();
+    IconManager.populateImageRegistry(registry);
+    return registry;
+  }
+
+  public void addRssListener(RssListener listener) {
+    synchronized (rssListeners) {
+      rssListeners.add(listener);
+    }
+  }
+
+  public void removeRssListener(RssListener listener) {
+    synchronized (rssListeners) {
+      rssListeners.remove(listener);
+    }
+  }
+
+  public void notifyChannelListChanged(RssListener source) {
+    Iterator iterator = rssListeners.iterator();
+    ArrayList channels = getChannelList();
+    while (iterator.hasNext()) {
+      RssListener listener = (RssListener) iterator.next();
+      if (listener != source) {
+        listener.onChannelListChanged(channels);
+      }
+    }
+  }
+
+  public void notifyChannelStatusChanged(Channel channel, RssListener source) {
+    Iterator iterator = rssListeners.iterator();
+    while (iterator.hasNext()) {
+      RssListener listener = (RssListener) iterator.next();
+      if (listener != source) {
+        listener.onChannelStatusChanged(channel);
+      }
+    }
+  }
+
+  public void notifyChannelSelected(Channel channel, RssListener source) {
+    Iterator iterator = rssListeners.iterator();
+    while (iterator.hasNext()) {
+      RssListener listener = (RssListener) iterator.next();
+      if (listener != source) {
+        listener.onChannelSelected(channel);
+      }
+    }
+  }
+
+  public void notifyItemSelected(Item item, RssListener source) {
+    Iterator iterator = rssListeners.iterator();
+    while (iterator.hasNext()) {
+      RssListener listener = (RssListener) iterator.next();
+      if (listener != source) {
+        listener.onItemSelected(item);
+      }
+    }
+  }
+
+  public void notifyItemStatusChanged(Item item, RssListener source) {
+    Iterator iterator = rssListeners.iterator();
+    while (iterator.hasNext()) {
+      RssListener listener = (RssListener) iterator.next();
+      if (listener != source) {
+        listener.onItemStatusChanged(item);
+      }
+    }
+  }
+
+  public void setTimer() {
+    if (timer != null) {
+      timer.cancel();
+    }
+    long period = getPreferenceStore().getInt(Plugin.REFRESH_INTERVAL_PREFERENCE) * 60000l;
+    if (period != 0) {
+      timer = new Timer(true);
+      timer.schedule(new UpdateTimer(), 0, period);
+    }
+  }
+
+  public void updateBanList() {
+    synchronized (banList) {
+      banList.clear();
+
+      String banned = this.getPreferenceStore().getString(Plugin.BANNED_ITEMS_PREFERENCE);
+      String[] bannedTitles = ListEncoder.decode(banned);
+      for (int i = 0; i < bannedTitles.length; i++) {
+        banList.add(bannedTitles[i]);
+      }
+    }
+  }
+
+  public boolean isBannedTitle(String title) {
+    synchronized (banList) {
+      return banList.contains(title);
+    }
+  }
+
+  public void updateChannelList() {
+    synchronized (channelLock) {
+      channelList = ChannelStore.getChannels();
+    }
+    notifyChannelListChanged(null);
+  }
+
+  public ArrayList getChannelList() {
+    synchronized (channelLock) {
+      return new ArrayList(channelList);
+    }
+  }
+
+  public void update() {
+    if (updateThread == null) {
+      updateThread = new UpdateThread();
+      updateThread.start();
+    }
+  }
+
+  protected class UpdateTimer extends TimerTask {
+    public void run() {
+      update();
+    }
+  }
+
+  public void shutdown() throws CoreException {
+    ChannelStore.saveReadStatus(getChannelList());
+    super.shutdown();
+  }
+
+  public IWorkbenchPage getActivePage() {
+    IWorkbenchWindow window = getWorkbench().getActiveWorkbenchWindow();
+    if (window != null)
+      return window.getActivePage();
+    return null;
+  }
+}
+
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/RssListener.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/RssListener.java
new file mode 100644 (file)
index 0000000..5e36f4b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Created on 15 mai 2004
+ * Copyright 2004 Jérôme Nègre
+ */
+package net.sourceforge.phpeclipse.news;
+
+import java.util.ArrayList;
+
+/**
+ * @author Jérôme Nègre
+ */
+public interface RssListener {
+       
+       public void onChannelListChanged(ArrayList channels);
+       
+       public void onChannelStatusChanged(Channel channel);
+
+       public void onChannelSelected(Channel channel);
+
+       public void onItemStatusChanged(Item tiem);
+       
+       public void onItemSelected(Item tiem);
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/UpdateThread.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/UpdateThread.java
new file mode 100644 (file)
index 0000000..8ab8e09
--- /dev/null
@@ -0,0 +1,36 @@
+package net.sourceforge.phpeclipse.news;
+
+import java.util.Iterator;
+
+public class UpdateThread extends Thread {
+
+
+    /**
+     * Constructor for UpdateThread
+     */
+    public UpdateThread() {
+        super();
+        this.setDaemon(true);
+    }
+
+    /**
+     * @see Runnable#run()
+     */
+    public void run() {
+        try {
+               Plugin plugin = Plugin.getDefault();
+            Iterator iterator = Plugin.getDefault().getChannelList().iterator();
+            while(iterator.hasNext()) {
+                Channel channel = (Channel)iterator.next();
+                channel.setRefreshing(true);
+                plugin.notifyChannelStatusChanged(channel, null);
+                channel.update();
+                channel.setRefreshing(false);
+                plugin.notifyChannelStatusChanged(channel, null);
+            }
+        } finally {
+            Plugin.getDefault().updateThread = null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/messages.properties b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/messages.properties
new file mode 100644 (file)
index 0000000..9aa9b8f
--- /dev/null
@@ -0,0 +1,3 @@
+#0 = description; 1=description with BR instead of \n; 2=url; 3=title
+BrowserView.DescriptionTemplate=<html><head><title>{3}</title></head><body><h2>{3}</h2><div>{1}</div><p><a href="{2}">Read more...</a></p></body></html>
+BrowserView.NoDescription=<i>No description</i>
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/BanListEditor.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/BanListEditor.java
new file mode 100644 (file)
index 0000000..c685c1f
--- /dev/null
@@ -0,0 +1,63 @@
+package net.sourceforge.phpeclipse.news.pref;
+
+import net.sourceforge.phpeclipse.news.Plugin;
+
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.preference.ListEditor;
+import org.eclipse.swt.widgets.Composite;
+
+public class BanListEditor extends ListEditor {
+
+    /**
+     * Constructor for SiteListEditor
+     */
+    protected BanListEditor(String name, String labelText, Composite parent) {
+        super(name, labelText, parent);
+    }
+
+    /**
+     * @see ListEditor#parseString(String)
+     */
+    protected String[] parseString(String stringList) {
+        return ListEncoder.decode(stringList);
+    }
+
+    /**
+     * @see ListEditor#getNewInputObject()
+     */
+    protected String getNewInputObject() {
+        InputDialog dialog;
+        dialog = new InputDialog(this.getShell(),"All The News","Enter item title to ban","",null);
+        dialog.open();
+        if("".equals(dialog.getValue()) || dialog.getValue()==null) {
+               return null;
+        } else {
+            return dialog.getValue();
+        }
+    }
+
+    /**
+     * @see ListEditor#createList(String[])
+     */
+    protected String createList(String[] items) {
+        return ListEncoder.encode(items);
+    }
+
+    /**
+     * @see org.eclipse.jface.preference.FieldEditor#doStore()
+     */
+    protected void doStore() {
+        super.doStore();
+        Plugin.getDefault().updateBanList();
+    }
+
+
+    /**
+     * @see org.eclipse.jface.preference.FieldEditor#doLoadDefault()
+     */
+    protected void doLoadDefault() {
+        super.doLoadDefault();
+        Plugin.getDefault().updateBanList();
+    }
+}
+
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/ChannelStore.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/ChannelStore.java
new file mode 100644 (file)
index 0000000..f48c494
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Created on 9 juin 2004
+ * Copyright 2004 Jérôme Nègre
+ */
+package net.sourceforge.phpeclipse.news.pref;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+
+import net.sourceforge.phpeclipse.news.Channel;
+import net.sourceforge.phpeclipse.news.Item;
+import net.sourceforge.phpeclipse.news.Plugin;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+
+/**
+ * @author Jérôme Nègre
+ */
+public class ChannelStore {
+       
+       private final static String DEFAULT_CHANNELS_FILE = "default_feeds.properties";
+       
+       private final static String BACKENDS_SECTION = "backends";
+       
+       private final static String CHANNELS_ORDER_KEY = "order";
+       private final static String TITLE_KEY = "title";
+       private final static String URL_KEY = "url";
+       private final static String TYPE_KEY = "type";
+       private final static String READ_KEY = "read";
+       
+       private final static int TYPE_CHANNEL = 1;
+       
+       private static Plugin plugin = null;
+       
+       public static void init(Plugin plugin) {
+               ChannelStore.plugin = plugin;
+       }
+       
+       public static synchronized ArrayList getChannels() {
+               IDialogSettings section = getChannelsSection();
+               String[] uids =  section.getArray(CHANNELS_ORDER_KEY);
+               ArrayList result = new ArrayList();
+               for(int i=0; i<uids.length; i++) {
+                       String uid = uids[i];
+                       IDialogSettings channelSection = section.getSection(uid);
+                       String title = channelSection.get(TITLE_KEY);
+                       String url = channelSection.get(URL_KEY);
+                       
+                       String[] readUids = channelSection.getArray(READ_KEY);
+                       HashSet set = new HashSet();
+                       if(readUids != null) {
+                               for(int k=0; k<readUids.length; k++) {
+                                       set.add(readUids[k]);
+                               }
+                       }
+                       
+                       result.add(new Channel(title, url, set));
+               }
+               return result;
+       }
+
+       public static synchronized void setChannels(ArrayList channels) {
+               IDialogSettings section = getChannelsSection();
+               section.put(CHANNELS_ORDER_KEY,new String[0]);
+               int newSize = channels.size();
+               for(int i=0; i<newSize; i++) {
+                       Channel channel = (Channel)channels.get(i); 
+                       addChannel(section,channel);
+               }
+       }
+       
+       public static synchronized void saveReadStatus(ArrayList channels) {
+               IDialogSettings channelsSection = getChannelsSection();
+               Iterator channelIter = channels.iterator();
+               while(channelIter.hasNext()) {
+                       Channel channel = (Channel)channelIter.next();
+                       IDialogSettings section = channelsSection.getSection(channel.getUID());
+                       Iterator itemIter = channel.getItems().iterator();
+                       ArrayList readItems = new ArrayList();
+                       while(itemIter.hasNext()) {
+                               Item item = (Item)itemIter.next();
+                               if(item.isReadFlag()) {
+                                       readItems.add(item.getUID());
+                               }
+                       }
+                       section.put(READ_KEY,(String[])readItems.toArray(new String[0]));
+               }
+       }
+       
+       public static synchronized ArrayList getDefaultChannels() {
+               ArrayList result = new ArrayList();
+               try {
+                       Properties prop = new Properties();
+                       URL propLocation = new URL(Plugin.getDefault().getDescriptor().getInstallURL(), DEFAULT_CHANNELS_FILE);
+                       prop.load(propLocation.openStream());
+                       Enumeration e = prop.propertyNames();
+                       while(e.hasMoreElements()) {
+                               String url = (String)e.nextElement();
+                               String title = prop.getProperty(url);
+                               result.add(new Channel(title, url));
+                       }
+               } catch(Exception e) {
+                       Plugin.logError("Error while getting default feed list", e);
+               }
+               return result;
+               
+       }
+       
+       /**
+        * Returns a non null Channels Section,
+        * creating it if needed.
+        * @return
+        */
+       private static IDialogSettings getChannelsSection() {
+        IDialogSettings section = plugin.getDialogSettings().getSection(BACKENDS_SECTION);
+        if(section == null) {
+               section = createDefaultChannelsSection();
+        }
+        return section;
+       }
+       
+       private static IDialogSettings createDefaultChannelsSection() {
+               IDialogSettings section = plugin.getDialogSettings().addNewSection(BACKENDS_SECTION);
+               section.put(CHANNELS_ORDER_KEY,new String[0]);
+               //add some default channels from config file
+               Iterator iterator = getDefaultChannels().iterator();
+               while(iterator.hasNext()) {
+                       addChannel(section, (Channel)iterator.next());
+               }
+               return section;
+       }
+       
+       private static void addChannel(IDialogSettings backendSection, Channel channel) {
+               String title = channel.getTitle();
+               String url = channel.getUrl();
+               String uid = channel.getUID();
+               //check that section does not already exist before
+               //creating it, and if it exists, add it to the order key
+               //only if it's not already in it.
+               IDialogSettings section = backendSection.getSection(uid);
+               boolean addInOrder = true;
+               if(section == null) {
+                       //create section
+                       section = backendSection.addNewSection(uid);
+               } else {
+                       //check if the section is already in the order key
+                       String[] orders = backendSection.getArray(CHANNELS_ORDER_KEY);
+                       for(int i=0; i<orders.length; i++) {
+                               if(orders[i].equals(uid)) {
+                                       addInOrder = false;
+                                       break;
+                               }
+                       }
+               }
+               //set data
+               section.put(TITLE_KEY, title);
+               section.put(URL_KEY, url);
+               section.put(TYPE_KEY, TYPE_CHANNEL);
+               //set order key if needed
+               if(addInOrder) {
+                       String[] oldOrder = backendSection.getArray(CHANNELS_ORDER_KEY);
+                       String[] newOrder = new String[oldOrder.length+1];
+                       System.arraycopy(oldOrder, 0, newOrder, 0, oldOrder.length);
+                       newOrder[oldOrder.length] = uid;
+                       backendSection.put(CHANNELS_ORDER_KEY,newOrder);
+               }
+       }
+       
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/ListEncoder.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/ListEncoder.java
new file mode 100644 (file)
index 0000000..a83e409
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Created on 14 juil. 2003
+ * (c)2003 Jérôme Nègre - http://www.jnegre.org/
+ *
+ */
+package net.sourceforge.phpeclipse.news.pref;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.StringTokenizer;
+
+import net.sourceforge.phpeclipse.news.Plugin;
+
+/**
+ * @author jerome
+ *
+ */
+public class ListEncoder {
+
+    public static String[] decode(String stringList) {
+        StringTokenizer tokenizer = new StringTokenizer(stringList, " ");
+        int countTokens = tokenizer.countTokens();
+        String[] result = new String[countTokens];
+        try {
+            for (int i = 0; i < countTokens; i++) {
+                result[i] = URLDecoder.decode(tokenizer.nextToken(), "UTF-8");
+            }
+        } catch (UnsupportedEncodingException e) {
+            Plugin.logError("Internal Error", e);
+        }
+        return result;
+    }
+
+    public static String encode(String[] items) {
+        StringBuffer result = new StringBuffer();
+        try {
+            for (int i = 0; i < items.length; i++) {
+                result.append(URLEncoder.encode(items[i], "UTF-8")).append(' ');
+            }
+        } catch (UnsupportedEncodingException e) {
+            Plugin.logError("Internal Error", e);
+        }
+        return result.toString();
+    }
+
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/PreferencePage.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/PreferencePage.java
new file mode 100644 (file)
index 0000000..ded0e33
--- /dev/null
@@ -0,0 +1,59 @@
+package net.sourceforge.phpeclipse.news.pref;
+
+import net.sourceforge.phpeclipse.news.Plugin;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.FileFieldEditor;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+public class PreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+    protected SiteListEditor siteListFE;
+    protected BanListEditor banListFE;
+    protected FileFieldEditor browserAppFE;
+    protected IntegerFieldEditor refreshFE;
+    protected BooleanFieldEditor forceCacheFE;
+
+    public PreferencePage() {
+        super("All The News", FieldEditorPreferencePage.GRID);
+    }
+
+    /**
+     * @see FieldEditorPreferencePage#createFieldEditors()
+     */
+    protected void createFieldEditors() {
+        siteListFE = new SiteListEditor(Plugin.BACKENDS_PREFERENCE, "Sites", getFieldEditorParent());
+        banListFE = new BanListEditor(Plugin.BANNED_ITEMS_PREFERENCE, "Banned items", getFieldEditorParent());
+        browserAppFE = new FileFieldEditor(Plugin.BROWSER_PREFERENCE, "External Browser", getFieldEditorParent());
+        refreshFE = new IntegerFieldEditor(Plugin.REFRESH_INTERVAL_PREFERENCE,"Refresh interval (minutes)", getFieldEditorParent());
+        refreshFE.setValidRange(0,10000);
+
+        forceCacheFE = new BooleanFieldEditor(Plugin.FORCE_CACHE_PREFERENCE,"Force refresh from proxy", getFieldEditorParent());
+
+        addField(siteListFE);
+        addField(banListFE);
+        addField(browserAppFE);
+        addField(refreshFE);
+        addField(forceCacheFE);
+    }
+
+    /**
+     * @see IWorkbenchPreferencePage#init(IWorkbench)
+     */
+    public void init(IWorkbench workbench) {
+        setPreferenceStore(Plugin.getDefault().getPreferenceStore());
+    }
+
+    /**
+     * @see org.eclipse.jface.preference.IPreferencePage#performOk()
+     */
+    public boolean performOk() {
+        boolean result = super.performOk();
+        Plugin.getDefault().setTimer();
+        return result;
+    }
+
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/SiteListEditor.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/pref/SiteListEditor.java
new file mode 100644 (file)
index 0000000..afcd485
--- /dev/null
@@ -0,0 +1,442 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Jérôme Nègre    - adaptation of ListEditor to add the search button
+ *******************************************************************************/
+package net.sourceforge.phpeclipse.news.pref;
+
+import java.util.ArrayList;
+
+import net.sourceforge.phpeclipse.news.Channel;
+import net.sourceforge.phpeclipse.news.Plugin;
+import net.sourceforge.phpeclipse.news.search.SearchDialog;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.Assert;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+
+public class SiteListEditor extends FieldEditor {
+       /**
+        * The list widget; <code>null</code> if none
+        * (before creation or after disposal).
+        */
+       private List list;
+       private ArrayList channels;
+       /**
+        * The button box containing the Add, Remove, Up, and Down buttons;
+        * <code>null</code> if none (before creation or after disposal).
+        */
+       private Composite buttonBox;
+       /**
+        * The Add button.
+        */
+       private Button addButton;
+       /**
+        * The Search button.
+        */
+       private Button searchButton;
+       /**
+        * The Remove button.
+        */
+       private Button removeButton;
+       /**
+        * The Up button.
+        */
+       private Button upButton;
+       /**
+        * The Down button.
+        */
+       private Button downButton;
+       /**
+        * The selection listener.
+        */
+       private SelectionListener selectionListener;
+       /**
+        * Notifies that the Add button has been pressed.
+        */
+       private void addPressed() {
+               setPresentsDefaultValue(false);
+               Channel input = getNewInputChannel();
+               if (input != null) {
+                       int index = list.getSelectionIndex();
+                       if (index >= 0) {
+                               list.add(input.getTitle(), index + 1);
+                               channels.add(index + 1, input);
+                       } else {
+                               list.add(input.getTitle(), 0);
+                               channels.add(0, input);
+                       }
+                       selectionChanged();
+               }
+       }
+
+       /**
+        * Notifies that the Search button has been pressed.
+        */
+       private void searchPressed() {
+               setPresentsDefaultValue(false);
+               SearchDialog sd = new SearchDialog(SiteListEditor.this
+                               .getShell());
+               sd.open();
+               Channel[] inputs = sd.getChannels();
+               for(int i=0; i<inputs.length; i++) {
+                       int index = list.getSelectionIndex();
+                       if (index >= 0) {
+                               list.add(inputs[i].getTitle(), index + 1);
+                               channels.add(index + 1, inputs[i]);
+                       } else {
+                               list.add(inputs[i].getTitle(), 0);
+                               channels.add(0, inputs[i]);
+                       }
+               }
+               selectionChanged();
+       }
+
+       
+       /* (non-Javadoc)
+        * Method declared on FieldEditor.
+        */
+       protected void adjustForNumColumns(int numColumns) {
+               Control control = getLabelControl();
+               ((GridData) control.getLayoutData()).horizontalSpan = numColumns;
+               ((GridData) list.getLayoutData()).horizontalSpan = numColumns - 1;
+       }
+       /**
+        * Creates the Add, Remove, Up, and Down button in the given button box.
+        *
+        * @param buttonBox the box for the buttons
+        */
+       private void createButtons(Composite buttonBox) {
+               addButton = createPushButton(buttonBox, "ListEditor.add");//$NON-NLS-1$
+               //TODO use my bundle ?
+               searchButton = createPushButton(buttonBox, "Search (experimental)");
+               removeButton = createPushButton(buttonBox, "ListEditor.remove");//$NON-NLS-1$
+               upButton = createPushButton(buttonBox, "ListEditor.up");//$NON-NLS-1$
+               downButton = createPushButton(buttonBox, "ListEditor.down");//$NON-NLS-1$
+       }
+       /**
+        * Helper method to create a push button.
+        * 
+        * @param parent the parent control
+        * @param key the resource name used to supply the button's label text
+        */
+       private Button createPushButton(Composite parent, String key) {
+               Button button = new Button(parent, SWT.PUSH);
+               button.setText(JFaceResources.getString(key));
+               button.setFont(parent.getFont());
+               GridData data = new GridData(GridData.FILL_HORIZONTAL);
+               data.heightHint = convertVerticalDLUsToPixels(button,
+                               IDialogConstants.BUTTON_HEIGHT);
+               int widthHint = convertHorizontalDLUsToPixels(button,
+                               IDialogConstants.BUTTON_WIDTH);
+               data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT,
+                               SWT.DEFAULT, true).x);
+               button.setLayoutData(data);
+               button.addSelectionListener(getSelectionListener());
+               return button;
+       }
+       /**
+        * Creates a selection listener.
+        */
+       public void createSelectionListener() {
+               selectionListener = new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent event) {
+                               Widget widget = event.widget;
+                               if (widget == addButton) {
+                                       addPressed();
+                               } else if (widget == searchButton) {
+                                       searchPressed();
+                               } else if (widget == removeButton) {
+                                       removePressed();
+                               } else if (widget == upButton) {
+                                       upPressed();
+                               } else if (widget == downButton) {
+                                       downPressed();
+                               } else if (widget == list) {
+                                       selectionChanged();
+                               }
+                       }
+               };
+       }
+       /* (non-Javadoc)
+        * Method declared on FieldEditor.
+        */
+       protected void doFillIntoGrid(Composite parent, int numColumns) {
+               Control control = getLabelControl(parent);
+               GridData gd = new GridData();
+               gd.horizontalSpan = numColumns;
+               control.setLayoutData(gd);
+               list = getListControl(parent);
+               gd = new GridData(GridData.FILL_HORIZONTAL);
+               gd.verticalAlignment = GridData.FILL;
+               gd.horizontalSpan = numColumns - 1;
+               gd.grabExcessHorizontalSpace = true;
+               list.setLayoutData(gd);
+               buttonBox = getButtonBoxControl(parent);
+               gd = new GridData();
+               gd.verticalAlignment = GridData.BEGINNING;
+               buttonBox.setLayoutData(gd);
+       }
+       /* (non-Javadoc)
+        * Method declared on FieldEditor.
+        */
+       protected void doLoad() {
+               if (list != null) {
+                       channels = ChannelStore.getChannels();
+                       for (int i = 0; i < channels.size(); i++) {
+                               list.add(((Channel)channels.get(i)).getTitle());
+                       }
+               }
+       }
+       /* (non-Javadoc)
+        * Method declared on FieldEditor.
+        */
+       protected void doLoadDefault() {
+               if (list != null) {
+                       list.removeAll();
+                       channels = ChannelStore.getDefaultChannels();
+                       for (int i = 0; i < channels.size(); i++) {
+                               list.add(((Channel)channels.get(i)).getTitle());
+                       }
+                       setPresentsDefaultValue(false);
+               }
+       }
+       /* (non-Javadoc)
+        * Method declared on FieldEditor.
+        */
+       protected void doStore() {
+               ChannelStore.saveReadStatus(Plugin.getDefault().getChannelList());
+               ChannelStore.setChannels(channels);
+               Plugin.getDefault().updateChannelList();
+       }
+       /**
+        * Notifies that the Down button has been pressed.
+        */
+       private void downPressed() {
+               swap(false);
+       }
+       /**
+        * Returns this field editor's button box containing the Add, Remove,
+        * Up, and Down button.
+        *
+        * @param parent the parent control
+        * @return the button box
+        */
+       public Composite getButtonBoxControl(Composite parent) {
+               if (buttonBox == null) {
+                       buttonBox = new Composite(parent, SWT.NULL);
+                       GridLayout layout = new GridLayout();
+                       layout.marginWidth = 0;
+                       buttonBox.setLayout(layout);
+                       createButtons(buttonBox);
+                       buttonBox.addDisposeListener(new DisposeListener() {
+                               public void widgetDisposed(DisposeEvent event) {
+                                       addButton = null;
+                                       searchButton = null;
+                                       removeButton = null;
+                                       upButton = null;
+                                       downButton = null;
+                                       buttonBox = null;
+                               }
+                       });
+               } else {
+                       checkParent(buttonBox, parent);
+               }
+               selectionChanged();
+               return buttonBox;
+       }
+       /**
+        * Returns this field editor's list control.
+        *
+        * @param parent the parent control
+        * @return the list control
+        */
+       public List getListControl(Composite parent) {
+               if (list == null) {
+                       list = new List(parent, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL
+                                       | SWT.H_SCROLL);
+                       list.setFont(parent.getFont());
+                       list.addSelectionListener(getSelectionListener());
+                       list.addDisposeListener(new DisposeListener() {
+                               public void widgetDisposed(DisposeEvent event) {
+                                       list = null;
+                               }
+                       });
+               } else {
+                       checkParent(list, parent);
+               }
+               return list;
+       }
+       /* (non-Javadoc)
+        * Method declared on FieldEditor.
+        */
+       public int getNumberOfControls() {
+               return 2;
+       }
+       /**
+        * Returns this field editor's selection listener.
+        * The listener is created if nessessary.
+        *
+        * @return the selection listener
+        */
+       private SelectionListener getSelectionListener() {
+               if (selectionListener == null)
+                       createSelectionListener();
+               return selectionListener;
+       }
+       /**
+        * Returns this field editor's shell.
+        * <p>
+        * This method is internal to the framework; subclassers should not call
+        * this method.
+        * </p>
+        *
+        * @return the shell
+        */
+       protected Shell getShell() {
+               if (addButton == null)
+                       return null;
+               return addButton.getShell();
+       }
+       /**
+        * Notifies that the Remove button has been pressed.
+        */
+       private void removePressed() {
+               setPresentsDefaultValue(false);
+               int index = list.getSelectionIndex();
+               if (index >= 0) {
+                       list.remove(index);
+                       channels.remove(index);
+                       selectionChanged();
+               }
+       }
+       /**
+        * Notifies that the list selection has changed.
+        */
+       private void selectionChanged() {
+               int index = list.getSelectionIndex();
+               int size = list.getItemCount();
+               removeButton.setEnabled(index >= 0);
+               upButton.setEnabled(size > 1 && index > 0);
+               downButton.setEnabled(size > 1 && index >= 0 && index < size - 1);
+       }
+       /* (non-Javadoc)
+        * Method declared on FieldEditor.
+        */
+       public void setFocus() {
+               if (list != null) {
+                       list.setFocus();
+               }
+       }
+       /**
+        * Moves the currently selected item up or down.
+        *
+        * @param up <code>true</code> if the item should move up,
+        *  and <code>false</code> if it should move down
+        */
+       private void swap(boolean up) {
+               setPresentsDefaultValue(false);
+               int index = list.getSelectionIndex();
+               int target = up ? index - 1 : index + 1;
+               if (index >= 0) {
+                       //list widget
+                       String[] selection = list.getSelection();
+                       Assert.isTrue(selection.length == 1);
+                       list.remove(index);
+                       list.add(selection[0], target);
+                       list.setSelection(target);
+                       //channels arrayList
+                       Object obj = channels.remove(index);
+                       channels.add(target, obj);
+               }
+               selectionChanged();
+       }
+       /**
+        * Notifies that the Up button has been pressed.
+        */
+       private void upPressed() {
+               swap(true);
+       }
+       /*
+        * @see FieldEditor.setEnabled(boolean,Composite).
+        */
+       public void setEnabled(boolean enabled, Composite parent) {
+               super.setEnabled(enabled, parent);
+               getListControl(parent).setEnabled(enabled);
+               addButton.setEnabled(enabled);
+               removeButton.setEnabled(enabled);
+               upButton.setEnabled(enabled);
+               downButton.setEnabled(enabled);
+       }
+
+       /*
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        * 
+        */
+       
+       /**
+        * Creates a site list field editor.
+        * 
+        * @param name the name of the preference this field editor works on
+        * @param labelText the label text of the field editor
+        * @param parent the parent of the field editor's control
+        */
+       protected SiteListEditor(String name, String labelText, Composite parent) {
+               init(name, labelText);
+               createControl(parent);
+       }
+       /**
+        * Creates and returns a new item for the list.
+        *
+        * @return a new item
+        */
+       protected Channel getNewInputChannel() {
+               InputDialog dialog;
+               dialog = new InputDialog(this.getShell(), "All The News",
+                               "Enter new site name", "", null);
+               dialog.open();
+               if ("".equals(dialog.getValue()) || dialog.getValue() == null)
+                       return null;
+               String title = dialog.getValue();
+               dialog = new InputDialog(this.getShell(), "All The News",
+                               "Enter new site URL", "", null);
+               dialog.open();
+               if ("".equals(dialog.getValue()) || dialog.getValue() == null)
+                       return null;
+               String url = dialog.getValue();
+               return new Channel(title, url);
+       }
+}
\ No newline at end of file
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/search/SearchDialog.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/search/SearchDialog.java
new file mode 100644 (file)
index 0000000..7e63e5a
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Created on 25 janv. 2004
+ *
+ * (c)2004 Jérôme Nègre - http://www.jnegre.org/
+ */
+
+package net.sourceforge.phpeclipse.news.search;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import net.sourceforge.phpeclipse.news.Channel;
+
+import org.apache.xmlrpc.XmlRpcClient;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @author Jérôme Nègre
+ *
+ */
+public class SearchDialog extends Dialog {
+
+    private Label statusBar;
+    private Text searchText;
+    private List list;
+    private Text name;
+    private Text siteUrl;
+    private Text feedUrl;
+    private Text version;
+    private Text description;
+    
+    private ArrayList resultChannels = new ArrayList();
+    
+    private XmlRpcClient xmlRpcClient;
+    
+    /**
+     * @param parentShell
+     */
+    public SearchDialog(Shell parentShell) {
+        super(parentShell);
+        this.setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MODELESS);
+    }
+
+    protected void configureShell(Shell newShell) {
+        super.configureShell(newShell);
+        newShell.setText("Search using http://www.syndic8.com/");
+    }
+
+    /**
+     * Adds the controls to the dialog
+     * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+     */
+    protected Control createDialogArea(Composite parent) {
+        Composite composite = (Composite)super.createDialogArea(parent);
+        GridLayout gl = (GridLayout)composite.getLayout();
+        gl.numColumns = 4;
+        
+        //Text to enter the searched words
+        searchText = new Text(composite,SWT.BORDER);
+        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+        gd.horizontalSpan = 3;
+        searchText.setLayoutData(gd);
+        //Button "search!"
+        Button searchButton = new Button(composite,0);
+        searchButton.setText("Search!");
+        searchButton.addSelectionListener(new SelectionAdapter() {
+            public void widgetSelected(SelectionEvent e) {
+                //TODO use a worker
+               Cursor waitCursor = new Cursor(SearchDialog.this.getContents().getDisplay(), SWT.CURSOR_WAIT);
+                try {
+                       SearchDialog.this.getContents().setCursor(waitCursor);
+                    SearchDialog.this.searchNow();
+                } catch (Exception x) {
+                    setStatusMessage("Error: "+x.getMessage());
+                } finally {
+                       SearchDialog.this.getContents().setCursor(null);
+                       waitCursor.dispose();
+                }
+            }
+        });
+        //List for the titles of the feeds
+        list = new List(composite,SWT.BORDER|SWT.H_SCROLL|SWT.V_SCROLL|SWT.SINGLE);
+        gd = new GridData(GridData.FILL_BOTH);
+        list.setLayoutData(gd);
+        list.addSelectionListener(new SelectionAdapter() {
+            public void widgetSelected(SelectionEvent e) {
+                SearchDialog.this.showFieldDetails((Hashtable)((ArrayList)list.getData()).get(list.getSelectionIndex()));
+            }
+        });
+        
+        //Description of the selected feed
+        Group group = new Group(composite,0);
+        group.setText("Selected Feed");
+        gd = new GridData(GridData.FILL_BOTH);
+        gd.horizontalSpan = 3;
+        group.setLayoutData(gd);
+        group.setLayout(new GridLayout(2,false));
+        //name
+        new Label(group,0).setText("Name:");
+        name = new Text(group,SWT.BORDER|SWT.READ_ONLY);
+        name.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        //site url
+        new Label(group,0).setText("Site URL:");
+        siteUrl = new Text(group,SWT.BORDER|SWT.READ_ONLY);
+        siteUrl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        //feed url
+        new Label(group,0).setText("Feed URL:");
+        feedUrl = new Text(group,SWT.BORDER|SWT.READ_ONLY);
+        feedUrl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        //RSS version
+        new Label(group,0).setText("RSS version:");
+        version = new Text(group,SWT.BORDER|SWT.READ_ONLY);
+        version.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        //description
+        new Label(group,0).setText("Description:");
+        description = new Text(group,SWT.BORDER|SWT.READ_ONLY|SWT.MULTI|SWT.H_SCROLL|SWT.V_SCROLL|SWT.WRAP);
+        description.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+        //status bar
+        statusBar = new Label(composite,SWT.NONE);
+        gd = new GridData(GridData.FILL_HORIZONTAL);
+        gd.horizontalSpan = 4;
+        statusBar.setLayoutData(gd);
+        setStatusMessage("Ready.");
+        return composite;
+    }
+
+    private XmlRpcClient getXmlRpcClient() throws MalformedURLException {
+        if(this.xmlRpcClient == null) {
+            this.xmlRpcClient = new XmlRpcClient("http://www.syndic8.com/xmlrpc.php");
+        }
+        return this.xmlRpcClient;
+    }
+
+    /**
+     * 
+     */
+    protected void searchNow() throws Exception {
+      clearFeedList();
+      setStatusMessage("Connecting...");
+      XmlRpcClient client = getXmlRpcClient();
+      //Get the list of ids
+      Vector args = new Vector();
+      args.add(searchText.getText());
+      args.add("sitename");
+      //args.add(new Integer(30));
+      Vector ids = (Vector)client.execute("syndic8.FindFeeds",args);
+      setStatusMessage("Found "+ids.size()+" result(s), asking for details...");
+      //Get the descriptions of the feeds
+      Vector fields = new Vector();
+      fields.add("sitename");
+      fields.add("siteurl");
+      fields.add("dataurl");
+      fields.add("rss_version");
+      fields.add("description");
+      args.clear();
+      args.add(ids);
+      args.add(fields);
+      Vector infos = (Vector)client.execute("syndic8.GetFeedInfo",args);
+      setStatusMessage("Showing details...");
+      Iterator iterator = infos.iterator();
+      while(iterator.hasNext()) {
+          Hashtable info = (Hashtable)iterator.next();
+          addFeedInList(info);
+      }
+      setStatusMessage("Ready.");
+    }
+    
+    protected void clearFeedList() {
+        list.removeAll();
+        showFieldDetails(null);
+        list.setData(new ArrayList());
+    }
+    
+    protected void showFieldDetails(Hashtable info) {
+        name.setText(info==null?"":(String)info.get("sitename"));
+        siteUrl.setText(info==null?"":(String)info.get("siteurl"));
+        feedUrl.setText(info==null?"":(String)info.get("dataurl"));
+        version.setText(info==null?"":(String)info.get("rss_version"));
+        description.setText(info==null?"":(String)info.get("description"));
+    }
+    
+    protected void addFeedInList(Hashtable info) {
+        String name = (String)info.get("sitename");
+        String dataurl = (String)info.get("dataurl");
+        if("".equals(name) || "".equals(dataurl)) {
+            //skip it
+            return;
+        }
+        ArrayList al = (ArrayList)list.getData();
+        al.add(info);
+        list.add(name);
+    }
+    
+    protected void setStatusMessage(String message) {
+        statusBar.setText(message);
+        //TODO remove next line
+        System.out.println(message);
+    }
+
+    protected void createButtonsForButtonBar(Composite parent) {
+        createButton(parent,IDialogConstants.OPEN_ID,"Add Selected",false);
+        createButton(parent,IDialogConstants.OK_ID,IDialogConstants.OK_LABEL,false);
+    }
+
+       protected void buttonPressed(int buttonId) {
+               super.buttonPressed(buttonId);
+               if(buttonId == IDialogConstants.OPEN_ID) {
+                       String name = this.name.getText();
+                       String url = this.feedUrl.getText();
+                       if(!"".equals(name) && !"".equals(url)) {
+                               resultChannels.add(new Channel(name, url));
+                       }
+               }
+       }
+       
+       public Channel[] getChannels() {
+               return (Channel[])resultChannels.toArray(new Channel[]{});
+       }
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/ExplorerView.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/ExplorerView.java
new file mode 100644 (file)
index 0000000..e1faf8d
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Created on 15 mai 2004
+ * Copyright 2004 Jérôme Nègre
+ */
+package net.sourceforge.phpeclipse.news.view;
+
+import java.util.ArrayList;
+
+import net.sourceforge.phpeclipse.news.Channel;
+import net.sourceforge.phpeclipse.news.IconManager;
+import net.sourceforge.phpeclipse.news.Item;
+import net.sourceforge.phpeclipse.news.Plugin;
+import net.sourceforge.phpeclipse.news.RssListener;
+import net.sourceforge.phpeclipse.webbrowser.views.BrowserView;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * @author Jérôme Nègre
+ */
+public class ExplorerView extends ViewPart implements RssListener {
+
+  private TreeViewer treeViewer;
+
+  private NewsTreeViewerProvider provider;
+
+  private Action refreshAction;
+
+  public ExplorerView() {
+    super();
+  }
+
+  public void dispose() {
+    Plugin.getDefault().removeRssListener(this);
+    super.dispose();
+  }
+
+  public void createPartControl(Composite parent) {
+    treeViewer = new TreeViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+    provider = new NewsTreeViewerProvider();
+    treeViewer.setContentProvider(provider);
+    treeViewer.setLabelProvider(provider);
+    treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+      public void selectionChanged(SelectionChangedEvent event) {
+        Object selected = ((StructuredSelection) event.getSelection()).getFirstElement();
+        if (selected != null) {
+          if (selected instanceof Channel) {
+            Plugin.getDefault().notifyChannelSelected((Channel) selected, ExplorerView.this);
+          } else if (selected instanceof Item) {
+            Plugin.getDefault().notifyItemSelected((Item) selected, ExplorerView.this);
+          }
+        }
+      }
+    });
+
+    createActions();
+    createMenu();
+    createToolBar();
+
+    Plugin.getDefault().addRssListener(this);
+    treeViewer.setInput(Plugin.getDefault());
+  }
+
+  public void setFocus() {
+    treeViewer.getControl().setFocus();
+  }
+
+  public void onChannelListChanged(ArrayList channels) {
+    treeViewer.setInput(Plugin.getDefault());
+  }
+
+  public void onChannelStatusChanged(final Channel channel) {
+    treeViewer.getControl().getDisplay().asyncExec(new Runnable() {
+      public void run() {
+        treeViewer.refresh(channel);
+      }
+    });
+  }
+
+  public void onChannelSelected(Channel channel) {
+    System.out.println("Explorer.onChannelSelected -> " + channel);
+  }
+
+  public void onItemStatusChanged(final Item item) {
+    treeViewer.getControl().getDisplay().asyncExec(new Runnable() {
+      public void run() {
+        treeViewer.refresh(item);
+      }
+    });
+  }
+
+  private void createActions() {
+    //refresh
+    refreshAction = new Action("Refresh", IconManager.getImageDescriptor(IconManager.ICON_ACTION_REFRESH)) {
+      public void run() {
+        Plugin.getDefault().update();
+      }
+    };
+    refreshAction.setToolTipText("Refresh");
+  }
+
+  private void createMenu() {
+    //IMenuManager mgr = getViewSite().getActionBars().getMenuManager();
+    //mgr.add(clearAction);
+  }
+
+  private void createToolBar() {
+    IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager();
+    mgr.add(refreshAction);
+  }
+
+  private void setUrl(String url) {
+    IWorkbenchPage page = Plugin.getDefault().getActivePage();
+    try {
+      IViewPart part = page.findView(BrowserView.ID_BROWSER);
+      if (part == null) {
+        part = page.showView(BrowserView.ID_BROWSER);
+      } else {
+        page.bringToTop(part);
+      }
+      ((BrowserView) part).setUrl(url);
+    } catch (Exception e) {
+    }
+  }
+
+  //    public void onItemSelected(Item tiem) {
+  //           // NOP
+  //   }
+  public void onItemSelected(Item item) {
+    if (item != null) { // && uiReady && linkAction.isChecked()) {
+    //                 if(showDescritionAction.isChecked()) {
+    //                         String desc = item.getDescription();
+    //                         if(desc == null)
+    //                                 desc = HTML_NO_DESCRIPTION;
+    //                         browser.setText(MessageFormat.format(HTML,new String[]{desc, encodeNewLine(desc), item.getUsableLink(),
+    // item.getUsableTitle()}));
+    //                 } else {  
+      setUrl(item.getUsableLink());
+      //                       }
+      //XXX this is a hack, should be done otherwise
+      boolean channelStatus = item.getChannel().isUnread();
+      item.setReadFlag(true);
+      Plugin.getDefault().notifyItemStatusChanged(item, this);
+      if (channelStatus != item.getChannel().isUnread()) {
+        Plugin.getDefault().notifyChannelStatusChanged(item.getChannel(), this);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/HeadlineView.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/HeadlineView.java
new file mode 100644 (file)
index 0000000..e87ef3e
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Created on 15 mai 2004
+ * Copyright 2004 Jérôme Nègre
+ */
+package net.sourceforge.phpeclipse.news.view;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import net.sourceforge.phpeclipse.news.Channel;
+import net.sourceforge.phpeclipse.news.IconManager;
+import net.sourceforge.phpeclipse.news.Item;
+import net.sourceforge.phpeclipse.news.Plugin;
+import net.sourceforge.phpeclipse.news.RssListener;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * @author Jérôme Nègre
+ */
+public class HeadlineView extends ViewPart implements RssListener {
+       
+       Table table;
+
+       public HeadlineView() {
+               super();
+       }
+
+       public void dispose() {
+               Plugin.getDefault().removeRssListener(this);
+               super.dispose();
+       }
+
+       private TableColumn createColumn(int style, int width, String text) {
+               TableColumn col = new TableColumn(table, style);
+               col.setWidth(width);
+               col.setText(text);
+               return col;
+       }
+       
+       public void createPartControl(Composite parent) {
+        table = new Table(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
+        //TODO remember the width of the columns
+        createColumn(SWT.LEFT, 120, "Publication Date");
+        createColumn(SWT.CENTER, 20, "");
+        createColumn(SWT.LEFT, 600, "Title");
+        table.setHeaderVisible(true);
+        table.addSelectionListener(new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent e) {
+                Item item = (Item) e.item.getData();
+                Plugin.getDefault().notifyItemSelected(item,HeadlineView.this);
+                       }
+        });
+        Plugin.getDefault().addRssListener(this);
+       }
+       
+       public void setFocus() {
+               table.setFocus();
+       }
+
+       public void onChannelListChanged(ArrayList channels) {
+               // NOP
+       }
+
+       public void onChannelStatusChanged(Channel channel) {
+               // NOP
+       }
+
+       public void onChannelSelected(Channel channel) {
+               fillTable(channel);
+       }
+
+       public void onItemSelected(Item item) {
+               fillTable(item.getChannel());
+               int index = item.getChannel().getItems().indexOf(item);
+               table.setSelection(index);
+       }
+
+       public void onItemStatusChanged(Item item) {
+               fillTable(item.getChannel());
+               int index = item.getChannel().getItems().indexOf(item);
+               table.setSelection(index);
+       }
+       
+       private void fillTable(Channel channel) {
+               Iterator items = channel.getItems().iterator();
+               table.removeAll();
+               while(items.hasNext()) {
+                       Item item = (Item)items.next();
+                       TableItem tableItem = new TableItem(table,SWT.NONE);
+                       tableItem.setText(0,item.getDate());
+                       String image = item.isReadFlag()? IconManager.ICON_STATUS_READ : IconManager.ICON_STATUS_UNREAD;
+                       tableItem.setImage(1,IconManager.getImage(image));
+                       tableItem.setText(2,item.getUsableTitle());
+                       tableItem.setData(item);
+               }
+       }
+}
diff --git a/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/NewsTreeViewerProvider.java b/archive/net.sourceforge.phpeclipse.news/src/net/sourceforge/phpeclipse/news/view/NewsTreeViewerProvider.java
new file mode 100644 (file)
index 0000000..8b225b3
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Created on 16 mai 2004
+ * Copyright 2004 Jérôme Nègre
+ */
+package net.sourceforge.phpeclipse.news.view;
+
+import net.sourceforge.phpeclipse.news.Channel;
+import net.sourceforge.phpeclipse.news.IconManager;
+import net.sourceforge.phpeclipse.news.Item;
+import net.sourceforge.phpeclipse.news.Plugin;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * @author Jérôme Nègre
+ */
+public class NewsTreeViewerProvider
+               implements
+                       ITreeContentProvider,
+                       ILabelProvider {
+
+       public Object[] getChildren(Object parentElement) {
+               if(parentElement instanceof Channel) {
+                       return ((Channel)parentElement).getItems().toArray();
+               } else {
+                       return null;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
+        */
+       public Object getParent(Object element) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public boolean hasChildren(Object element) {
+               if(element instanceof Channel) {
+                       return !((Channel)element).getItems().isEmpty();
+               } else {
+                       return false;
+               }
+       }
+
+       public Object[] getElements(Object inputElement) {
+               return ((Plugin)inputElement).getChannelList().toArray();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+        */
+       public void dispose() {
+               // TODO Auto-generated method stub
+               
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
+        */
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+               // TODO Auto-generated method stub
+       }
+
+       public Image getImage(Object element) {
+
+               String iconId;
+               
+               if(element instanceof Channel) {
+                       Channel channel = (Channel)element;
+                       if(channel.isRefreshing()) {
+                               iconId = IconManager.ICON_STATUS_REFRESH;
+                       } else if(channel.getErrorMessage()!=null) {
+                               iconId = IconManager.ICON_STATUS_ERROR;
+                       } else if(channel.isUnread()) {
+                               iconId = IconManager.ICON_STATUS_UNREAD;
+                       } else {
+                               iconId = IconManager.ICON_STATUS_READ;
+                       }
+               } else if(element instanceof Item) {
+                       Item item = (Item)element;
+                       if(item.isReadFlag()) {
+                               iconId = IconManager.ICON_STATUS_READ;
+                       } else {
+                               iconId = IconManager.ICON_STATUS_UNREAD;
+                       }
+               } else {
+                       return null;
+               }
+               return Plugin.getDefault().getImageRegistry().getDescriptor(iconId).createImage();
+       }
+
+       public String getText(Object element) {
+               if(element instanceof Channel) {
+                       return ((Channel)element).getTitle();
+               } else if(element instanceof Item) {
+                       return ((Item)element).getUsableTitle();
+               } else {
+                       return "Unexpected object: "+element;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
+        */
+       public void addListener(ILabelProviderListener listener) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
+        */
+       public boolean isLabelProperty(Object element, String property) {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
+        */
+       public void removeListener(ILabelProviderListener listener) {
+               // TODO Auto-generated method stub
+               
+       }
+}