Fixed: [Issue 208] 'stream' element not displaying correctly in Outline
View
diff --git a/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Images_imageFor_Test.java b/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Images_imageFor_Test.java
index 87a8d9d..9d5ef56 100644
--- a/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Images_imageFor_Test.java
+++ b/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Images_imageFor_Test.java
@@ -199,6 +199,22 @@
   }
 
   // syntax = "proto2";
+  //
+  // message Person {}
+  //
+  // message Type {}
+  //
+  // service PersonService {
+  //   stream PersonStream (Person, Type);
+  // }
+  @Test public void should_return_image_for_stream() {
+    Stream stream = xtext.findFirst(Stream.class);
+    String image = images.imageFor(stream);
+    assertThat(image, equalTo("stream.gif"));
+    assertThat(image, existsInProject());
+  }
+
+  // syntax = "proto2";
   @Test public void should_return_image_for_syntax() {
     Syntax syntax = xtext.findFirst(Syntax.class);
     String image = images.imageFor(syntax);
diff --git a/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Labels_labelFor_Test.java b/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Labels_labelFor_Test.java
index 1d2f097..3b6ebc0 100644
--- a/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Labels_labelFor_Test.java
+++ b/com.google.eclipse.protobuf.ui.functional.test/src/com/google/eclipse/protobuf/ui/labeling/Labels_labelFor_Test.java
@@ -183,6 +183,64 @@
 
   // syntax = "proto2";
   //
+  // service PersonService {}
+  @Test public void should_return_label_for_service() {
+    Service service = xtext.findFirst(Service.class);
+    Object label = labels.labelFor(service);
+    assertThat(label, instanceOf(String.class));
+    String labelText = (String) label;
+    assertThat(labelText, equalTo("PersonService"));
+  }
+
+  // syntax = "proto2";
+  //
+  // message Person {}
+  //
+  // message Type {}
+  //
+  // service PersonService {
+  //   stream PersonStream (Person, Type);
+  // }
+  @Test public void should_return_label_for_stream() {
+    Stream stream = xtext.findFirst(Stream.class);
+    Object label = labels.labelFor(stream);
+    assertThat(label, instanceOf(StyledString.class));
+    StyledString labelText = (StyledString) label;
+    assertThat(labelText.getString(), equalTo("PersonStream (Person, Type)"));
+  }
+
+  // syntax = "proto2";
+  //
+  // message Type {}
+  //
+  // service PersonService {
+  //   stream PersonStream (Person, Type);
+  // }
+  @Test public void should_return_label_for_stream_with_unresolved_client_message() {
+    Stream stream = xtext.findFirst(Stream.class);
+    Object label = labels.labelFor(stream);
+    assertThat(label, instanceOf(StyledString.class));
+    StyledString labelText = (StyledString) label;
+    assertThat(labelText.getString(), equalTo("PersonStream (<unresolved>, Type)"));
+  }
+
+  // syntax = "proto2";
+  //
+  // message Person {}
+  //
+  // service PersonService {
+  //   stream PersonStream (Person, Type);
+  // }
+  @Test public void should_return_label_for_stream_with_unresolved_server_message() {
+    Stream stream = xtext.findFirst(Stream.class);
+    Object label = labels.labelFor(stream);
+    assertThat(label, instanceOf(StyledString.class));
+    StyledString labelText = (StyledString) label;
+    assertThat(labelText.getString(), equalTo("PersonStream (Person, <unresolved>)"));
+  }
+
+  // syntax = "proto2";
+  //
   // message Person {}
   //
   // extend Person {}
diff --git a/com.google.eclipse.protobuf.ui/icons/stream.gif b/com.google.eclipse.protobuf.ui/icons/stream.gif
new file mode 100644
index 0000000..7134210
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/icons/stream.gif
Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Images.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Images.java
index 22204a6..df6c575 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Images.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Images.java
@@ -33,7 +33,8 @@
   private static final Set<String> IMAGES = newHashSet();
   static {
     addImages(OPTIONAL, REPEATED, REQUIRED);
-    addImages(ENUM, TYPE_EXTENSION, EXTENSIONS, GROUP, IMPORT, LITERAL, MESSAGE, OPTION, PACKAGE, RPC, SERVICE, SYNTAX);
+    addImages(ENUM, TYPE_EXTENSION, EXTENSIONS, GROUP, IMPORT, LITERAL, MESSAGE, OPTION, PACKAGE, RPC, SERVICE, STREAM,
+        SYNTAX);
     addImages("imports", "options");
   }
 
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Labels.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Labels.java
index 03898aa..7bbe755 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Labels.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/labeling/Labels.java
@@ -57,6 +57,10 @@
       Rpc rpc = (Rpc) o;
       return labelFor(rpc);
     }
+    if (o instanceof Stream) {
+      Stream stream = (Stream) o;
+      return labelFor(stream);
+    }
     if (o instanceof TypeExtension) {
       TypeExtension extension = (TypeExtension) o;
       return labelFor(extension);
@@ -132,12 +136,19 @@
 
   private Object labelFor(Rpc rpc) {
     StyledString text = new StyledString(nameResolver.nameOf(rpc));
-    String types = String.format(" : %s > %s", messageName(rpc.getArgType()), messageName(rpc.getReturnType()));
+    String types = String.format(" : %s > %s", nameOf(rpc.getArgType()), nameOf(rpc.getReturnType()));
     text.append(types, DECORATIONS_STYLER);
     return text;
   }
 
-  private String messageName(MessageLink link) {
+  private Object labelFor(Stream stream) {
+    StyledString text = new StyledString(nameResolver.nameOf(stream));
+    String types = String.format(" (%s, %s)", nameOf(stream.getClientMessage()), nameOf(stream.getServerMessage()));
+    text.append(types, DECORATIONS_STYLER);
+    return text;
+  }
+
+  private String nameOf(MessageLink link) {
     return nameOf(link.getTarget());
   }
 
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java
index 3a383f1..92fa32c 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/outline/ProtobufOutlineTreeProvider.java
@@ -27,23 +27,14 @@
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class ProtobufOutlineTreeProvider extends DefaultOutlineTreeProvider {
-  private static final ImmutableList<Class<? extends EObject>> IGNORED_ELEMENT_TYPES = of(BooleanLink.class,
-      FieldOption.class, MessageLink.class);
+  private static final ImmutableList<Class<? extends EObject>> IGNORED_ELEMENT_TYPES =
+      of(BooleanLink.class, FieldOption.class, MessageLink.class);
 
-  boolean _isLeaf(Extensions extensions) {
-    return true;
-  }
+  private static final ImmutableList<Class<? extends EObject>> LEAF_TYPES =
+      of(Extensions.class, Import.class, MessageField.class, Option.class, Package.class, Stream.class);
 
-  boolean _isLeaf(MessageField field) {
-    return true;
-  }
-
-  boolean _isLeaf(Option option) {
-    return true;
-  }
-
-  boolean _isLeaf(Package aPackage) {
-    return true;
+  @Override protected boolean _isLeaf(EObject e) {
+    return isInstanceOfAny(e, LEAF_TYPES);
   }
 
   protected void _createChildren(DocumentRootNode parent, Protobuf protobuf) {
@@ -68,16 +59,20 @@
     }
   }
 
-  @Override protected void createNode(IOutlineNode parent, EObject modelElement) {
-    if (isIgnored(modelElement)) {
+  @Override protected void createNode(IOutlineNode parent, EObject e) {
+    if (isIgnored(e)) {
       return;
     }
-    super.createNode(parent, modelElement);
+    super.createNode(parent, e);
   }
 
-  private boolean isIgnored(EObject modelElement) {
-    for (Class<? extends EObject> ignoredType : IGNORED_ELEMENT_TYPES) {
-      if (ignoredType.isInstance(modelElement)) {
+  private boolean isIgnored(EObject e) {
+    return isInstanceOfAny(e, IGNORED_ELEMENT_TYPES);
+  }
+
+  private boolean isInstanceOfAny(EObject e, List<Class<? extends EObject>> types) {
+    for (Class<? extends EObject> type : types) {
+      if (type.isInstance(e)) {
         return true;
       }
     }