1 package net.sourceforge.phpeclipse.phpmanual.views;
3 import java.io.BufferedReader;
4 import java.io.FileNotFoundException;
5 import java.io.FileReader;
6 import java.io.IOException;
7 import java.io.InputStream;
9 import java.util.ArrayList;
10 import java.util.zip.ZipEntry;
11 import java.util.zip.ZipFile;
13 import net.sourceforge.phpdt.internal.ui.text.JavaWordFinder;
14 import net.sourceforge.phpdt.internal.ui.viewsupport.ISelectionListenerWithAST;
15 import net.sourceforge.phpdt.internal.ui.viewsupport.SelectionListenerWithASTManager;
16 import net.sourceforge.phpdt.phphelp.PHPHelpPlugin;
17 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
18 import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
19 import net.sourceforge.phpeclipse.phpmanual.PHPManualUIPlugin;
21 import org.eclipse.core.runtime.Path;
22 import org.eclipse.core.runtime.Platform;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.IRegion;
25 import org.eclipse.jface.text.ITextSelection;
26 import org.eclipse.jface.viewers.ISelection;
27 import org.eclipse.swt.SWT;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Display;
30 import org.eclipse.swt.browser.Browser;
31 import org.eclipse.ui.IEditorPart;
32 import org.eclipse.ui.ISelectionListener;
33 import org.eclipse.ui.IWorkbenchPart;
34 import org.eclipse.ui.part.ViewPart;
35 import org.htmlparser.Node;
36 import org.htmlparser.Parser;
37 import org.htmlparser.tags.Div;
38 import org.htmlparser.util.ParserException;
39 import org.htmlparser.visitors.TagFindingVisitor;
40 import org.osgi.framework.Bundle;
43 * This ViewPart is the implementation of the idea of having the
44 * PHP Manual easily accessible while coding. It shows the
45 * under-cursor function's reference inside a browser.
47 * The view listens to selection changes both in the (1)workbench, to
48 * know when the user changes between the instances of the PHPEditor
49 * or when a new instance is created; and in the (2)PHPEditor, to know
50 * when the user changes the cursor position. This explains the need
51 * to implement both ISelectionListener and ISelectionListenerWithAST.
53 * Up to now, the ViewPart show reference pages from HTML stored in the
54 * doc.zip file from the net.sourceforge.phpeclipse.phphelp plugin. It
55 * also depends on net.sourceforge.phpeclipse.phpmanual.htmlparser to
56 * parse these HTML files.
60 public class PHPManualView extends ViewPart implements ISelectionListener, ISelectionListenerWithAST {
63 * The ViewPart's browser
65 private Browser browser;
68 * A reference to store last active editor to know when we've
69 * got a new instance of the PHPEditor
71 private PHPEditor lastEditor;
74 * The path to the doc.zip file containing the PHP Manual
77 private final Path docPath = new Path("doc.zip");
82 public PHPManualView() {
86 * This method initializes the ViewPart. It instantiates components
89 * @param parent The parent control
91 public void createPartControl(Composite parent) {
92 browser = new Browser(parent, SWT.NONE);
94 if ((lastEditor = getJavaEditor()) != null) {
95 SelectionListenerWithASTManager.getDefault().addListener(lastEditor, this);
97 getSite().getWorkbenchWindow().getSelectionService()
98 .addSelectionListener(PHPeclipsePlugin.EDITOR_ID, this);
102 * Cleanup to remove the selection listener
104 public void dispose() {
105 getSite().getWorkbenchWindow().getSelectionService()
106 .removeSelectionListener(PHPeclipsePlugin.EDITOR_ID, this);
110 * Passing the focus request to the viewer's control.
112 public void setFocus() {
117 * Treats selection changes from the PHPEditor
119 public void selectionChanged(IEditorPart part, ITextSelection selection) {
120 IDocument document = ((PHPEditor)part).getViewer().getDocument();
121 int offset = selection.getOffset();
122 IRegion iRegion = JavaWordFinder.findWord(document, offset);
124 final String wordStr = document.get(iRegion.getOffset(),
125 iRegion.getLength());
126 showReference(wordStr);
127 } catch (Exception e) {
133 * Treats selection changes from the workbench. When part is new
134 * instance of PHPEditor it gets a listener attached
136 public void selectionChanged(IWorkbenchPart part, ISelection selection) {
137 if (!((PHPEditor)part).equals(lastEditor)) {
138 SelectionListenerWithASTManager.getDefault().addListener((PHPEditor)part, this);
139 lastEditor = (PHPEditor)part;
144 * Updates the browser with the reference page for a given function
146 * @param funcName Function name
148 private void showReference(final String funcName) {
149 System.out.println("Show reference for " + funcName);
150 new Thread(new Runnable() {
152 Display.getDefault().asyncExec(new Runnable() {
154 String html = getHtmlSource(funcName);
155 browser.setText(html);
163 * Filters the function's reference page extracting only parts of it
165 * @param source HTML source of the reference page
166 * @return HTML source of reference page
168 private String filterHtmlSource(String source) {
170 Parser parser = new Parser(source);
171 String [] tagsToBeFound = {"DIV"};
172 ArrayList<String> classList = new ArrayList<String>(6);
173 classList.add("refnamediv");
174 classList.add("refsect1 description");
175 classList.add("refsect1 parameters");
176 classList.add("refsect1 returnvalues");
177 classList.add("refsect1 examples");
178 classList.add("refsect1 seealso");
179 classList.add("refsect1 u");
180 TagFindingVisitor visitor = new TagFindingVisitor(tagsToBeFound);
181 parser.visitAllNodesWith(visitor);
182 Node [] allPTags = visitor.getTags(0);
183 StringBuilder output = new StringBuilder();
184 for (int i = 0; i < allPTags.length; i++) {
185 String tagClass = ((Div)allPTags[i]).getAttribute("class");
186 if (classList.contains(tagClass)) {
187 output.append(allPTags[i].toHtml());
190 return output.toString().replace("—", "-");
191 //.replace("<h3 class=\"title\">Description</h3>", " ");
192 } catch (ParserException e) {
199 * Reads the template that defines the style of the reference page
200 * shown inside the view's browser
202 * @return HTML source of the template
204 public String getRefPageTemplate() {
205 Bundle bundle = Platform.getBundle(PHPManualUIPlugin.PLUGIN_ID);
206 URL fileURL = Platform.find(bundle, new Path("templates"));
207 StringBuffer contents = new StringBuffer();
208 BufferedReader input = null;
210 URL resolve = Platform.resolve(fileURL);
211 input = new BufferedReader(new FileReader(resolve.getPath()+"/refpage.html"));
213 while ((line = input.readLine()) != null){
214 contents.append(line);
217 catch (FileNotFoundException e) {
219 } catch (IOException e) {
228 catch (IOException ex) {
229 ex.printStackTrace();
232 return contents.toString();
236 * Looks for the function's reference page inside the doc.zip file
237 * and returns a filtered HTML source of it embedded in the template
239 * @param funcName Function name
240 * @return HTML source of reference page
242 public String getHtmlSource(String funcName) {
243 Bundle bundle = Platform.getBundle(PHPHelpPlugin.PLUGIN_ID);
244 URL fileURL = Platform.find(bundle, docPath);
247 URL resolve = Platform.resolve(fileURL);
248 ZipFile docFile = new ZipFile(resolve.getPath());
249 ZipEntry entry = docFile.getEntry("doc/function."+funcName.replace('_', '-')+".html");
250 InputStream ref = docFile.getInputStream(entry);
251 b = new byte[(int)entry.getSize()];
252 ref.read(b, 0, (int)entry.getSize());
253 } catch (IOException e) {
254 return "<html></html>";
257 String reference = filterHtmlSource(new String(b));
258 String refPageTpl = getRefPageTemplate();
259 refPageTpl = refPageTpl.replace("{title}", funcName);
260 refPageTpl = refPageTpl.replace("{reference}", reference);
263 return "<html></html>";
267 * Returns the currently active java editor, or <code>null</code> if it
268 * cannot be determined.
270 * @return the currently active java editor, or <code>null</code>
272 private PHPEditor getJavaEditor() {
274 IEditorPart part = PHPeclipsePlugin.getActivePage().getActiveEditor();
275 if (part instanceof PHPEditor)
276 return (PHPEditor) part;
279 } catch (Exception e) {