Merge: Document the doc/ directory
authorJean Privat <jean@pryen.org>
Fri, 28 Nov 2014 01:58:27 +0000 (20:58 -0500)
committerJean Privat <jean@pryen.org>
Fri, 28 Nov 2014 01:58:27 +0000 (20:58 -0500)
The directory is empty except an outdated README.
So, maybe not the best user-experience for people that look for documentation and naively open the `doc/` directory...

So update the README and offer a `Makefile` to generate something in the directory.

Pull-Request: #942
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

26 files changed:
contrib/jwrapper/src/code_generator.nit
examples/calculator/Makefile
examples/calculator/art/icon.svg [new file with mode: 0644]
examples/calculator/src/calculator_android.nit [new file with mode: 0644]
lib/a_star.nit
lib/android/examples/Makefile [new file with mode: 0644]
lib/android/examples/art/icon.svg [new file with mode: 0644]
lib/android/examples/src/ui_test.nit [new file with mode: 0644]
lib/android/native_app_glue.nit
lib/android/notification/native_notification.nit [new file with mode: 0644]
lib/android/notification/notification.nit [new file with mode: 0644]
lib/android/toast.nit [new file with mode: 0644]
lib/android/ui.nit [new file with mode: 0644]
lib/cpp.nit
lib/emscripten.nit
lib/gpio.nit
lib/hash_debug.nit
lib/libevent.nit
lib/more_collections.nit
lib/mpi.nit
lib/ordered_tree.nit
lib/pipeline.nit
lib/poset.nit
lib/privileges.nit
lib/sqlite3/sqlite3.nit
lib/standard/collection/abstract_collection.nit

index 8192855..45ce666 100644 (file)
@@ -221,7 +221,7 @@ class CodeGenerator
 
                # FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it
                if comment == "#" then
-                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                # Methods with return type
                else if return_type != null then
                        if jreturn_type.is_primitive_array then
@@ -238,7 +238,7 @@ class CodeGenerator
                                temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, true))
                        # No copy
                        else
-                               temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+                               temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                        end
                # Methods without return type
                else if jreturn_type.is_void then
@@ -247,11 +247,11 @@ class CodeGenerator
                                temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, false))
                        # No copy
                        else
-                               temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+                               temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                        end
                # No copy
                else
-                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+                       temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
                end
 
                return temp.join("")
index 9782660..acb600b 100644 (file)
@@ -1,3 +1,8 @@
 all:
        mkdir -p bin/
-       ../../bin/nitg --dir bin/ src/calculator_test.nit src/calculator_gtk.nit
+       ../../bin/nitg --dir bin/ src/calculator_gtk.nit src/calculator_test.nit
+
+android:
+       mkdir -p bin/ res/
+       ../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+       ../../bin/nitg -o bin/calculator.apk src/calculator_android.nit
diff --git a/examples/calculator/art/icon.svg b/examples/calculator/art/icon.svg
new file mode 100644 (file)
index 0000000..ccd533c
--- /dev/null
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="512"
+   height="512"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="icon.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.9899495"
+     inkscape:cx="58.64005"
+     inkscape:cy="380.00465"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1601"
+     inkscape:window-height="1316"
+     inkscape:window-x="2646"
+     inkscape:window-y="84"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-540.36218)">
+    <rect
+       style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2987"
+       width="500"
+       height="500"
+       x="5.9999847"
+       y="546.36218"
+       rx="64"
+       ry="64" />
+    <rect
+       ry="48"
+       rx="48"
+       y="569.2193"
+       x="32.42857"
+       height="211.42856"
+       width="211.42856"
+       id="rect2989"
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2991"
+       width="211.42856"
+       height="211.42856"
+       x="268.14285"
+       y="569.2193"
+       rx="48"
+       ry="48" />
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2993"
+       width="211.42856"
+       height="211.42856"
+       x="32.42857"
+       y="806.36218"
+       rx="48"
+       ry="48" />
+    <rect
+       ry="48"
+       rx="48"
+       y="806.36218"
+       x="268.14285"
+       height="211.42856"
+       width="211.42856"
+       id="rect2995"
+       style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+    <text
+       xml:space="preserve"
+       style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       x="299.74573"
+       y="770.06946"
+       id="text2997"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan2999"
+         x="299.74573"
+         y="770.06946">+</tspan></text>
+    <path
+       inkscape:connector-curvature="0"
+       id="path3018"
+       style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="m 313.14886,921.9317 0,-19.71047 121.41654,0 0,19.71047"
+       sodipodi:nodetypes="cccc" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path2995"
+       style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="m 170.83821,674.43965 c -1e-4,11.65624 -0.8562,22.0941 -2.56831,31.31363 -1.64645,9.21961 -4.34646,17.02331 -8.10005,23.41114 -3.68792,6.38786 -8.46234,11.26106 -14.32328,14.61962 -5.86108,3.35856 -12.97332,5.03783 -21.33673,5.03784 -7.77084,-10e-6 -14.5538,-1.67928 -20.34892,-5.03784 -5.729341,-3.35856 -10.50376,-8.23176 -14.323274,-14.61962 -3.753702,-6.38783 -6.585427,-14.19153 -8.495182,-23.41114 -1.843926,-9.21953 -2.765883,-19.65739 -2.765873,-31.31363 -10e-6,-11.6561 0.823166,-22.09397 2.46953,-31.31364 1.712193,-9.21946 4.379282,-16.99024 8.001275,-23.31236 3.687807,-6.38772 8.4293,-11.26092 14.224494,-14.61961 5.86097,-3.35842 12.94028,-5.0377 21.23795,-5.03784 7.83658,1.4e-4 14.65247,1.67942 20.4477,5.03784 5.79508,3.29284 10.60243,8.13311 14.42206,14.52083 3.81944,6.32212 6.68409,14.09289 8.59396,23.31236 1.90967,9.21967 2.86455,19.69047 2.86465,31.41242 m -73.9871,0 c -2.8e-5,9.87818 0.493877,18.50506 1.481718,25.88067 0.987781,7.3757 2.568282,13.53305 4.741492,18.47208 2.17315,4.87322 5.00488,8.56105 8.49518,11.06349 3.55608,2.43662 7.86952,3.65492 12.94034,3.6549 5.07071,2e-5 9.38415,-1.21828 12.94033,-3.6549 3.55605,-2.43658 6.45363,-6.09148 8.69275,-10.96471 2.30481,-4.87317 3.95116,-10.9976 4.93906,-18.3733 1.05358,-7.44146 1.58041,-16.1342 1.5805,-26.07823 -9e-5,-9.87804 -0.52692,-18.50492 -1.5805,-25.88068 -0.9879,-7.37555 -2.63425,-13.49998 -4.93906,-18.3733 -2.23912,-4.87308 -5.1367,-8.52798 -8.69275,-10.96471 -3.55618,-2.43647 -7.86962,-3.65477 -12.94033,-3.6549 -5.07082,1.3e-4 -9.38426,1.21843 -12.94034,3.6549 -3.4903,2.43673 -6.32203,6.09163 -8.49518,10.96471 -2.17321,4.87332 -3.753711,10.99775 -4.741492,18.3733 -0.987841,7.37576 -1.481746,16.00264 -1.481718,25.88068" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path2997"
+       style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="m 179.68975,735.88154 c -1e-5,-2.50244 0.32926,-4.60977 0.98782,-6.32199 0.65852,-1.77805 1.54755,-3.19391 2.66709,-4.2476 1.1195,-1.11949 2.43658,-1.90974 3.95125,-2.37074 1.51462,-0.52681 3.16097,-0.79023 4.93905,-0.79025 1.71218,2e-5 3.32561,0.26344 4.84028,0.79025 1.58047,0.461 2.93048,1.25125 4.05003,2.37074 1.11948,1.05369 2.00851,2.46955 2.66709,4.2476 0.65851,1.71222 0.98778,3.81955 0.98782,6.32199 -4e-5,2.43661 -0.32931,4.54394 -0.98782,6.322 -0.65858,1.71221 -1.54761,3.12807 -2.66709,4.24759 -1.11955,1.11952 -2.46956,1.94269 -4.05003,2.46953 -1.51467,0.52683 -3.1281,0.79024 -4.84028,0.79025 -1.77808,-10e-6 -3.42443,-0.26342 -4.93905,-0.79025 -1.51467,-0.52684 -2.83175,-1.35001 -3.95125,-2.46953 -1.11954,-1.11952 -2.00857,-2.53538 -2.66709,-4.24759 -0.65856,-1.77806 -0.98783,-3.88539 -0.98782,-6.322" />
+    <text
+       xml:space="preserve"
+       style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       x="64.031456"
+       y="1006.8839"
+       id="text3013"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3015"
+         x="64.031456"
+         y="1006.8839">=</tspan></text>
+  </g>
+</svg>
diff --git a/examples/calculator/src/calculator_android.nit b/examples/calculator/src/calculator_android.nit
new file mode 100644 (file)
index 0000000..e66fea8
--- /dev/null
@@ -0,0 +1,108 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Android calculator application
+module calculator_android is
+       app_name "app.nit Calc."
+       app_version(0, 1, git_revision)
+       java_package "org.nitlanguage.calculator"
+
+       # Use a translucent background and lock in portrait mode
+       android_manifest_activity """
+               android:theme="@android:style/Theme.Holo.Wallpaper"
+               android:screenOrientation="portrait""""
+end
+
+import android
+import android::ui
+
+import calculator_logic
+
+redef class App
+       private var context = new CalculatorContext
+
+       # The main display, at the top of the screen
+       private var display: EditText
+
+       # Maps operators as `String` to their `Button`
+       private var op2but = new HashMap[String, Button]
+
+       # Has this window been initialized?
+       private var inited = false
+
+       redef fun init_window
+       do
+               super
+
+               if inited then return
+               inited = true
+
+               # Setup UI
+               var context = native_activity
+               var layout = new NativeLinearLayout(context)
+               layout.set_vertical
+
+               # Display screen
+               var display = new EditText
+               layout.add_view_with_weight(display.native, 1.0)
+               display.text_size = 36.0
+               self.display = display
+
+               # Buttons; numbers and operators
+               var ops = [["7", "8", "9", "+"],
+                          ["4", "5", "6", "-"],
+                          ["1", "2", "3", "*"],
+                          ["0", ".", "C", "/"],
+                          ["="]]
+
+               for line in ops do
+                       var buts_layout = new NativeLinearLayout(context)
+                       buts_layout.set_horizontal
+                       layout.add_view_with_weight(buts_layout, 1.0)
+
+                       for op in line do
+                               var but = new Button
+                               but.text = op
+                               but.text_size = 40
+                               buts_layout.add_view_with_weight(but.native, 1.0)
+                               op2but[op] = but
+                       end
+               end
+
+               context.content_view = layout
+       end
+
+       redef fun catch_event(event)
+       do
+               if event isa ClickEvent then
+                       var sender = event.sender
+                       var op = sender.text
+
+                       if op == "." then
+                               sender.enabled = false
+                               context.switch_to_decimals
+                       else if op.is_numeric then
+                               var n = op.to_i
+                               context.push_digit n
+                       else
+                               op2but["."].enabled = true
+                               context.push_op op.chars.first
+                       end
+
+                       display.text = context.display_text
+               end
+       end
+end
index 4108268..97925ff 100644 (file)
@@ -57,14 +57,14 @@ module a_star
 
 # General graph node
 class Node
+       # Type of the others nodes in the `graph`
        type N: Node
 
        # parent graph
        var graph: Graph[N, Link]
 
-       init(graph: Graph[N, Link])
+       init
        do
-               self.graph = graph
                graph.add_node(self)
        end
 
@@ -186,29 +186,36 @@ end
 
 # Link between two nodes and associated to a graph
 class Link
+       # Type of the nodes in `graph`
        type N: Node
+
+       # Type of the other links in `graph`
        type L: Link
 
+       # The graph to which belongs `self`
        var graph: Graph[N, L]
 
+       # Origin of this link
        var from: N
+
+       # Endpoint of this link
        var to: N
 
-       init(graph: Graph[N, L], from, to: N)
+       init
        do
-               self.graph = graph
-               self.from = from
-               self.to = to
-
                graph.add_link(self)
        end
 end
 
 # General graph
 class Graph[N: Node, L: Link]
+       # Nodes in this graph
        var nodes: Set[N] = new HashSet[N]
+
+       # Links in this graph
        var links: Set[L] = new HashSet[L]
 
+       # Add a `node` to this graph
        fun add_node(node: N): N
        do
                nodes.add(node)
@@ -216,6 +223,7 @@ class Graph[N: Node, L: Link]
                return node
        end
 
+       # Add a `link` to this graph
        fun add_link(link: L): L
        do
                links.add(link)
@@ -225,20 +233,22 @@ class Graph[N: Node, L: Link]
                return link
        end
 
-       # used to check if nodes have been searched in one pathfinding
-       var pathfinding_current_evocation: Int = 0
+       # Used to check if nodes have been searched in one pathfinding
+       private var pathfinding_current_evocation: Int = 0
 end
 
-# Result from pathfinding, a walkable path
+# Result from path finding and a walkable path
 class Path[N]
 
+       # The total cost of this path
        var total_cost: Int
 
+       # The list of nodes composing this path
        var nodes = new List[N]
 
-       init (cost: Int) do total_cost = cost
+       private var at: Int = 0
 
-       var at: Int = 0
+       # Step on the path and get the next node to travel
        fun step: N
        do
                assert nodes.length >= at else print "a_star::Path::step failed, is at_end_of_path"
@@ -249,16 +259,22 @@ class Path[N]
                return s
        end
 
+       # Peek at the next step of the path
        fun peek_step: N do return nodes[at]
 
+       # Are we at the end of this path?
        fun at_end_of_path: Bool do return at >= nodes.length
 end
 
 # Context related to an evocation of pathfinding
 class PathContext
+       # Type of the nodes in `graph`
        type N: Node
+
+       # Type of the links in `graph`
        type L: Link
 
+       # Graph to which is associated `self`
        var graph: Graph[N, L]
 
        # Worst cost of all the link's costs
@@ -273,6 +289,7 @@ class PathContext
        # Heuristic
        fun heuristic_cost(a, b: N): Int is abstract
 
+       # The worst cost suggested by the heuristic
        fun worst_heuristic_cost: Int is abstract
 end
 
@@ -292,12 +309,13 @@ class ConstantPathContext
        redef fun worst_heuristic_cost do return 0
 end
 
+# A `PathContext` for graphs with `WeightedLink`
 class WeightedPathContext
        super PathContext
 
        redef type L: WeightedLink
 
-       init(graph: Graph[N, L])
+       init
        do
                super
 
@@ -309,7 +327,7 @@ class WeightedPathContext
                self.worst_cost = worst_cost
        end
 
-       redef var worst_cost: Int
+       redef var worst_cost: Int is noinit
 
        redef fun cost(l) do
                return l.weight
@@ -319,17 +337,12 @@ class WeightedPathContext
        redef fun worst_heuristic_cost do return 0
 end
 
+# A `Link` with a `weight`
 class WeightedLink
        super Link
 
+       # The `weight`, or cost, of this link
        var weight: Int
-
-       init(graph: Graph[N, L], from, to: N, weight: Int)
-       do
-               super
-
-               self.weight = weight
-       end
 end
 
 # Advanced path conditions with customizable accept states
diff --git a/lib/android/examples/Makefile b/lib/android/examples/Makefile
new file mode 100644 (file)
index 0000000..5255657
--- /dev/null
@@ -0,0 +1,11 @@
+android:
+       mkdir -p bin/ res/
+       ../../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+       ../../../bin/nitg --dir bin/ src/ui_test.nit
+       adb install -r bin/ui_test.apk
+
+install: android
+       adb install -r bin/ui.apk
+
+clean:
+       rm -rf bin
diff --git a/lib/android/examples/art/icon.svg b/lib/android/examples/art/icon.svg
new file mode 100644 (file)
index 0000000..fb46e63
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="512"
+   height="512"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="icon.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="309.32788"
+     inkscape:cy="302.66563"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1311"
+     inkscape:window-height="960"
+     inkscape:window-x="3037"
+     inkscape:window-y="440"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-540.36218)">
+    <path
+       style="font-size:320.10992432px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-55.78796005px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       d="M 116.09375,542.95593 C 95.970238,546.76157 75.866352,550.69664 55.75,554.54968 37.271066,654.48453 18.600595,754.38392 0.1875,854.33093 c 4.5670667,-0.0224 11.88925,-3.92217 14.989244,-1.88564 2.348097,12.30965 6.527711,24.13426 7.951802,36.55472 4.55774,23.64215 8.603147,47.44405 14.058954,70.86217 20.446729,-3.97475 40.892439,-7.95532 61.34375,-11.90625 0.806348,-6.01877 0.340643,-13.9623 0.6875,-18.84375 5.52874,12.6291 21.06261,15.98721 33.375,12.9375 18.4814,-4.95238 37.89007,-7.63966 56.75,-11.59375 -0.61826,-2.8783 4.8827,-0.79167 7.02749,-1.68038 14.16686,-1.03878 27.37606,-6.02271 41.41001,-7.38212 46.67851,-52.63829 -1.21449,-16.83212 30.65625,78.40625 17.19389,35.71392 58.70592,54.88142 97.40613,52.07812 21.55059,0.3486 43.28622,-5.5501 61.25012,-17.3281 0,7.9479 0,15.8958 0,23.8437 12.8637,-12.8518 32.06959,-10.4444 48.6875,-10.5625 12.08275,-0.4504 26.74579,-3.3417 33.09375,-14.75 2.84788,-8.0897 -0.35571,-16.9124 0.875,-25.25 0,-68.40622 0,-136.81247 0,-205.21872 -12.80081,2.58433 -25.80422,3.15955 -39,2.65625 -4.49542,-0.0745 -2.70343,-6.71819 -9.375,-2.8125 -14.41967,4.34039 -29.68137,2.22535 -44.53125,3.3125 -1.97068,-10.5394 -3.89878,-21.08667 -5.875,-31.625 43.54527,5.39974 90.52353,-22.98463 100.5,-66.625 11.74182,-45.53602 0.57063,-96.29858 -28.34375,-133 -18.76502,-21.52312 -47.96855,-34.21533 -76.77629,-30.338 -17.82405,1.69881 -35.28672,8.34732 -49.69246,18.74425 -12.97547,-7.86574 -27.99494,0.14323 -41.46466,1.78058 -8.5847,1.6356 -17.16935,3.2715 -25.75409,4.90692 2.25786,4.53438 -2.9589,1.63366 -5.28125,1.90625 -24.37251,-2.08163 -49.75835,4.12727 -69.28125,18.9375 -12.98942,-8.01584 -28.14096,-0.0134 -41.65179,1.65749 -7.26996,1.39739 -14.54254,2.78105 -21.81696,4.15501 C 140.087,578.41196 128.739,560.57354 117.4375,542.70593 l -0.98313,0.18291 z"
+       id="path3034"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc" />
+    <text
+       transform="matrix(1.0172511,-0.19643198,0.1830023,0.94770357,0,0)"
+       sodipodi:linespacing="125%"
+       id="text2999"
+       y="843.55823"
+       x="-121.33073"
+       style="font-size:338.93121338px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:-0.06177186px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;letter-spacing:-59.06808853px;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+         y="843.55823"
+         x="-121.33073"
+         id="tspan3001"
+         sodipodi:role="line">App</tspan></text>
+    <text
+       transform="matrix(1.0172511,-0.19643198,0.1830023,0.94770357,0,0)"
+       xml:space="preserve"
+       style="font-size:171.81326294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="-132.6741"
+       y="958.20111"
+       id="text3003"
+       sodipodi:linespacing="125%"><tspan
+         style="letter-spacing:-22.57948303px"
+         sodipodi:role="line"
+         id="tspan3005"
+         x="-132.6741"
+         y="958.20111">nit</tspan></text>
+    <text
+       transform="scale(1.0360431,0.96521081)"
+       sodipodi:linespacing="125%"
+       id="text3007"
+       y="1056.8173"
+       x="253.55678"
+       style="font-size:265.30044556px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="1056.8173"
+         x="253.55678"
+         id="tspan3009"
+         sodipodi:role="line"
+         style="letter-spacing:-34.865448px">UI</tspan></text>
+  </g>
+</svg>
diff --git a/lib/android/examples/src/ui_test.nit b/lib/android/examples/src/ui_test.nit
new file mode 100644 (file)
index 0000000..f6c2a1b
--- /dev/null
@@ -0,0 +1,91 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for app.nit's UI services
+module ui_test is
+       app_name("app.nit UI test")
+       app_version(0, 1, git_revision)
+       java_package("org.nitlanguage.ui_test")
+       android_manifest_activity """android:theme="@android:style/Theme.Light""""
+end
+
+import android
+import android::ui
+import android::toast
+import android::notification
+
+redef class App
+
+       var but_notif: Button
+       var but_toast: Button
+
+       var notif: nullable Notification = null
+
+       var inited = false
+       redef fun init_window
+       do
+               super
+
+               if inited then return
+               inited = true
+
+               # Setup UI
+               var context = native_activity
+               var layout = new NativeLinearLayout(context)
+               layout.set_vertical
+
+               but_notif = new Button
+               but_notif.text = "Show Notification"
+               layout.add_view but_notif.native
+
+               but_toast = new Button
+               but_toast.text = "Show Toast"
+               layout.add_view but_toast.native
+
+               context.content_view = layout
+       end
+
+       fun act_notif
+       do
+               var notif = self.notif
+               if notif == null then
+                       notif = new Notification("From app.nit", "Some content...")
+                       notif.ticker = "Ticker text..."
+                       notif.show
+                       self.notif = notif
+               else
+                       notif.cancel
+                       self.notif = null
+               end
+       end
+
+       fun act_toast
+       do
+               toast("Sample toast from app.nit at {get_time}", false)
+       end
+
+       redef fun catch_event(event)
+       do
+               if event isa ClickEvent then
+                       var sender = event.sender
+                       if sender == but_notif then
+                               act_notif
+                       else if sender == but_toast then
+                               act_toast
+                       end
+               end
+       end
+end
index 50368de..fc5a19f 100644 (file)
@@ -114,12 +114,22 @@ in "C body" `{
        }
 `}
 
+# An Android activity context
+extern class NativeContext in "Java" `{ android.content.Context `}
+       super JavaObject
+end
+
+# A wrapper of context
+extern class NativeContextWrapper in "Java" `{ android.content.ContextWrapper `}
+       super NativeContext
+end
+
 # Android SDK's `android.app.NativeActivity`.
 #
 # Can be used to get anything related to the `Context` of the activity in Java
 # and as anchor to execute Java UI code.
 extern class NativeActivity in "Java" `{ android.app.NativeActivity `}
-       super JavaObject
+       super NativeContextWrapper
 end
 
 redef class App
@@ -252,11 +262,11 @@ extern class NdkNativeActivity `{ ANativeActivity * `}
        # The `NativeActivity`, as in the Java object, associated to `self`
        fun java_native_activity: NativeActivity `{ return recv->clazz; `}
 
-       # Path to this application's internal data directory.
+       # Path to this application's internal data directory.
        fun internal_data_path: NativeString `{ return (char*)recv->internalDataPath; `}
     
        # Path to this application's external (removable/mountable) data directory.
-       fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `}
+       fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `}
     
        # The platform's SDK version code.
        fun sdk_version: Int `{ return recv->sdkVersion; `}
diff --git a/lib/android/notification/native_notification.nit b/lib/android/notification/native_notification.nit
new file mode 100644 (file)
index 0000000..988727f
--- /dev/null
@@ -0,0 +1,71 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Native Java classes for notifications
+module native_notification is min_api_version 11
+
+import android::assets_and_resources
+
+in "Java" `{
+       import android.content.Context;
+       import android.app.NotificationManager;
+       import android.app.Notification;
+`}
+
+redef class NativeActivity
+       fun notification_manager: NativeNotificationManager in "Java" `{
+               return (NotificationManager)recv.getSystemService(Context.NOTIFICATION_SERVICE);
+       `}
+end
+
+extern class NativeNotificationManager in "Java" `{ android.app.NotificationManager `}
+
+       fun notify(tag: JavaString, id: Int, notif: NativeNotification) in "Java" `{
+               recv.notify(tag, (int)id, notif);
+       `}
+
+       fun cancel(tag: JavaString, id: Int) in "Java" `{ recv.cancel(tag, (int)id); `}
+
+       fun cancel_all in "Java" `{ recv.cancelAll(); `}
+end
+
+extern class NativeNotification in "Java" `{ android.app.Notification `}
+end
+
+extern class NativeNotificationBuilder in "Java" `{ android.app.Notification$Builder `}
+
+       new (context: NativeActivity) in "Java" `{ return new Notification.Builder(context); `}
+
+       fun create: NativeNotification in "Java" `{
+               // Deprecated since API 16, which introduces `build`,
+               // refinement and global compilation should prevent warnings.
+               return recv.getNotification();
+       `}
+
+       fun title=(value: JavaString) in "Java" `{ recv.setContentTitle(value); `}
+
+       fun text=(value: JavaString) in "Java" `{ recv.setContentText(value); `}
+
+       fun ticker=(value: JavaString) in "Java" `{ recv.setTicker(value); `}
+
+       fun small_icon=(value: Int) in "Java" `{ recv.setSmallIcon((int)value); `}
+
+       fun auto_cancel=(value: Bool) in "Java" `{ recv.setAutoCancel(value); `}
+
+       fun number=(value: Int) in "Java" `{ recv.setNumber((int)value); `}
+
+       fun ongoing=(value: Bool) in "Java" `{ recv.setOngoing(value); `}
+end
diff --git a/lib/android/notification/notification.nit b/lib/android/notification/notification.nit
new file mode 100644 (file)
index 0000000..07d1c00
--- /dev/null
@@ -0,0 +1,132 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to show notification in the Android status bar
+#
+# ~~~~
+# # Create and show a notification
+# var notif = new Notification("My Title", "Some content")
+# notif.ticker = "Ticker text"
+# notif.show
+#
+# # Update the notification
+# notif.text = "New content!"
+# notif.ongoing = true # Make it un-dismissable
+# nofif.show
+#
+# # Hide the notification
+# notif.cancel
+# ~~~~
+#
+# For more information, see:
+# http://developer.android.com/guide/topics/ui/notifiers/notifications.html
+module notification
+
+import standard
+private import native_notification
+
+# An Android notification, shown at the top of the screen
+class Notification
+       # Title of this notification
+       var title: nullable Text is writable
+
+       # Text content of this notification
+       var text: nullable Text is writable
+
+       # Text to show in the bar as the notification appears
+       var ticker: nullable Text = null is writable
+
+       # Name of a resource found in the `res/drawable-*` folders to use for the small icon
+       #
+       # By default, we use the app's icon, named "icon". A valid icon must be used
+       # to display notifications.
+       var small_icon: nullable Text = null is writable
+
+       # Number to display on the bottom right part of the notification
+       var number: nullable Int = null is writable
+
+       # Is this notification ongoing? Not user dismissable.
+       var ongoing: Bool = false is writable
+
+       private var id: nullable Int = null
+       private var tag = "app.nit notification"
+
+       # Show the notification
+       fun show
+       do
+               sys.jni_env.push_local_frame(8)
+
+               var context = app.native_activity
+               var builder = new NativeNotificationBuilder(context)
+
+               # If no custom icon is specified, use app's
+               var small_icon = self.small_icon
+               if small_icon == null then small_icon = "icon"
+               var small_icon_id = app.resource_manager.other_id(small_icon.to_s, "drawable")
+               builder.small_icon = small_icon_id
+
+               # Other options
+               if title != null then builder.title = title.to_java_string
+               if text != null then builder.text = text.to_java_string
+               if ticker != null then builder.ticker = ticker.to_java_string
+               builder.ongoing = ongoing
+
+               var notif = builder.create
+               var manager = context.notification_manager
+
+               var id = self.id
+               if id == null then id = sys.next_notification_id
+               manager.notify(tag.to_java_string, id, notif)
+
+               self.id = id
+
+               sys.jni_env.pop_local_frame
+       end
+
+       # Was this notification shown with `show`?
+       #
+       # This does not indicates whether is has been dismissed or not. Only that
+       # it was shown at least once.
+       private fun was_shown: Bool do return id != null
+
+       # Cancel this notification and hide it if it is currently displayed
+       fun cancel
+       do
+               var id = self.id
+               if id != null then
+                       sys.jni_env.push_local_frame(8)
+
+                       var manager = app.native_activity.notification_manager
+                       manager.cancel(tag.to_java_string, id)
+
+                       self.id = null
+
+                       sys.jni_env.pop_local_frame
+               end
+       end
+end
+
+redef class Sys
+       private var next_notification_id_cache = 0
+
+       # Returns a unique ID for new notifications
+       private fun next_notification_id: Int
+       do
+               var id = next_notification_id_cache
+               next_notification_id_cache = id + 1
+               return id
+       end
+end
diff --git a/lib/android/toast.nit b/lib/android/toast.nit
new file mode 100644 (file)
index 0000000..dd8e149
--- /dev/null
@@ -0,0 +1,49 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to display a _toast_, a small popup on Android
+module toast
+
+import native_app_glue
+
+in "Java" `{
+       import android.widget.Toast;
+`}
+
+redef class App
+       # Display a _toast_ with `message`, for longer if `is_long`
+       fun toast(message: String, is_long: Bool)
+       do
+               var jstr = message.to_java_string
+               native_toast(jstr, is_long)
+               jstr.delete_local_ref
+       end
+
+       private fun native_toast(message: JavaString, is_long: Bool)
+       import native_activity in "Java" `{
+               final android.app.NativeActivity context = App_native_activity(recv);
+               final CharSequence final_message = message;
+               final int duration = is_long? Toast.LENGTH_LONG: Toast.LENGTH_SHORT;
+
+               context.runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               Toast toast = Toast.makeText(context, final_message, duration);
+                               toast.show();
+                       }
+               });
+       `}
+end
diff --git a/lib/android/ui.nit b/lib/android/ui.nit
new file mode 100644 (file)
index 0000000..b4ed822
--- /dev/null
@@ -0,0 +1,417 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Views and services to use the Android native user interface
+#
+# Events, such as a button click, come from the UI thread and are then
+# passed to the main thread. It is recommended to specialize one of the
+# methods of the main thread to customize the response to a given event.
+#
+# This graph shows the path of a button click:
+# ~~~
+#     UI Thread     #   Main thread
+#
+#       User
+#        |
+#        V
+# Button::click_ui --> Button::click
+#                           |
+#                           V
+#                    App::catch_event
+# ~~~
+module ui is min_api_version 14
+
+import native_app_glue
+import pthreads::concurrent_collections
+
+in "Java" `{
+       import android.app.NativeActivity;
+
+       import android.view.Gravity;
+       import android.view.MotionEvent;
+       import android.view.ViewGroup;
+       import android.view.ViewGroup.MarginLayoutParams;
+
+       import android.widget.Button;
+       import android.widget.LinearLayout;
+       import android.widget.GridLayout;
+       import android.widget.PopupWindow;
+       import android.widget.TextView;
+
+       import java.lang.*;
+       import java.util.*;
+`}
+
+# An event from the `app.nit` framework
+interface AppEvent
+       # Reaction to this event
+       fun react do end
+end
+
+# A control click event
+class ClickEvent
+       super AppEvent
+
+       # Sender of this event
+       var sender: Button
+
+       redef fun react do sender.click self
+end
+
+# Receiver of events not handled directly by the sender
+interface EventCatcher
+       fun catch_event(event: AppEvent) do end
+end
+
+redef class App
+       super EventCatcher
+
+       # Queue of events to be received by the main thread
+       var event_queue = new ConcurrentList[AppEvent]
+
+       # Call `react` on all `AppEvent` available in `event_queue`
+       protected fun loop_on_ui_callbacks
+       do
+               var queue = event_queue
+               while not queue.is_empty do
+                       var event = queue.pop
+                       event.react
+               end
+       end
+
+       redef fun run
+       do
+               loop
+                       # Process Android events
+                       poll_looper 100
+
+                       # Process app.nit events
+                       loop_on_ui_callbacks
+               end
+       end
+end
+
+redef extern class NativeActivity
+
+       # Fill this entire `NativeActivity` with `popup`
+       #
+       # This is a workaround for the use on `takeSurface` in `NativeActivity.java`
+       #
+       # TODO replace NativeActivity by our own NitActivity
+       private fun dedicate_to_popup(popup: NativePopupWindow, popup_layout: NativeViewGroup) in "Java" `{
+               final LinearLayout final_main_layout = new LinearLayout(recv);
+               final ViewGroup final_popup_layout = popup_layout;
+               final PopupWindow final_popup = popup;
+               final NativeActivity final_recv = recv;
+
+               recv.runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               MarginLayoutParams params = new MarginLayoutParams(
+                                       LinearLayout.LayoutParams.MATCH_PARENT,
+                                       LinearLayout.LayoutParams.MATCH_PARENT);
+
+                               final_recv.setContentView(final_main_layout, params);
+
+                               final_popup.showAtLocation(final_popup_layout, Gravity.TOP, 0, 40);
+                       }
+               });
+       `}
+
+       # Set the main layout of this activity
+       fun content_view=(layout: NativeViewGroup)
+       do
+               var popup = new NativePopupWindow(self)
+               popup.content_view = layout
+               dedicate_to_popup(popup, layout)
+       end
+
+       # Set the real content view of this activity, without hack
+       #
+       # TODO bring use this instead of the hack with `dedicate_to_pupup`
+       private fun real_content_view=(layout: NativeViewGroup) in "Java" `{
+               final ViewGroup final_layout = layout;
+               final NativeActivity final_recv = recv;
+
+               recv.runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               final_recv.setContentView(final_layout);
+
+                               final_layout.requestFocus();
+                       }
+               });
+       `}
+end
+
+# An `Object` that raises events
+abstract class Eventful
+       var event_catcher: EventCatcher = app is lazy, writable
+end
+
+#
+## Nity classes and services
+#
+
+# An Android control with text
+abstract class TextView
+       super Finalizable
+       super Eventful
+
+       # Native Java variant to this Nity class
+       type NATIVE: NativeTextView
+
+       # The native Java object encapsulated by `self`
+       var native: NATIVE is noinit
+
+       # Get the text of this view
+       fun text: String
+       do
+               var jstr = native.text
+               var str = jstr.to_s
+               jstr.delete_local_ref
+               return str
+       end
+
+       # Set the text of this view
+       fun text=(value: Text)
+       do
+               var jstr = value.to_s.to_java_string
+               native.text = jstr
+               jstr.delete_local_ref
+       end
+
+       # Get whether this view is enabled or not
+       fun enabled: Bool do return native.enabled
+
+       # Set if this view is enabled
+       fun enabled=(val: Bool) do native.enabled = val
+
+       # Set the size of the text in this view at `dpi`
+       fun text_size=(dpi: Numeric) do native.text_size = dpi.to_f
+
+       private var finalized = false
+       redef fun finalize
+       do
+               if not finalized then
+                       native.delete_global_ref
+                       finalized = true
+               end
+       end
+end
+
+# An Android button
+class Button
+       super TextView
+
+       redef type NATIVE: NativeButton
+
+       init
+       do
+               var native = new NativeButton(app.native_activity, app.event_queue, self)
+               self.native = native.new_global_ref
+       end
+
+       # Click event on the Main thread
+       #
+       # By default, this method calls `app.catch_event`. It can be specialized
+       # with custom behavior or the receiver of `catch_event` can be changed
+       # with `event_catcher=`.
+       fun click(event: AppEvent) do event_catcher.catch_event(event)
+
+       # Click event on the UI thread
+       #
+       # This method is called on the UI thread and redirects the event to `click`
+       # throught `App::event_queue`. In most cases, you should implement `click`
+       # and leave `click_ui` as is.
+       fun click_ui do app.event_queue.add(new ClickEvent(self))
+end
+
+# An Android editable text field
+class EditText
+       super TextView
+
+       redef type NATIVE: NativeEditText
+
+       init
+       do
+               var native = new NativeEditText(app.native_activity)
+               self.native = native.new_global_ref
+       end
+end
+
+#
+## Native classes
+#
+
+# A `View` for Android
+extern class NativeView in "Java" `{ android.view.View `}
+       super JavaObject
+
+       fun minimum_width=(val: Int) in "Java" `{ recv.setMinimumWidth((int)val); `}
+       fun minimum_height=(val: Int) in "Java" `{ recv.setMinimumHeight((int)val); `}
+end
+
+# A collection of `NativeView`
+extern class NativeViewGroup in "Java" `{ android.view.ViewGroup `}
+       super NativeView
+
+       fun add_view(view: NativeView) in "Java" `{ recv.addView(view); `}
+end
+
+# A `NativeViewGroup` organized in a line
+extern class NativeLinearLayout in "Java" `{ android.widget.LinearLayout `}
+       super NativeViewGroup
+
+       new(context: NativeActivity) in "Java" `{ return new LinearLayout(context); `}
+
+       fun set_vertical in "Java" `{ recv.setOrientation(LinearLayout.VERTICAL); `}
+       fun set_horizontal in "Java" `{ recv.setOrientation(LinearLayout.HORIZONTAL); `}
+
+       redef fun add_view(view) in "Java"
+       `{
+               MarginLayoutParams params = new MarginLayoutParams(
+                       LinearLayout.LayoutParams.MATCH_PARENT,
+                       LinearLayout.LayoutParams.WRAP_CONTENT);
+               recv.addView(view, params);
+       `}
+
+       fun add_view_with_weight(view: NativeView, weight: Float)
+       in "Java" `{
+               recv.addView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, (float)weight));
+       `}
+end
+
+# A `NativeViewGroup` organized as a grid
+extern class NativeGridLayout in "Java" `{ android.widget.GridLayout `}
+       super NativeViewGroup
+
+       new(context: NativeActivity) in "Java" `{ return new android.widget.GridLayout(context); `}
+
+       fun row_count=(val: Int) in "Java" `{ recv.setRowCount((int)val); `}
+
+       fun column_count=(val: Int) in "Java" `{ recv.setColumnCount((int)val); `}
+
+       redef fun add_view(view) in "Java" `{ recv.addView(view); `}
+end
+
+extern class NativePopupWindow in "Java" `{ android.widget.PopupWindow `}
+       super NativeView
+
+       new (context: NativeActivity) in "Java" `{
+               PopupWindow recv = new PopupWindow(context);
+               recv.setWindowLayoutMode(LinearLayout.LayoutParams.MATCH_PARENT,
+                       LinearLayout.LayoutParams.MATCH_PARENT);
+               recv.setClippingEnabled(false);
+               return recv;
+       `}
+
+       fun content_view=(layout: NativeViewGroup) in "Java" `{ recv.setContentView(layout); `}
+end
+
+extern class NativeTextView in "Java" `{ android.widget.TextView `}
+       super NativeView
+
+       new (context: NativeActivity) in "Java" `{ return new TextView(context); `}
+
+       fun text: JavaString in "Java" `{ return recv.getText().toString(); `}
+
+       fun text=(value: JavaString) in "Java" `{
+
+               android.util.Log.d("Nity", "1");
+               final TextView final_recv = recv;
+               final String final_value = value;
+
+               android.util.Log.d("Nity", "4");
+               ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               android.util.Log.d("Nity", "-5");
+                               android.util.Log.d("Nity", final_value);
+                               android.util.Log.d("Nity", "-5.5");
+                               final_recv.setText(final_value);
+                               android.util.Log.d("Nity", "-6");
+                       }
+               });
+               android.util.Log.d("Nity", "7");
+       `}
+
+       fun enabled: Bool in "Java" `{ return recv.isEnabled(); `}
+       fun enabled=(value: Bool) in "Java" `{
+               final TextView final_recv = recv;
+               final boolean final_value = value;
+
+               ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() {
+                       @Override
+                       public void run()  {
+                               final_recv.setEnabled(final_value);
+                       }
+               });
+       `}
+
+       fun gravity_center in "Java" `{
+               recv.setGravity(Gravity.CENTER);
+       `}
+
+       fun text_size=(dpi: Float) in "Java" `{
+               recv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_DIP, (float)dpi);
+       `}
+end
+
+extern class NativeEditText in "Java" `{ android.widget.EditText `}
+       super NativeTextView
+
+       redef type SELF: NativeEditText
+
+       new (context: NativeActivity) in "Java" `{ return new android.widget.EditText(context); `}
+
+       fun width=(val: Int) in "Java" `{ recv.setWidth((int)val); `}
+
+       fun input_type_text in "Java" `{ recv.setInputType(android.text.InputType.TYPE_CLASS_TEXT); `}
+
+       redef fun new_global_ref: SELF import sys, Sys.jni_env `{
+               Sys sys = NativeEditText_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, recv);
+       `}
+end
+
+extern class NativeButton in "Java" `{ android.widget.Button `}
+       super NativeTextView
+
+       redef type SELF: NativeButton
+
+       new (context: NativeActivity, queue: ConcurrentList[AppEvent], sender_object: Object) import Button.click_ui in "Java" `{
+               final int final_sender_object = sender_object;
+
+               return new Button(context){
+                       @Override
+                       public boolean onTouchEvent(MotionEvent event) {
+                               if(event.getAction() == MotionEvent.ACTION_DOWN) {
+                                       Button_click_ui(final_sender_object);
+                                       return true;
+                               }
+                               return false;
+                       }
+               };
+       `}
+
+       redef fun new_global_ref: SELF import sys, Sys.jni_env `{
+               Sys sys = NativeButton_sys(recv);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, recv);
+       `}
+end
index 3d4daf6..6fe897a 100644 (file)
@@ -23,12 +23,14 @@ end
 extern class CppString in "C++" `{ std::string* `}
 end
 
-redef class String
-       fun to_cpp_string: CppString do return to_cstring.to_cpp_string
+redef class Text
+       # Get `self` as a `CppString`
+       fun to_cpp_string: CppString do return to_cstring.to_cpp_string(length)
 end
 
 redef class NativeString
-       fun to_cpp_string: CppString in "C++" `{
-               return new std::string(recv);
+       # Get `self` as a `CppString`
+       fun to_cpp_string(length: Int): CppString in "C++" `{
+               return new std::string(recv, length);
        `}
 end
index d46f4d1..3fd2fff 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Platform for the _emscripten_ framework
+#
+# Importing this module from your project will tell _nitg_ to compile
+# to JavaScript for the _emscripten_ framework.
 module emscripten is platform
 
 `{
@@ -21,12 +25,16 @@ module emscripten is platform
        #include <gc.h>
 `}
 
-redef class String
+redef class Text
+       # Run `self` as JavaScript code
        fun run_js do run_js_native(self.escape_to_js.to_cstring)
+
        private fun run_js_native(script: NativeString) `{ emscripten_run_script(script); `}
 
-       fun escape_to_js: String do return self.replace('\n', "\\n")
+       # Escape the content of `self` to pass to JavaScript code
+       fun escape_to_js: Text do return replace('\n', "\\n")
 
+       # Raise a JavaScript alert
        fun alert do "alert('{self.escape_to_js}')".run_js
 end
 
index 820f608..cea53cb 100644 (file)
@@ -17,6 +17,8 @@
 # GPIO related functionnalities
 module gpio
 
+# A physical binary pin
 interface Pin
+       # Set the output of this pin
        fun write(high: Bool) is abstract
 end
index 8426097..1626437 100644 (file)
@@ -136,7 +136,7 @@ redef class HashCollection[K]
        # Count and update length of collisions for `node_at_idx`
        # Note for dynamic call-graph analysis: callers of this functions are
        # responsible of collisions.
-       private fun gt_collide(i: Int, k: K)
+       fun gt_collide(i: Int, k: K)
        do
                var c = _array[i]
                sys.gt_coll += 1
@@ -159,7 +159,7 @@ redef class HashCollection[K]
        # Count and update length of collisions for `store`
        # Note for dynamic call-graph analysis: callers of this functions are
        # responsible of collisions.
-       private fun st_collide(i: Int, n: N)
+       fun st_collide(i: Int, n: N)
        do
                var c = _array[i]
                sys.st_coll += 1
index 525915c..9ff7ed0 100644 (file)
@@ -92,8 +92,9 @@ extern class NativeEventBase `{ struct event_base * `}
 
        # Create a new event_base to use with the rest of Libevent
        new `{ return event_base_new(); `}
+
+       # Has `self` been correctly initialized?
        fun is_valid: Bool do return not address_is_null
-       #fun creation_ok
 
        # Event dispatching loop
        #
@@ -154,7 +155,7 @@ class Connection
        # Write a string to the connection
        fun write(str: String)
        do
-               var res = native_buffer_event.write(str.to_cstring, str.length)
+               native_buffer_event.write(str.to_cstring, str.length)
        end
 
        # Write a file to the connection
@@ -175,6 +176,7 @@ end
 
 # A buffer event structure, strongly associated to a connection, an input buffer and an output_buffer
 extern class NativeBufferEvent `{ struct bufferevent * `}
+       # Write `length` bytes of `line`
        fun write(line: NativeString, length: Int): Int `{
                return bufferevent_write(recv, line, length);
        `}
@@ -205,6 +207,7 @@ extern class NativeEvBuffer `{ struct evbuffer * `}
        fun length: Int `{ return evbuffer_get_length(recv); `}
 end
 
+# An input buffer
 extern class InputNativeEvBuffer
        super NativeEvBuffer
 
@@ -212,6 +215,7 @@ extern class InputNativeEvBuffer
        fun drain(length: Int) `{ evbuffer_drain(recv, length); `}
 end
 
+# An output buffer
 extern class OutputNativeEvBuffer
        super NativeEvBuffer
 
@@ -270,6 +274,7 @@ end
 
 # Factory to listen on sockets and create new `Connection`
 class ConnectionFactory
+       # The `NativeEventBase` for the dispatch loop of this factory
        var event_base: NativeEventBase
 
        # On new connection, create the handler `Connection` object
index bd441a1..1bcc514 100644 (file)
@@ -48,13 +48,19 @@ class MultiHashMap[K: Object, V]
                self[key] = res
                return res
        end
-
-       init do end
 end
 
 # Simple way to store an `HashMap[K1, HashMap[K2, V]]`
+#
+# ~~~~
+# var hm2 = new HashMap2[Int, String, Float]
+# hm2[1, "one"] = 1.0
+# hm2[2, "two"] = 2.0
+# assert hm2[1, "one"] == 1.0
+# assert hm2[2, "not-two"] == null
+# ~~~~
 class HashMap2[K1: Object, K2: Object, V]
-       private var level1: HashMap[K1, HashMap[K2, V]] = new HashMap[K1, HashMap[K2, V]]
+       private var level1 = new HashMap[K1, HashMap[K2, V]]
 
        # Return the value associated to the keys `k1` and `k2`.
        # Return `null` if no such a value.
@@ -83,8 +89,16 @@ class HashMap2[K1: Object, K2: Object, V]
 end
 
 # Simple way to store an `HashMap[K1, HashMap[K2, HashMap[K3, V]]]`
+#
+# ~~~~
+# var hm3 = new HashMap3[Int, String, Int, Float]
+# hm3[1, "one", 11] = 1.0
+# hm3[2, "two", 22] = 2.0
+# assert hm3[1, "one", 11] == 1.0
+# assert hm3[2, "not-two", 22] == null
+# ~~~~
 class HashMap3[K1: Object, K2: Object, K3: Object, V]
-       private var level1: HashMap[K1, HashMap2[K2, K3, V]] = new HashMap[K1, HashMap2[K2, K3, V]]
+       private var level1 = new HashMap[K1, HashMap2[K2, K3, V]]
 
        # Return the value associated to the keys `k1`, `k2`, and `k3`.
        # Return `null` if no such a value.
@@ -112,6 +126,45 @@ class HashMap3[K1: Object, K2: Object, K3: Object, V]
 end
 
 # A map with a default value.
+#
+# ~~~~
+# var dm = new DefaultMap[String, Int](10)
+# assert dm["a"] == 10
+# ~~~~
+#
+# The default value is used when the key is not present.
+# And getting a default value does not register the key.
+#
+# ~~~~
+# assert dm["a"] == 10
+# assert dm.length == 0
+# assert dm.has_key("a") == false
+# ~~~~
+#
+# It also means that removed key retrieve the default value.
+#
+# ~~~~
+# dm["a"] = 2
+# assert dm["a"] == 2
+# dm.keys.remove("a")
+# assert dm["a"] == 10
+# ~~~~
+#
+# Warning: the default value is used as is, so using mutable object might
+# cause side-effects.
+#
+# ~~~~
+# var dma = new DefaultMap[String, Array[Int]](new Array[Int])
+#
+# dma["a"].add(65)
+# assert dma["a"] == [65]
+# assert dma.default == [65]
+# assert dma["c"] == [65]
+#
+# dma["b"] += [66]
+# assert dma["b"] == [65, 66]
+# assert dma.default == [65]
+# ~~~~
 class DefaultMap[K: Object, V]
        super HashMap[K, V]
 
index 20ff9af..1d8c406 100644 (file)
@@ -123,26 +123,34 @@ class MPI
                return deserialized
        end
 
+       # Send an empty buffer, only for the `tag`
        fun send_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError
        `{
                return MPI_Send(NULL, 0, MPI_CHAR, dest, tag, comm);
        `}
 
+       # Receive an empty buffer, only for the `tag`
        fun recv_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError
        `{
                return MPI_Recv(NULL, 0, MPI_CHAR, dest, tag, comm, MPI_STATUS_IGNORE);
        `}
 
-       fun native_send(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError
+       # Send a `NativeCArray` `buffer` with a given `count` of `data_type`
+       fun native_send(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError
        `{
-               return MPI_Send(data, count, data_type, dest, tag, comm);
+               return MPI_Send(buffer, count, data_type, dest, tag, comm);
        `}
 
-       fun native_recv(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
+       # Receive into a `NativeCArray` `buffer` with a given `count` of `data_type`
+       fun native_recv(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
        `{
-               return MPI_Recv(data, count, data_type, dest, tag, comm, status);
+               return MPI_Recv(buffer, count, data_type, dest, tag, comm, status);
        `}
 
+       # Probe for the next data to receive, store the result in `status`
+       #
+       # Note: If you encounter an error where the next receive does not correspond
+       # to the last `probe`, call this method twice to ensure a correct result.
        fun probe(source: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
        `{
                return MPI_Probe(source, tag, comm, status);
@@ -157,8 +165,13 @@ end
 
 # An MPI communicator
 extern class Comm `{ MPI_Comm `}
+       # The _null_ communicator, targeting no processors
        new null_ `{ return MPI_COMM_NULL; `}
+
+       # The _world_ communicator, targeting all processors
        new world `{ return MPI_COMM_WORLD; `}
+
+       # The _self_ communicator, targeting this processor only
        new self_ `{ return MPI_COMM_SELF; `}
 
        # Number of processors in this communicator
@@ -278,6 +291,7 @@ end
 
 # An MPI rank within a communcator
 extern class Rank `{ int `}
+       # Special rank accepting any processor
        new any `{ return MPI_ANY_SOURCE; `}
 
        # This Rank as an `Int`
@@ -287,6 +301,7 @@ end
 
 # An MPI tag, can be defined using `Int::tag`
 extern class Tag `{ int `}
+       # Special tag accepting any tag
        new any `{ return MPI_ANY_TAG; `}
 
        # This tag as an `Int`
index 34ca522..5c42f46 100644 (file)
@@ -21,24 +21,57 @@ module ordered_tree
 #
 # Ordered tree are tree where the elements of a same parent are in a specific order
 #
-# The class can be used as it to work with generic tree.
-# The class can also be specialized to provide more specific behavior.
+# Elements of the trees are added with the `add` method that takes a parent and
+# a sub-element.
+# If the parent is `null`, then the element is considered a root.
+#
+# ~~~~
+# var t = new OrderedTree[String]
+# t.add(null, "root")
+# t.add("root", "child1")
+# t.add("root", "child2")
+# t.add("child1", "grand-child")
+# assert t.length == 4
+# ~~~~
+#
+# By default, the elements with a same parent
+# are visited in the order they are added.
+#
+# ~~~
+# assert t.to_a == ["root", "child1", "grand-child", "child2"]
+# assert t.write_to_string == """
+# root
+# |--child1
+# |  `--grand-child
+# `--child2
+# """
+# ~~~
+#
+# The `sort_with` method can be used reorder elements
+#
+# ~~~
+# t.add("root", "aaa")
+# assert t.to_a == ["root", "child1", "grand-child", "child2", "aaa"]
+# t.sort_with(alpha_comparator)
+# assert t.to_a == ["root", "aaa", "child1", "grand-child", "child2"]
+# ~~~
+#
+# This class can be used as it to work with generic trees but can also be specialized to provide more specific
+# behavior or display. It is why the internal attributes are mutable.
 class OrderedTree[E: Object]
        super Streamable
        super Collection[E]
 
-       # Sequence
+       # The roots of the tree (in sequence)
        var roots = new Array[E]
+
+       # The branches of the trees.
+       # For each element, the ordered array of its direct sub-elements.
        var sub = new HashMap[E, Array[E]]
 
-       # Add a new element `e` in the tree
+       # Add a new element `e` in the tree.
        # `p` is the parent of `e`.
        # if `p` is null, then `e` is a root element.
-       #
-       # By defauld, the elements with a same parent 
-       # are displayed in the order they are added.
-       #
-       # The `sort_with` method can be used reorder elements
        fun add(p: nullable E, e: E)
        do
                if p == null then
@@ -54,7 +87,6 @@ class OrderedTree[E: Object]
        # Write a ASCII-style tree and use the `display` method to label elements
        redef fun write_to(stream: OStream)
        do
-               var last = roots.last
                for r in roots do
                        stream.write display(r)
                        stream.write "\n"
index 31d007b..be553ad 100644 (file)
@@ -14,9 +14,8 @@
 
 # Pipelined filters and operations on iterators.
 #
-# This module enhance `Iterator`s with some methods that enable a
-# pipeline-like programing that offers the manupulation of
-# collections trough connected filters with reasonable memory constraints.
+# This module enhances `Iterator` with some methods that enable a pipeline-like programing.
+# The processing of elements in a pipeline is done trough connected filters that are implemented with reasonable memory constraints.
 module pipeline
 
 redef interface Iterator[E]
@@ -35,6 +34,8 @@ redef interface Iterator[E]
 
        # Filter: sort with a given `comparator`.
        # Important: require O(n) memory.
+       #
+       #    assert ["a", "c", "b"].iterator.sort_with(alpha_comparator).to_a  == ["a", "b", "c"]
        fun sort_with(comparator: Comparator): Iterator[E]
        do
                var a = self.to_a
index 9549e48..c6fd1d2 100644 (file)
 # Pre order sets and partial order set (ie hierarchies)
 module poset
 
-# Preorder set graph.
-# This class modelize an incremental preorder graph where new node and edges can be added (but no removal)
-# Preorder graph has two caracteristics:
+# Pre-order set graph.
+# This class models an incremental pre-order graph where new nodes and edges can be added (but not removed).
+# Pre-order graph has two characteristics:
 #  * reflexivity: an element is in relation with itself (ie `self.has(e) implies self.has_edge(e,e)`)
 #  * transitivity: `(self.has_edge(e,f) and self.has_edge(f,g)) implies self.has_edge(e,g)`
+#
+# Nodes and edges are added to the POSet.
+#
+# ~~~
+# var pos = new POSet[String]
+# pos.add_edge("A", "B") # add A->B
+# pos.add_edge("B", "C") # add B->C
+# pos.add_node("D") # add unconnected node "D"
+#
+# # A -> B -> C    D
+#
+# assert pos.has_edge("A", "B") == true  # direct
+# ~~~
+#
+# Since a poset is transitive, direct and indirect edges are considered by default.
+# Direct edges (transitive-reduction) can also be considered independently.
+#
+# ~~~
+# assert pos.has_edge("A", "C") == true  # indirect
+# assert pos.has_edge("A", "D") == false # no edge
+# assert pos.has_edge("B", "A") == false # edges are directed
+#
+# assert pos.has_direct_edge("A", "B") == true  # direct
+# assert pos.has_direct_edge("A", "C") == false # indirect
+# ~~~
+#
+# POSet are dynamic.
+# It means that the transitivity is updated while new nodes and edges are added.
+# The transitive-reduction (*direct edges*)) is also updated,
+# so adding new edges can make some direct edge to disappear.
+#
+# ~~~
+# pos.add_edge("A","D")
+# pos.add_edge("D","B")
+# pos.add_edge("A","E")
+# pos.add_edge("E","C")
+#
+# # A -> D -> B
+# # |         |
+# # v         v
+# # E ------> C
+#
+# assert pos.has_edge("D", "C") == true # new indirect edge
+# assert pos.has_edge("A", "B") == true # still an edge
+# assert pos.has_direct_edge("A", "B") == false  # but no-more a direct one
+# ~~~
+#
+# Thanks to the `[]` method, elements can be considered relatively to the poset.
+# SEE `POSetElement`
 class POSet[E: Object]
        super Collection[E]
        super Comparator
@@ -31,7 +80,7 @@ class POSet[E: Object]
        redef fun iterator do return elements.keys.iterator
 
        # All the nodes
-       private var elements: HashMap[E, POSetElement[E]] = new HashMap[E, POSetElement[E]]
+       private var elements = new HashMap[E, POSetElement[E]]
 
        redef fun has(e) do return self.elements.keys.has(e)
 
@@ -50,14 +99,15 @@ class POSet[E: Object]
        end
 
        # Return a view of `e` in the poset.
-       # This allows to asks manipulate elements in thier relation with others elements.
+       # This allows to view the elements in their relation with others elements.
        #
-       #     var poset: POSet[Something] # ...
-       #     for x in poset do
-       #         for y in poset[x].direct_greaters do
-       #             print "{x} -> {y}"
-       #         end
-       #     end
+       #     var poset = new POSet[String]
+       #     poset.add_chain(["A", "B", "D"])
+       #     poset.add_chain(["A", "C", "D"])
+       #     var a = poset["A"]
+       #     assert a.direct_greaters.has_exactly(["B", "C"])
+       #     assert a.greaters.has_exactly(["A", "B", "C", "D"])
+       #     assert a.direct_smallers.is_empty
        #
        # REQUIRE: has(e)
        fun [](e: E): POSetElement[E]
@@ -69,9 +119,18 @@ class POSet[E: Object]
        # Add an edge from `f` to `t`.
        # Because a POSet is transitive, all transitive edges are also added to the graph.
        # If the edge already exists, the this function does nothing.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_edge("A", "B") # add A->B
+       # assert pos.has_edge("A", "C") == false
+       # pos.add_edge("B", "C") # add B->C
+       # assert pos.has_edge("A", "C") == true
+       # ~~~
+       #
        # If a reverse edge (from `t` to `f`) already exists, a loop is created.
        #
-       # FIXME: Do somethind clever to manage loops.
+       # FIXME: Do something clever to manage loops.
        fun add_edge(f, t: E)
        do
                var fe = add_node(f)
@@ -108,8 +167,38 @@ class POSet[E: Object]
                te.dfroms.add f
        end
 
+       # Add an edge between all elements of `es` in order.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos.has_direct_edge("A", "B")
+       # assert pos.has_direct_edge("B", "C")
+       # assert pos.has_direct_edge("C", "D")
+       # ~~~~
+       fun add_chain(es: SequenceRead[E])
+       do
+               if es.is_empty then return
+               var i = es.iterator
+               var e = i.item
+               i.next
+               for f in i do
+                       add_edge(e, f)
+                       e = f
+               end
+       end
+
        # Is there an edge (transitive or not) from `f` to `t`?
+       #
+       # SEE: `add_edge`
+       #
        # Since the POSet is reflexive, true is returned if `f == t`.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_node("A")
+       # assert pos.has_edge("A", "A") == true
+       # ~~~
        fun has_edge(f,t: E): Bool
        do
                if not elements.keys.has(f) then return false
@@ -118,6 +207,15 @@ class POSet[E: Object]
        end
 
        # Is there a direct edge from `f` to `t`?
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C"]) # add A->B->C
+       # assert pos.has_direct_edge("A", "B") == true
+       # assert pos.has_direct_edge("A", "C") == false
+       # assert pos.has_edge("A", "C")        == true
+       # ~~~
+       #
        # Note that because of loops, the result may not be the expected one.
        fun has_direct_edge(f,t: E): Bool
        do
@@ -163,12 +261,32 @@ class POSet[E: Object]
        end
 
        # Compare two elements in an arbitrary total order.
-       # Tis function is mainly used to sort elements of the set in an arbitrary linear extension.
-       # if a<b then return -1
-       # if a>b then return 1
+       #
+       # This function is mainly used to sort elements of the set in an coherent way.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D", "E"])
+       # pos.add_chain(["A", "X", "C", "Y", "E"])
+       # var a = ["X", "C", "E", "A", "D"]
+       # pos.sort(a)
+       # assert a == ["E", "D", "C", "X", "A"]
+       # ~~~~
+       #
+       # POSet are not necessarily total orders because some distinct elements may be incomparable (neither greater or smaller).
+       # Therefore this method relies on arbitrary linear extension.
+       # This linear extension is a lawful total order (transitive, anti-symmetric, reflexive, and total), so can be used to compare the elements.
+       #
+       # The abstract behavior of the method is thus the following:
+       #
+       # ~~~~nitish
        # if a == b then return 0
-       # else return -1 or 1
-       # The total order is stable unless a new node or a new edge is added
+       # if has_edge(b, a) then return -1
+       # if has_edge(a, b) then return 1
+       # return -1 or 1 # according to the linear extension.
+       # ~~~~
+       #
+       # Note that the linear extension is stable, unless a new node or a new edge is added.
        redef fun compare(a, b: E): Int
        do
                var ae = self.elements[a]
@@ -203,6 +321,8 @@ class POSet[E: Object]
                return res
        end
 
+       # Filter elements to return only the greatest ones
+       #
        # ~~~
        # var s = new POSet[String]
        # s.add_edge("B", "A")
@@ -213,7 +333,6 @@ class POSet[E: Object]
        # assert s.select_greatest(["A", "B", "C"]) == ["A"]
        # assert s.select_greatest(["B", "C", "D"]) == ["B", "C"]
        # ~~~
-       # Filter elements to return only the greatest ones
        fun select_greatest(elements: Collection[E]): Array[E]
        do
                var res = new Array[E]
@@ -228,6 +347,13 @@ class POSet[E: Object]
        end
 
        # Sort a sorted array of poset elements using linearization order
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D", "E"])
+       # pos.add_chain(["A", "X", "C", "Y", "E"])
+       # var a = pos.linearize(["X", "C", "E", "A", "D"])
+       # assert a == ["E", "D", "C", "X", "A"]
+       # ~~~~
        fun linearize(elements: Collection[E]): Array[E] do
                var lin = elements.to_a
                sort(lin)
@@ -265,12 +391,24 @@ class POSetElement[E: Object]
 
        # Return the set of all elements `t` that have an edge from `element` to `t`.
        # Since the POSet is reflexive, element is included in the set.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["B"].greaters.has_exactly(["B", "C", "D"])
+       # ~~~~
        fun greaters: Collection[E]
        do
                return self.tos
        end
 
        # Return the set of all elements `t` that have a direct edge from `element` to `t`.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["B"].direct_greaters.has_exactly(["C"])
+       # ~~~~
        fun direct_greaters: Collection[E]
        do
                return self.dtos
@@ -278,30 +416,67 @@ class POSetElement[E: Object]
 
        # Return the set of all elements `f` that have an edge from `f` to `element`.
        # Since the POSet is reflexive, element is included in the set.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["C"].smallers.has_exactly(["A", "B", "C"])
+       # ~~~~
        fun smallers: Collection[E]
        do
                return self.froms
        end
 
        # Return the set of all elements `f` that have an edge from `f` to `element`.
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["C"].direct_smallers.has_exactly(["B"])
+       # ~~~~
        fun direct_smallers: Collection[E]
        do
                return self.dfroms
        end
 
        # Is there an edge from `element` to `t`?
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert     pos["B"] <= "D"
+       # assert     pos["B"] <= "C"
+       # assert     pos["B"] <= "B"
+       # assert not pos["B"] <= "A"
+       # ~~~~
        fun <=(t: E): Bool
        do
                return self.tos.has(t)
        end
 
        # Is `t != element` and is there an edge from `element` to `t`?
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert     pos["B"] < "D"
+       # assert     pos["B"] < "C"
+       # assert not pos["B"] < "B"
+       # assert not pos["B"] < "A"
+       # ~~~~
        fun <(t: E): Bool
        do
                return t != self.element and self.tos.has(t)
        end
 
        # The length of the shortest path to the root of the poset hierarchy
+       #
+       # ~~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["A", "B", "C", "D"])
+       # assert pos["A"].depth == 3
+       # assert pos["D"].depth == 0
+       # ~~~~
        fun depth: Int do
                if direct_greaters.is_empty then
                        return 0
index 7a5503f..f17a28e 100644 (file)
@@ -75,8 +75,11 @@ class OptionUserAndGroup
 
        redef type VALUE: nullable UserGroup
 
-       init for_dropping_privileges do init("Drop privileges to user:group or simply user", "-u", "--usergroup")
-       init(help: String, names: String...) do super(help, null, names)
+       # Create an `OptionUserAndGroup` for dropping privileges
+       init for_dropping_privileges
+       do
+               init("Drop privileges to user:group or simply user", null, ["-u", "--usergroup"])
+       end
 
        redef fun convert(str)
        do
@@ -87,8 +90,7 @@ class OptionUserAndGroup
                        return new UserGroup(words[0], words[1])
                else
                        errors.add("Option {names.join(", ")} expected parameter in the format \"user:group\" or simply \"user\".\n")
-                       abort # FIXME only for nitc, remove and replace with next line when FFI is working in nitg
-                       #return null
+                       return null
                end
        end
 end
index 05cbed0..23b1ef7 100644 (file)
@@ -114,8 +114,6 @@ end
 class Statement
        private var native_statement: NativeStatement
 
-       private init(ns: NativeStatement) do self.native_statement = ns
-
        # Is this statement usable?
        var is_open = true
 
@@ -134,12 +132,11 @@ class Statement
        end
 end
 
+# A row from a `Statement`
 class StatementRow
        # Statement linked to `self`
        var statement: Statement
 
-       private init(s: Statement) do self.statement = s
-
        # Number of entries in this row
        #
        # require: `self.statement.is_open`
@@ -161,12 +158,6 @@ class StatementEntry
 
        private var index: Int
 
-       private init(s: Statement, i: Int)
-       do
-               self.statement = s
-               self.index = i
-       end
-
        # Name of the column
        #
        # require: `self.statement.is_open`
@@ -258,17 +249,15 @@ class StatementIterator
        # Statement linked to `self`
        var statement: Statement
 
-       private init(s: Statement)
+       init
        do
-               self.statement = s
-               self.item = new StatementRow(s)
-
+               self.item = new StatementRow(statement)
                self.is_ok = statement.native_statement.step.is_row
        end
 
-       redef var item: StatementRow
+       redef var item: StatementRow is noinit
 
-       redef var is_ok: Bool
+       redef var is_ok: Bool is noinit
 
        # require: `self.statement.is_open`
        redef fun next
@@ -310,12 +299,9 @@ end
 class Blob
        super Sqlite3Data
 
-       private init(pointer: Pointer, length: Int)
-       do
-               self.pointer = pointer
-               self.length = length
-       end
-
+       # Pointer to the beginning of the blob
        var pointer: Pointer
+
+       # Size of the blob
        var length: Int
 end
index 56633ce..fa16295 100644 (file)
@@ -123,17 +123,48 @@ interface Collection[E]
                return iterator.item
        end
 
-       # Is the collection contains all the elements of `other`?
+       # Does the collection contain at least each element of `other`?
        #
-       #    assert [1,1,1].has_all([1])         == true
-       #    assert [1,1,1].has_all([1,2])       == false
        #    assert [1,3,4,2].has_all([1..2])    == true
        #    assert [1,3,4,2].has_all([1..5])    == false
+       #
+       # Repeated elements in the collections are not considered.
+       #
+       #    assert [1,1,1].has_all([1])         == true
+       #    assert [1..5].has_all([1,1,1])      == true
+       #
+       # Note that the default implementation is general and correct for any lawful Collections.
+       # It is memory-efficient but relies on `has` so may be CPU-inefficient for some kind of collections.
        fun has_all(other: Collection[E]): Bool
        do
                for x in other do if not has(x) then return false
                return true
        end
+
+       # Does the collection contain exactly all the elements of `other`?
+       #
+       # The same elements must be present in both `self` and `other`,
+       # but the order of the elements in the collections are not considered.
+       #
+       #    assert [1..3].has_exactly([3,1,2]) == true  # the same elements
+       #    assert [1..3].has_exactly([3,1])   == false # 2 is not in the array
+       #    assert [1..2].has_exactly([3,1,2]) == false # 3 is not in the range
+       #
+       # Repeated elements must be present in both collections in the same amount.
+       # So basically it is a multi-set comparison.
+       #
+       #    assert [1,2,3,2].has_exactly([1,2,2,3]) == true  # the same elements
+       #    assert [1,2,3,2].has_exactly([1,2,3])   == false # more 2 in the first array
+       #    assert [1,2,3].has_exactly([1,2,2,3])   == false # more 2 in the second array
+       #
+       # Note that the default implementation is general and correct for any lawful Collections.
+       # It is memory-efficient but relies on `count` so may be CPU-inefficient for some kind of collections.
+       fun has_exactly(other: Collection[E]): Bool
+       do
+               if length != other.length then return false
+               for e in self do if self.count(e) != other.count(e) then return false
+               return true
+       end
 end
 
 # Instances of the Iterator class generates a series of elements, one at a time.