In progress: [ Issue 45 ] Protobuf-dt should be able to open files outside workspace
https://code.google.com/p/protobuf-dt/issues/detail?id=45
Initial work. Protobuf-dt now can open files outside the workspace. Outline View is working. Hyperlinking is broken.
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
index a006703..c7b82d9 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -14,12 +14,14 @@
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.xtext.ui.editor.IXtextEditorCallback;
+import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider;
import org.eclipse.xtext.ui.editor.outline.actions.IOutlineContribution;
import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
import com.google.eclipse.protobuf.scoping.IFileUriResolver;
import com.google.eclipse.protobuf.ui.builder.AutoAddNatureEditorCallback;
-import com.google.eclipse.protobuf.ui.editor.ProtobufHyperlinkDetector;
+import com.google.eclipse.protobuf.ui.editor.hyperlinking.ProtobufHyperlinkDetector;
+import com.google.eclipse.protobuf.ui.editor.model.ProtobufDocumentProvider;
import com.google.eclipse.protobuf.ui.outline.LinkWithEditor;
import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage;
import com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferenceStoreInitializer;
@@ -34,6 +36,8 @@
*/
public class ProtobufUiModule extends AbstractProtobufUiModule {
+ public static final String PLUGIN_ID = "com.google.eclipse.protobuf.ui";
+
public ProtobufUiModule(AbstractUIPlugin plugin) {
super(plugin);
}
@@ -73,4 +77,8 @@
public void configureFileUriResolver(Binder binder) {
binder.bind(IFileUriResolver.class).to(FileUriResolver.class);
}
+
+ public void configureDocumentProvider(Binder binder) {
+ binder.bind(XtextDocumentProvider.class).to(ProtobufDocumentProvider.class);
+ }
}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ImportHyperlink.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ImportHyperlink.java
similarity index 92%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ImportHyperlink.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ImportHyperlink.java
index ffcd9c4..93c741d 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ImportHyperlink.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ImportHyperlink.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.editor;
+package com.google.eclipse.protobuf.ui.editor.hyperlinking;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
@@ -53,7 +53,7 @@
private void openFromFileSystem() {
IFileStore fileStore = EFS.getLocalFileSystem().getStore(new Path(importUri.toFileString()));
IEditorInput editorInput = new FileStoreEditorInput(fileStore);
- openFile(editorInput, "org.eclipse.ui.DefaultTextEditor");
+ openFile(editorInput, "com.google.eclipse.protobuf.Protobuf"/*"org.eclipse.ui.DefaultTextEditor"*/);
}
private void openFile(IEditorInput editorInput, String editorId) {
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ProtobufHyperlinkDetector.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
similarity index 98%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ProtobufHyperlinkDetector.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
index 729c483..59a0775 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ProtobufHyperlinkDetector.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/hyperlinking/ProtobufHyperlinkDetector.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.editor;
+package com.google.eclipse.protobuf.ui.editor.hyperlinking;
import static org.eclipse.emf.common.util.URI.createURI;
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java
new file mode 100644
index 0000000..fc3dad8
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/model/ProtobufDocumentProvider.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved. This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.editor.model;
+
+import static com.google.eclipse.protobuf.ui.ProtobufUiModule.PLUGIN_ID;
+import static org.eclipse.core.runtime.IStatus.ERROR;
+import static org.eclipse.emf.common.util.URI.createURI;
+import static org.eclipse.xtext.validation.CheckMode.FAST_ONLY;
+
+import java.io.*;
+import java.net.URI;
+
+import org.eclipse.core.filesystem.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.ide.FileStoreEditorInput;
+import org.eclipse.xtext.parser.IParseResult;
+import org.eclipse.xtext.parser.IParser;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.ui.editor.model.XtextDocument;
+import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider;
+import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionProvider;
+import org.eclipse.xtext.ui.editor.validation.AnnotationIssueProcessor;
+import org.eclipse.xtext.ui.editor.validation.ValidationJob;
+import org.eclipse.xtext.util.StringInputStream;
+import org.eclipse.xtext.validation.IResourceValidator;
+
+import com.google.eclipse.protobuf.ui.util.Closeables;
+import com.google.inject.Inject;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ProtobufDocumentProvider extends XtextDocumentProvider {
+
+ private static final String ENCODING = "UTF-8";
+
+ @Inject private Closeables closeables;
+ @Inject private IssueResolutionProvider issueResolutionProvider;
+ @Inject private IParser parser;
+ @Inject private IResourceValidator resourceValidator;
+
+ @Override protected ElementInfo createElementInfo(Object element) throws CoreException {
+ if (element instanceof FileStoreEditorInput) {
+ FileStoreEditorInput input = (FileStoreEditorInput) element;
+ IDocument document = null;
+ IStatus status = null;
+ try {
+ document = createDocument(element);
+ } catch (CoreException e) {
+ handleCoreException(e, "ProtobufDocumentProvider.createElementInfo");
+ document = createEmptyDocument();
+ status = e.getStatus();
+ }
+ IFileStore store = EFS.getLocalFileSystem().getStore(fileFrom(input).toURI());
+ IFileInfo fileInfo = store.fetchInfo();
+ IAnnotationModel model = createAnnotationModel(element);
+ // new FileSynchronizer(input).install();
+ FileInfo info = new FileInfo(document, model, null);
+ info.fModificationStamp = fileInfo.getLastModified();
+ info.fStatus = status;
+ info.fEncoding = ENCODING;
+ cacheEncodingState(element);
+ XtextDocument xtextDocument = (XtextDocument) document;
+ AnnotationIssueProcessor annotationIssueProcessor = new AnnotationIssueProcessor(xtextDocument, model,
+ issueResolutionProvider);
+ ValidationJob job = new ValidationJob(resourceValidator, xtextDocument, annotationIssueProcessor, FAST_ONLY);
+ xtextDocument.setValidationJob(job);
+ return info;
+ }
+ return super.createElementInfo(element);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IDocument createDocument(Object element) throws CoreException {
+ if (element instanceof FileStoreEditorInput) {
+ XtextDocument document = createEmptyDocument();
+ FileStoreEditorInput input = (FileStoreEditorInput) element;
+ File file = fileFrom(input);
+ XtextResource resource = new XtextResource(createURI(file.toURI().toString()));
+ try {
+ String contents = contentsOf(file);
+ document.set(contents);
+ IParseResult result = parser.parse(new InputStreamReader(new StringInputStream(contents), ENCODING));
+ resource.getContents().add(result.getRootASTElement());
+ document.setInput(resource);
+ return document;
+ } catch (Throwable t) {
+ if (t instanceof CoreException) throw (CoreException) t;
+ throw wrapWithCoreException(t);
+ }
+ }
+ return super.createDocument(element);
+ }
+
+ private File fileFrom(IURIEditorInput input) {
+ URI uri = input.getURI();
+ String scheme = uri.getScheme();
+ if (scheme != "file") {
+ String cleanUri = uri.toString().replaceFirst(scheme, "file");
+ uri = URI.create(cleanUri);
+ }
+ return new File(uri);
+ }
+
+ private String contentsOf(File file) throws CoreException {
+ Reader reader = null;
+ InputStream contentStream = null;
+ try {
+ contentStream = new FileInputStream(file);
+ reader = new BufferedReader(new InputStreamReader(contentStream, ENCODING), DEFAULT_FILE_SIZE);
+ StringBuilder contents = new StringBuilder(DEFAULT_FILE_SIZE);
+ char[] buffer = new char[2048];
+ int character = reader.read(buffer);
+ while (character > 0) {
+ contents.append(buffer, 0, character);
+ character = reader.read(buffer);
+ }
+ return contents.toString();
+ } catch (IOException e) {
+ throw wrapWithCoreException(e);
+ } finally {
+ if (!closeables.close(reader)) closeables.close(contentStream);
+ }
+ }
+
+ private CoreException wrapWithCoreException(Throwable cause) {
+ return new CoreException(new Status(ERROR, PLUGIN_ID, messageOf(cause), cause));
+ }
+
+ private String messageOf(Throwable t) {
+ String message = t.getMessage();
+ return (message != null) ? message : "";
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java
index 02460b7..c9aa6e2 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectorySelectionDialogs.java
@@ -8,6 +8,7 @@
*/
package com.google.eclipse.protobuf.ui.preferences.paths;
+import static com.google.eclipse.protobuf.ui.ProtobufUiModule.PLUGIN_ID;
import static com.google.eclipse.protobuf.ui.swt.Messages.*;
import static org.eclipse.core.runtime.IStatus.ERROR;
import static org.eclipse.core.runtime.Status.OK_STATUS;
@@ -17,9 +18,12 @@
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.*;
-import org.eclipse.ui.dialogs.*;
-import org.eclipse.ui.model.*;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
+import org.eclipse.ui.dialogs.ISelectionStatusValidator;
+import org.eclipse.ui.model.WorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator;
/**
@@ -29,8 +33,6 @@
*/
class DirectorySelectionDialogs {
- private static final String PLUGIN_ID = "com.google.eclipse.protobuf.ui";
-
static String showWorkspaceDirectoryDialog(Shell shell, String initialPath) {
return showWorkspaceDirectoryDialog(shell, initialPath, null);
}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java
new file mode 100644
index 0000000..4abef77
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/Closeables.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved. This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import com.google.inject.Singleton;
+
+/**
+ * Utility methods related to <code>{@link Closeable}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton
+public class Closeables {
+
+ public boolean close(Closeable c) {
+ if (c == null) return false;
+ try {
+ c.close();
+ } catch (IOException ignored) {}
+ return true;
+ }
+}