Bug 1650 - Source not found for preview code while stepping in debugger - was fixed
authorEugene Ostroukhov <eugeneo@symbian.org>
Mon, 08 Feb 2010 11:14:10 -0800
changeset 104 58b323842de3
parent 103 ef9f02ee3266
child 105 080d3ff46c86
child 107 7dc2457b02ac
Bug 1650 - Source not found for preview code while stepping in debugger - was fixed
org.symbian.tools.wrttools.debug.core/META-INF/MANIFEST.MF
org.symbian.tools.wrttools.debug.core/plugin.xml
org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/WorkspaceLineBreakpointAdapter.java
org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/WRTProjectWorkspaceBridge.java
org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/model/JsWatchExpressionDelegate.java
org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/model/SymbianDebugModelPresentation.java
org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/model/WorkspaceBreakpointHandler.java
org.symbian.tools.wrttools.previewer/src/org/symbian/tools/wrttools/previewer/http/HttpPreviewer.java
org.symbian.tools.wrttools.previewer/src/org/symbian/tools/wrttools/previewer/http/WorkspaceResourcesServlet.java
org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/util/CoreUtil.java
--- a/org.symbian.tools.wrttools.debug.core/META-INF/MANIFEST.MF	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools.debug.core/META-INF/MANIFEST.MF	Mon Feb 08 11:14:10 2010 -0800
@@ -16,7 +16,9 @@
  org.eclipse.ui.editors;bundle-version="3.5.0",
  org.eclipse.jface.text;bundle-version="3.5.0",
  org.symbian.tools.wrttools.previewer;bundle-version="1.0.0",
- org.symbian.tools.wrttools;bundle-version="1.0.0"
+ org.symbian.tools.wrttools;bundle-version="1.0.0",
+ org.eclipse.core.filesystem;bundle-version="1.2.0",
+ org.eclipse.ui.ide;bundle-version="3.5.1"
 Bundle-RequiredExecutionEnvironment: J2SE-1.5,
  JavaSE-1.6
 Bundle-ActivationPolicy: lazy
--- a/org.symbian.tools.wrttools.debug.core/plugin.xml	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools.debug.core/plugin.xml	Mon Feb 08 11:14:10 2010 -0800
@@ -184,4 +184,41 @@
          </actionSet>
       </perspectiveExtension>
    </extension>
+   <extension
+         point="org.eclipse.debug.ui.debugModelPresentations">
+      <debugModelPresentation
+            class="org.symbian.tools.wrttools.debug.internal.model.SymbianDebugModelPresentation"
+            id="org.symbian.debug">
+      </debugModelPresentation>
+   </extension>
+     <extension point="org.eclipse.debug.core.watchExpressionDelegates">
+    <watchExpressionDelegate
+        debugModel="org.symbian.debug"
+        delegateClass="org.symbian.tools.wrttools.debug.internal.model.JsWatchExpressionDelegate"/>
+  </extension>
+    <extension point="org.eclipse.ui.editorActions">
+    <editorContribution
+        targetID="org.chromium.debug.ui.editors.JsEditor"
+        id="org.chromium.debug.ui.editors.JsEditor.editorActions">
+      <action
+          toolbarPath="evaluationGroup"
+          id="org.chromium.debug.ui.SnippetInspect"
+          definitionId="org.chromium.debug.ui.commands.Inspect"
+          class="org.chromium.debug.ui.actions.JsInspectSnippetAction"
+          enablesFor="+"
+          label="Inspect"
+          tooltip="Inspect Result of Evaluating Selected Text">
+        <enablement>
+          <and>
+            <systemProperty
+                name="org.chromium.debug.ui.debuggerActive"
+                value="true"/>
+            <objectClass
+                name="org.eclipse.jface.text.ITextSelection"/>
+          </and>
+        </enablement>
+      </action>
+    </editorContribution>
+  </extension>
+  
 </plugin>
--- a/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/WorkspaceLineBreakpointAdapter.java	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/WorkspaceLineBreakpointAdapter.java	Mon Feb 08 11:14:10 2010 -0800
@@ -19,13 +19,13 @@
 package org.symbian.tools.wrttools.debug.internal;
 
 import org.chromium.debug.core.model.LineBreakpointAdapter;
-import org.chromium.debug.core.model.VProjectWorkspaceBridge;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor;
+import org.symbian.tools.wrttools.debug.internal.launch.WRTProjectWorkspaceBridge;
 
+@SuppressWarnings("restriction")
 public class WorkspaceLineBreakpointAdapter extends LineBreakpointAdapter {
-	@SuppressWarnings("restriction")
 	@Override
 	protected ITextEditor getEditor(IWorkbenchPart part) {
 		if (part instanceof JavaEditor) {
@@ -37,6 +37,6 @@
 
     @Override
     protected String getDebugModelId() {
-      return VProjectWorkspaceBridge.DEBUG_MODEL_ID;
+      return WRTProjectWorkspaceBridge.DEBUG_MODEL_ID;
     }
 }
--- a/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/WRTProjectWorkspaceBridge.java	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/launch/WRTProjectWorkspaceBridge.java	Mon Feb 08 11:14:10 2010 -0800
@@ -1,16 +1,17 @@
 package org.symbian.tools.wrttools.debug.internal.launch;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
 
 import org.chromium.debug.core.model.ChromiumLineBreakpoint;
 import org.chromium.debug.core.model.DebugTargetImpl;
 import org.chromium.debug.core.model.StackFrame;
-import org.chromium.debug.core.model.VProjectWorkspaceBridge;
 import org.chromium.debug.core.model.WorkspaceBridge;
 import org.chromium.sdk.JavascriptVm;
 import org.chromium.sdk.Script;
 import org.chromium.sdk.JavascriptVm.ScriptsCallback;
+import org.eclipse.core.filesystem.EFS;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IProject;
@@ -23,6 +24,7 @@
 import org.symbian.tools.wrttools.debug.internal.Activator;
 import org.symbian.tools.wrttools.debug.internal.model.ResourceManager;
 import org.symbian.tools.wrttools.debug.internal.model.WorkspaceBreakpointHandler;
+import org.symbian.tools.wrttools.previewer.PreviewerPlugin;
 
 public class WRTProjectWorkspaceBridge implements WorkspaceBridge {
 	public static final class Factory implements WorkspaceBridge.Factory {
@@ -48,7 +50,8 @@
 
 	}
 
-	public final static String DEBUG_MODEL_ID = VProjectWorkspaceBridge.DEBUG_MODEL_ID;
+//	public final static String DEBUG_MODEL_ID = VProjectWorkspaceBridge.DEBUG_MODEL_ID;
+	public final static String DEBUG_MODEL_ID = "org.symbian.debug";
 
 	private final BreakpointHandler breakpointHandler;
 	private final JavascriptVm javascriptVm;
@@ -145,7 +148,20 @@
 				return null;
 			}
 
-			return resourceManager.getResource(script);
+			IFile resource = resourceManager.getResource(script);
+			if (resource != null) {
+				return resource;
+			} else {
+				File file = PreviewerPlugin.getDefault().getHttpPreviewer().getLocalFile(script.getName());
+				if (file != null) {
+					try {
+						return EFS.getStore(file.toURI());
+					} catch (CoreException e) {
+						Activator.log(e);
+					}
+				}
+			}
+			return null;
 		}
 	};
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/model/JsWatchExpressionDelegate.java	Mon Feb 08 11:14:10 2010 -0800
@@ -0,0 +1,170 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.symbian.tools.wrttools.debug.internal.model;
+
+import org.chromium.debug.core.model.DebugElementImpl;
+import org.chromium.debug.core.model.EvaluateContext;
+import org.chromium.debug.core.model.Variable;
+import org.chromium.sdk.JsEvaluateContext;
+import org.chromium.sdk.JsVariable;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IWatchExpressionDelegate;
+import org.eclipse.debug.core.model.IWatchExpressionListener;
+import org.eclipse.debug.core.model.IWatchExpressionResult;
+import org.symbian.tools.wrttools.debug.internal.Activator;
+
+/**
+ * Performs the Watch expression evaluation while debugging Chromium JavaScript.
+ */
+public class JsWatchExpressionDelegate implements IWatchExpressionDelegate {
+
+  private static final String[] EMPTY_STRINGS = new String[0];
+
+  private static final class GoodWatchExpressionResult implements IWatchExpressionResult {
+
+    private final Variable variable;
+
+    private final String expression;
+
+    private IValue value;
+
+    private DebugException exception;
+
+    private GoodWatchExpressionResult(Variable variable, String expression) {
+      this.variable = variable;
+      this.expression = expression;
+    }
+
+    public String[] getErrorMessages() {
+      return exception == null
+          ? EMPTY_STRINGS
+          : new String[] { exception.getStatus().getMessage() };
+    }
+
+    public DebugException getException() {
+      getValue();
+      return exception;
+    }
+
+    public String getExpressionText() {
+      return expression;
+    }
+
+    public synchronized IValue getValue() {
+      if (value == null && exception == null) {
+        try {
+          value = variable.getValue();
+        } catch (DebugException e) {
+          this.exception = e;
+        }
+      }
+      return value;
+    }
+
+    public boolean hasErrors() {
+      getValue();
+      return exception != null;
+    }
+  }
+
+  private static final class BadWatchExpressionResult implements IWatchExpressionResult {
+
+    private final DebugException exception;
+
+    private final String expressionText;
+
+    private BadWatchExpressionResult(DebugException exception, String expressionText) {
+      this.exception = exception;
+      this.expressionText = expressionText;
+    }
+
+    public String[] getErrorMessages() {
+      return new String[] { exception.getStatus().getMessage() };
+    }
+
+    public DebugException getException() {
+      return exception;
+    }
+
+    public String getExpressionText() {
+      return expressionText;
+    }
+
+    public IValue getValue() {
+      return null;
+    }
+
+    public boolean hasErrors() {
+      return true;
+    }
+  }
+
+  public void evaluateExpression(final String expression, final IDebugElement context,
+      final IWatchExpressionListener listener) {
+    final DebugElementImpl contextImpl = (DebugElementImpl) context;
+    if (!contextImpl.getDebugTarget().isSuspended()) {
+      // can only evaluate while suspended. Notify empty result.
+      listener.watchEvaluationFinished(new IWatchExpressionResult() {
+
+        public String[] getErrorMessages() {
+          return EMPTY_STRINGS;
+        }
+
+        public DebugException getException() {
+          return null;
+        }
+
+        public String getExpressionText() {
+          return expression;
+        }
+
+        public IValue getValue() {
+          return null;
+        }
+
+        public boolean hasErrors() {
+          return false;
+        }
+      });
+      return;
+    }
+
+    final EvaluateContext evaluateContext =
+        (EvaluateContext) contextImpl.getAdapter(EvaluateContext.class);
+    if (evaluateContext == null) {
+      listener.watchEvaluationFinished(new BadWatchExpressionResult(
+          new DebugException(
+              new Status(Status.ERROR, Activator.PLUGIN_ID, "Bad debug context")), //$NON-NLS-1$
+          expression));
+      return;
+    }
+
+    evaluateContext.getJsEvaluateContext().evaluateAsync(
+        expression,
+        new JsEvaluateContext.EvaluateCallback() {
+          public void success(JsVariable variable) {
+            final Variable var = new Variable(contextImpl.getDebugTarget(), variable, false);
+            listener.watchEvaluationFinished(new GoodWatchExpressionResult(var, expression));
+          }
+
+          public void failure(String message) {
+            listener.watchEvaluationFinished(new BadWatchExpressionResult(new DebugException(
+                createErrorStatus(message == null
+                    ? "Error evaluating expression"
+                    : message, null)), expression));
+            return;
+          }
+        },
+        null);
+  }
+
+  private static Status createErrorStatus(String message, Exception e) {
+    return new Status(Status.ERROR, Activator.PLUGIN_ID, message, e);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/model/SymbianDebugModelPresentation.java	Mon Feb 08 11:14:10 2010 -0800
@@ -0,0 +1,113 @@
+package org.symbian.tools.wrttools.debug.internal.model;
+
+import org.chromium.debug.core.model.Value;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.ILineBreakpoint;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.ui.IDebugModelPresentation;
+import org.eclipse.debug.ui.IValueDetailListener;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.ide.FileStoreEditorInput;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.wst.jsdt.ui.JavaScriptUI;
+
+public class SymbianDebugModelPresentation extends LabelProvider implements
+		IDebugModelPresentation {
+
+	public void setAttribute(String attribute, Object value) {
+	}
+
+	@Override
+	public Image getImage(Object element) {
+		// use default image
+		return null;
+	}
+
+	@Override
+	public String getText(Object element) {
+		// use default label text
+		return null;
+	}
+
+	public void computeDetail(IValue value, IValueDetailListener listener) {
+		String detail = ""; //$NON-NLS-1$
+		if (value instanceof Value) {
+			// Avoid quoting string JavaScript values by getting the value
+			// string
+			// from the underlying JsValue.
+			detail = ((Value) value).getJsValue().getValueString();
+		}
+
+		listener.detailComputed(value, detail);
+	}
+
+	public IEditorInput getEditorInput(Object element) {
+		return toEditorInput(element);
+	}
+
+	public static IEditorInput toEditorInput(Object element) {
+		if (element instanceof IFile) {
+			return new FileEditorInput((IFile) element);
+		}
+		if (element instanceof IFileStore) {
+			return new FileStoreEditorInput((IFileStore) element);
+		}
+
+		if (element instanceof ILineBreakpoint) {
+			return new FileEditorInput((IFile) ((ILineBreakpoint) element)
+					.getMarker().getResource());
+		}
+
+		return null;
+	}
+
+	public String getEditorId(IEditorInput input, Object element) {
+		if (input instanceof IFileEditorInput) {
+			IFile file;
+			if (element instanceof IFile) {
+				file = (IFile) element;
+			} else if (element instanceof IBreakpoint) {
+				IBreakpoint breakpoint = (IBreakpoint) element;
+				IResource resource = breakpoint.getMarker().getResource();
+				// Can the breakpoint resource be folder or project? Better
+				// check for it.
+				if (resource instanceof IFile == false) {
+					return null;
+				}
+				file = (IFile) resource;
+			} else {
+				return null;
+			}
+
+			// Pick the editor based on the file extension, taking user
+			// preferences into account.
+			try {
+				return IDE.getEditorDescriptor(file).getId();
+			} catch (PartInitException e) {
+				// TODO(peter.rybin): should it really be the default case?
+				// There might be no virtual project.
+				return null;
+			}
+		} else {
+			if (element instanceof IFileStore) {
+				IFileStore store = (IFileStore) element;
+				String ext = new Path(store.getName()).getFileExtension();
+				if (ext.equals("js")) {
+					return JavaScriptUI.ID_CU_EDITOR;
+				} else {
+					return "org.eclipse.wst.html.core.htmlsource.source";
+				}
+			}
+		}
+		return null;
+	}
+}
--- a/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/model/WorkspaceBreakpointHandler.java	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools.debug.core/src/org/symbian/tools/wrttools/debug/internal/model/WorkspaceBreakpointHandler.java	Mon Feb 08 11:14:10 2010 -0800
@@ -8,6 +8,7 @@
 import org.chromium.debug.core.ChromiumDebugPlugin;
 import org.chromium.debug.core.model.ChromiumLineBreakpoint;
 import org.chromium.debug.core.model.DebugTargetImpl;
+import org.chromium.debug.core.model.VProjectWorkspaceBridge;
 import org.chromium.debug.core.model.WorkspaceBridge.BreakpointHandler;
 import org.chromium.sdk.Breakpoint;
 import org.chromium.sdk.JavascriptVm;
@@ -32,7 +33,9 @@
 	}
 	
 	public boolean supportsBreakpoint(IBreakpoint breakpoint) {
-		return WRTProjectWorkspaceBridge.DEBUG_MODEL_ID.equals(breakpoint.getModelIdentifier())
+		return (WRTProjectWorkspaceBridge.DEBUG_MODEL_ID.equals(breakpoint
+				.getModelIdentifier()) || VProjectWorkspaceBridge.DEBUG_MODEL_ID
+				.equals(breakpoint.getModelIdentifier()))
 				&& !debugTarget.isDisconnected();
 	}
 
--- a/org.symbian.tools.wrttools.previewer/src/org/symbian/tools/wrttools/previewer/http/HttpPreviewer.java	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools.previewer/src/org/symbian/tools/wrttools/previewer/http/HttpPreviewer.java	Mon Feb 08 11:14:10 2010 -0800
@@ -1,5 +1,6 @@
 package org.symbian.tools.wrttools.previewer.http;
 
+import java.io.File;
 import java.net.URI;
 import java.net.URISyntaxException;
 
@@ -34,4 +35,9 @@
 		}
 	}
 
+	public File getLocalFile(String name) {
+		return WorkspaceResourcesServlet.getPreviewerResource(name);
+		
+	}
+
 }
--- a/org.symbian.tools.wrttools.previewer/src/org/symbian/tools/wrttools/previewer/http/WorkspaceResourcesServlet.java	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools.previewer/src/org/symbian/tools/wrttools/previewer/http/WorkspaceResourcesServlet.java	Mon Feb 08 11:14:10 2010 -0800
@@ -18,11 +18,10 @@
  *******************************************************************************/
 package org.symbian.tools.wrttools.previewer.http;
 
-import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
@@ -50,6 +49,9 @@
 import org.symbian.tools.wrttools.util.CoreUtil;
 
 public class WorkspaceResourcesServlet extends HttpServlet {
+	private static final String PREVIEW_START = "/preview/wrt_preview.html";
+	private static final String METADATA_FILE = "Info.plist";
+	private static final String PREVIEW_PATH = "preview";
 	private static final String STARTING_PAGE = "preview-frame.html";
 	private static final String INDEX_PAGE = "wrt_preview_main.html";
 	private static final long serialVersionUID = -3217197074249607950L;
@@ -87,11 +89,11 @@
 		if (relativePath.segmentCount() == 1) {
 			if (STARTING_PAGE.equals(relativePath.segment(0))) {
 				return getPluginResourceStream(new Path(
-						"/preview/wrt_preview.html"));
+						PREVIEW_START));
 			} else if (INDEX_PAGE.equals(relativePath.segment(0))) {
 				return getProjectIndexPage(path.segment(0));
 			}
-		} else if ("preview".equals(relativePath.segment(0))) {
+		} else if (PREVIEW_PATH.equals(relativePath.segment(0))) {
 			return getPluginResourceStream(relativePath.makeAbsolute());
 		}
 		return null;
@@ -102,9 +104,9 @@
 		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(
 				projectName);
 		if (project.isAccessible()) {
-			String indexFileName = CoreUtil.getIndexFileName(readFile(project, "Info.plist"));
+			String indexFileName = CoreUtil.getIndexFileName(CoreUtil.readFile(project, METADATA_FILE));
 			if (indexFileName != null) {
-				String string = readFile(project, indexFileName);
+				String string = CoreUtil.readFile(project, indexFileName);
 				if (string != null) {
 					Matcher matcher = HEAD_TAG_PATTERN.matcher(string);
 					if (matcher.find()) {
@@ -117,41 +119,6 @@
 		return null;
 	}
 
-	private String readFile(IProject project, String fileName)
-			throws CoreException, UnsupportedEncodingException, IOException {
-		IFile file = getFile(project, fileName);
-		if (file.isAccessible()) {
-			InputStream contents = file.getContents();
-			final BufferedReader reader = new BufferedReader(
-					new InputStreamReader(contents, file.getCharset()));
-			StringBuffer buffer = new StringBuffer();
-			try {
-				int c = 0;
-				char[] buf = new char[4096];
-				while ((c = reader.read(buf)) > 0) {
-					buffer.append(buf, 0, c);
-				}
-				return buffer.toString();
-			} finally {
-				reader.close();
-			}
-		}
-		return null;
-	}
-
-	private IFile getFile(IProject project, String fileName) throws CoreException {
-		String n = fileName.toLowerCase();
-		IResource[] members = project.members();
-		for (IResource iResource : members) {
-			if (iResource.getType() == IResource.FILE
-					&& n.equals(iResource.getName().toLowerCase())
-					&& iResource.isAccessible()) {
-				return (IFile) iResource;
-			}
-		}
-		return null;
-	}
-
 	private InputStream getPluginResourceStream(IPath path) throws IOException {
 		URL url = FileLocator.find(PreviewerPlugin.getDefault().getBundle(),
 				path, null);
@@ -232,21 +199,44 @@
 	}
 
 	public static IFile getFileFromUrl(String name) {
+		IPath path = getProjectRelativePath(name);
+		if (path != null) {
+			return getProjectResource(path);
+		} else {
+			return null;
+		}
+	}
+
+	private static IPath getProjectRelativePath(String uri) {
+		IPath path = null;
 		try {
 			String root = getHttpUrl(null);
-			IFile file = null;
-			if (name.startsWith(root)) {
-				String fileName = name.substring(root.length());
+			if (uri.startsWith(root)) {
+				String fileName = uri.substring(root.length());
 				fileName = URLDecoder.decode(fileName, "UTF-8");
-				final IPath path = new Path(fileName);
-				file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
-				if (!file.isAccessible()) {
-					return null;
+				path = new Path(fileName);
+				if (path.segmentCount() == 2 && INDEX_PAGE.equals(path.lastSegment())) {
+					IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0));
+					path = new Path(project.getName()).append(CoreUtil.getIndexFileName(CoreUtil.readFile(project, METADATA_FILE)));
 				}
 			}
-			return file;
 		} catch (UnsupportedEncodingException e) {
 			throw new RuntimeException(e);
+		} catch (CoreException e) {
+			PreviewerPlugin.log(e);
+		} catch (IOException e) {
+			PreviewerPlugin.log(e);
+		}
+		return path;
+	}
+
+	private static IFile getProjectResource(IPath path) {
+		IFile file;
+		file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
+		if (!file.isAccessible()) {
+			return null;
+		} else {
+			return file;
 		}
 	}
 
@@ -254,4 +244,30 @@
 		return getServerURIForResource(new Path(widget).append(STARTING_PAGE)
 				.makeAbsolute().toString());
 	}
+
+	public static File getPreviewerResource(String name) {
+		try {
+			IPath path = getProjectRelativePath(name);
+			if (path.segmentCount() == 2 && STARTING_PAGE.equals(path.segment(1))) {
+				path = new Path(PREVIEW_START);
+			} else
+			if (path.segmentCount() > 2 && PREVIEW_PATH.equals(path.segment(1))) {
+				path = path.removeFirstSegments(1);
+			} else {
+				path = null;
+			}
+			if (path != null) {
+				URL pluginResource = FileLocator.find(PreviewerPlugin.getDefault().getBundle(), path, null);
+				if (pluginResource != null) {
+					URL url = FileLocator.toFileURL(pluginResource);
+					if (url != null) {
+						return new File(url.getPath());
+					}
+				}
+			}
+		} catch (IOException e) {
+			PreviewerPlugin.log(e);
+		}
+		return null;
+	}
 }
--- a/org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/util/CoreUtil.java	Fri Feb 05 14:12:27 2010 -0800
+++ b/org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/util/CoreUtil.java	Mon Feb 08 11:14:10 2010 -0800
@@ -1,9 +1,18 @@
 package org.symbian.tools.wrttools.util;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
 import java.text.MessageFormat;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.Region;
@@ -45,4 +54,39 @@
 		}
 		return null;
 	}
+
+	public static IFile getFile(IProject project, String fileName) throws CoreException {
+		String n = fileName.toLowerCase();
+		IResource[] members = project.members();
+		for (IResource iResource : members) {
+			if (iResource.getType() == IResource.FILE
+					&& n.equals(iResource.getName().toLowerCase())
+					&& iResource.isAccessible()) {
+				return (IFile) iResource;
+			}
+		}
+		return null;
+	}
+
+	public static String readFile(IProject project, String fileName)
+			throws CoreException, UnsupportedEncodingException, IOException {
+		IFile file = getFile(project, fileName);
+		if (file.isAccessible()) {
+			InputStream contents = file.getContents();
+			final BufferedReader reader = new BufferedReader(
+					new InputStreamReader(contents, file.getCharset()));
+			StringBuffer buffer = new StringBuffer();
+			try {
+				int c = 0;
+				char[] buf = new char[4096];
+				while ((c = reader.read(buf)) > 0) {
+					buffer.append(buf, 0, c);
+				}
+				return buffer.toString();
+			} finally {
+				reader.close();
+			}
+		}
+		return null;
+	}
 }