<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -59,6 +59,7 @@
 #include &lt;rtt/MultiVector.hpp&gt;
 #include &lt;rtt/TypeStream.hpp&gt;
 #include &quot;TaskBrowser.hpp&quot;
+#include &lt;boost/lexical_cast.hpp&gt;
 
 #include &quot;rtt/TryCommand.hpp&quot;
 #include &lt;rtt/TaskContext.hpp&gt;
@@ -646,6 +647,9 @@ namespace OCL
 #endif
         while (1)
             {
+                // Check port status:
+                checkPorts();
+
                 if (!macrorecording) {
                     if ( context == tb )
                         cout &lt;&lt; green &lt;&lt; &quot; Watching &quot; &lt;&lt;coloroff;
@@ -689,8 +693,7 @@ namespace OCL
                         }
                     }
                 }
-                // Check port status:
-                checkPorts();
+
                 // Call readline wrapper :
                 ::signal( SIGINT, ctrl_c_catcher ); // catch ctrl_c only when editting a line.
 
@@ -803,19 +806,50 @@ namespace OCL
 
     void TaskBrowser::checkPorts()
     {
-        // check periodically if the taskcontext did not change its ports.
 
-        DataFlowInterface::Ports ports;
-        ports = this-&gt;ports()-&gt;getPorts();
-        for( DataFlowInterface::Ports::iterator i=ports.begin(); i != ports.end(); ++i) {
-            // If our port is no longer connected, try to reconnect.
-            PortInterface* p = *i;
-            PortInterface* tcp = taskcontext-&gt;ports()-&gt;getPort( p-&gt;getName() );
-            if ( p-&gt;ready() == false || tcp == 0 || tcp-&gt;ready() == false) {
-                this-&gt;ports()-&gt;removePort( p-&gt;getName() );
-                delete p;
+        // Remove from the watch and peeking_ports maps the ports that are
+        // disconnected because the writer port we were watching has been
+        // destroyed.
+
+        map&lt;WritePortInterface*, ReadPortInterface*&gt;::iterator peek_it = peeking_ports.begin();
+        while(peek_it != peeking_ports.end())
+        {
+            if (!peek_it-&gt;second-&gt;connected())
+            {
+                delete peek_it-&gt;second;
+                peeking_ports.erase(peek_it++);
             }
-        }
+            else ++peek_it;
+        }
+        
+        ReadPortList::iterator watch_it;
+        watch_it = watch.begin();
+        while(watch_it != watch.end())
+        {
+            ReadPortInterface* reader = watch_it-&gt;get&lt;2&gt;();
+            if (!reader-&gt;connected())
+            {
+                delete reader;
+                watch.erase(watch_it++);
+                continue;
+            }
+
+            // There is a theoretical race condition here, as the writer port
+            // can disappear between the above test and the display. This only
+            // means that sometime the value displayed will be bogus.
+            //
+            // Note that watch_it should be fixed by changing the DataSourceBase
+            // interface.
+            std::string name = watch_it-&gt;get&lt;0&gt;();
+            sresult &lt;&lt; &quot;[&quot; &lt;&lt; watch_it - watch.begin() &lt;&lt; &quot;] &quot;
+                &lt;&lt; setw(11)&lt;&lt;right&lt;&lt; reader-&gt;getTypeInfo()-&gt;getTypeName()
+                &lt;&lt; &quot; &quot; &lt;&lt; coloron &lt;&lt;setw( 14 )&lt;&lt;left&lt;&lt; name &lt;&lt; coloroff;
+            sresult &lt;&lt; &quot; = &quot; &lt;&lt; DataSourceBase::shared_ptr(reader-&gt;getDataSource()) &lt;&lt; &quot;\n&quot;;
+
+            ++watch_it;
+        }
+        cout &lt;&lt; sresult.str() &lt;&lt; flush;
+        sresult.str(&quot;&quot;);
     }
 
     void TaskBrowser::setColorTheme(ColorTheme t)
@@ -950,6 +984,25 @@ namespace OCL
         return pp.peer();
     }
 
+    bool TaskBrowser::addWatch(PortInterface* port)
+    {
+        WritePortInterface* writer = dynamic_cast&lt;WritePortInterface*&gt;(port);
+        if (!writer)
+            return false;
+
+        ReadPortList::iterator it;
+        for (it = watch.begin(); it != watch.end(); ++it)
+        {
+            if (it-&gt;get&lt;1&gt;() == writer)
+                return true;
+        }
+
+        ReadPortInterface* reader = dynamic_cast&lt;ReadPortInterface*&gt;(writer-&gt;antiClone());
+        writer-&gt;createConnection(*reader, ConnPolicy::data());
+        watch.push_back( make_tuple(taskcontext-&gt;getName() + &quot;.&quot; + writer-&gt;getName(), writer, reader) );
+        return true;
+    }
+
     void TaskBrowser::browserAction(std::string const&amp; act)
     {
         std::stringstream ss(act);
@@ -1117,29 +1170,29 @@ namespace OCL
             cout &lt;&lt;nl &lt;&lt; &quot;Disabling all colors&quot;&lt;&lt;endl;
             return;
         }
-        if ( instr == &quot;connect&quot;) {
+        if ( instr == &quot;watch&quot;) {
             if (arg.empty() ) {
-                cout &lt;&lt;nl &lt;&lt; &quot;TaskBrowser connects to all ports of &quot;&lt;&lt;taskcontext-&gt;getName()&lt;&lt;endl;
+                cout &lt;&lt;nl &lt;&lt; &quot;TaskBrowser is watching all write ports of &quot;&lt;&lt;taskcontext-&gt;getName()&lt;&lt;endl;
                 // create 'anti-ports' to allow port-level interaction with the peer.
                 DataFlowInterface::Ports ports = taskcontext-&gt;ports()-&gt;getPorts();
-                for( DataFlowInterface::Ports::iterator i=ports.begin(); i != ports.end(); ++i) {
-                    if (this-&gt;ports()-&gt;getPort( (*i)-&gt;getName() ) == 0 )
-                        this-&gt;ports()-&gt;addPort( (*i)-&gt;antiClone() );
-                }
-                RTT::connectPorts(this,taskcontext);
+                for( DataFlowInterface::Ports::iterator i=ports.begin(); i != ports.end(); ++i)
+                    addWatch(*i);
             }
             else {
-                cout &lt;&lt;nl &lt;&lt; &quot;TaskBrowser connects to port '&quot;&lt;&lt;arg &lt;&lt;&quot;' of &quot;&lt;&lt;taskcontext-&gt;getName()&lt;&lt;endl;
-                // create 'anti-port' and connect.
-                DataFlowInterface::Ports ports = taskcontext-&gt;ports()-&gt;getPorts();
-                for( DataFlowInterface::Ports::iterator i=ports.begin(); i != ports.end(); ++i) {
-                    if ( (*i)-&gt;getName() == arg &amp;&amp; this-&gt;ports()-&gt;getPort( (*i)-&gt;getName() ) == 0 ) {
-                        this-&gt;ports()-&gt;addPort( (*i)-&gt;antiClone() );
-                        this-&gt;ports()-&gt;getPort( arg )-&gt;connectTo( *i ); // this should always succeed
-                        assert( this-&gt;ports()-&gt;getPort( arg )-&gt;connected() );
-                        return;
-                    }
-                }
+                if (addWatch(taskcontext-&gt;ports()-&gt;getPort(arg)))
+                    cout &lt;&lt;nl &lt;&lt; &quot;TaskBrowser is watching port '&quot;&lt;&lt;arg &lt;&lt;&quot;' of &quot;&lt;&lt;taskcontext-&gt;getName()&lt;&lt;endl;
+                else
+                    cout &lt;&lt;nl &lt;&lt; &quot;TaskBrowser can not watch port '&quot;&lt;&lt;arg &lt;&lt;&quot;' of &quot;&lt;&lt;taskcontext-&gt;getName()&lt;&lt;endl;
+            }
+            return;
+        }
+        if ( instr == &quot;unwatch&quot; ) {
+            try {
+                size_t idx = boost::lexical_cast&lt;int&gt;(arg);
+                if (idx &lt; watch.size())
+                    watch.erase(watch.begin() + idx);
+            } catch (boost::bad_lexical_cast) {
+                cerr &lt;&lt; &quot;usage: unwatch [idx]&quot; &lt;&lt; endl;
             }
             return;
         }
@@ -1518,11 +1571,12 @@ namespace OCL
         cout &lt;&lt; &quot;  may use loop or conditional statements, variables etc.&quot;&lt;&lt;nl;
 
         cout &lt;&lt;titlecol(&quot;Connecting Ports&quot;)&lt;&lt;nl;
-        cout &lt;&lt; &quot;  You can instruct the TaskBrowser to connect to the ports of the current Peer by&quot;&lt;&lt;nl;
-        cout &lt;&lt; &quot;  typing &quot;&lt;&lt;comcol(&quot;.connect [port-name]&quot;)&lt;&lt;&quot;, which will temporarily create connections&quot;&lt;&lt;nl;
-        cout &lt;&lt; &quot;  to all ports if [port-name] is omitted or to the specified port otherwise.&quot;&lt;&lt;nl;
-        cout &lt;&lt; &quot;  The TaskBrowser disconnects these ports when it visits another component, but the&quot;&lt;&lt;nl;
-        cout &lt;&lt; &quot;  created connection objects remain in place (this is more or less a bug)!&quot;&lt;&lt;nl;
+        cout &lt;&lt; &quot;  You can instruct the TaskBrowser to display the values of some ports before each prompt&quot; &lt;&lt; nl;
+        cout &lt;&lt; &quot;  by using &quot; &lt;&lt; comcol(&quot;.watch [port-name]&quot;) &lt;&lt; &quot;. If a name is given, that specific write&quot; &lt;&lt; nl;
+        cout &lt;&lt; &quot;  port will be added to the set of watched ports. If no name is given, then all write ports&quot; &lt;&lt; nl;
+        cout &lt;&lt; &quot;  of the given task are added.&quot; &lt;&lt; nl;
+        cout &lt;&lt; &quot;  Watches can be removed by using &quot; &lt;&lt; comcol(&quot;.unwatch port-index&quot;) &lt;&lt; &quot;, where the port&quot; &lt;&lt; nl;
+        cout &lt;&lt; &quot;  port index is the number displayed in front of the port in the watch list.&quot; &lt;&lt; nl;
     }
 
     void TaskBrowser::printProgram(const std::string&amp; progname, int cl /*= -1*/, TaskContext* progpeer /* = 0 */) {
@@ -1714,27 +1768,37 @@ namespace OCL
             if ( !objlist.empty() ) {
                 for(vector&lt;string&gt;::iterator it = objlist.begin(); it != objlist.end(); ++it) {
                     PortInterface* port = peer-&gt;ports()-&gt;getPort(*it);
-                    PortInterface::PortType pt = port-&gt;getPortType();
+                    WritePortInterface* writer = dynamic_cast&lt;WritePortInterface*&gt;(port);
+
                     // Port type R/W
-                    sresult &lt;&lt; nl &lt;&lt; &quot; &quot; &lt;&lt; (pt == PortInterface::ReadPort ?
-                        &quot; R&quot; : pt == PortInterface::WritePort ? &quot; W&quot; : &quot;RW&quot;);
-                    // Port data type + name
-                    if ( !port-&gt;ready() || !port-&gt;connection() )
-                        sresult &lt;&lt; &quot;(U) &quot; &lt;&lt; setw(11)&lt;&lt;right&lt;&lt; port-&gt;getTypeInfo()-&gt;getTypeName();
+                    sresult &lt;&lt; nl &lt;&lt; &quot; &quot; &lt;&lt; (writer ? &quot;W&quot; : &quot;R&quot;);
+
+                    // Port connection status
+                    if ( !port-&gt;connected() )
+                        sresult &lt;&lt; &quot;(U) &quot;;
                     else
-                        sresult &lt;&lt; &quot;(C) &quot; &lt;&lt; setw(11)&lt;&lt;right&lt;&lt; port-&gt;getTypeInfo()-&gt;getTypeName();
-                    sresult &lt;&lt; &quot; &quot;
+                        sresult &lt;&lt; &quot;(C) &quot;;
+
+                    // Port data type + name
+                    sresult &lt;&lt; setw(11)&lt;&lt;right&lt;&lt; port-&gt;getTypeInfo()-&gt;getTypeName() &lt;&lt; &quot; &quot;
                          &lt;&lt; coloron &lt;&lt;setw( 14 )&lt;&lt;left&lt;&lt; *it &lt;&lt; coloroff;
-                    if ( port-&gt;ready() )
-                        sresult &lt;&lt; &quot; = &quot; &lt;&lt;port-&gt;connection()-&gt;getDataSource();
-                    else {
-                        ConnectionInterface::shared_ptr c = port-&gt;createConnection();
-                        if ( c )
-                            sresult &lt;&lt; &quot; = &quot; &lt;&lt; c-&gt;getDataSource();
+
+                    // Note: the port description is already given in the task
+                    // object list, we don't have to put it here as well.
+
+                    // And finally, if it is a writer port, the last written
+                    // value. It is done only if the port is already connected
+                    if ( writer &amp;&amp; writer-&gt;connected() ) 
+                    {
+                        ReadPortInterface* reader = peeking_ports[writer];
+                        if (!reader)
+                        {
+                            peeking_ports[writer] = reader =
+                                dynamic_cast&lt;ReadPortInterface*&gt;(writer-&gt;antiClone());
+                            writer-&gt;createConnection(*reader, ConnPolicy::data());
+                        }
+                        sresult &lt;&lt; &quot; = &quot; &lt;&lt; DataSourceBase::shared_ptr(reader-&gt;getDataSource());
                     }
-                    // Port description
-//                     if ( peer-&gt;getObject(*it) )
-//                         sresult &lt;&lt; &quot; ( &quot;&lt;&lt; taskobject-&gt;getObject(*it)-&gt;getDescription() &lt;&lt; &quot; ) &quot;;
                 }
             } else {
                 sresult &lt;&lt; &quot;(none)&quot;;</diff>
      <filename>taskbrowser/TaskBrowser.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -66,6 +66,7 @@
 #include &lt;string&gt;
 #include &lt;sstream&gt;
 #include &lt;vector&gt;
+#include &lt;boost/tuple/tuple.hpp&gt;
 
 #include &lt;ocl/OCL.hpp&gt;
 
@@ -97,6 +98,12 @@ namespace OCL
         RTT::DispatchInterface*   command;
         RTT::DataSource&lt;bool&gt;::shared_ptr   accepted;
 
+        typedef std::vector&lt; boost::tuple&lt;std::string, RTT::WritePortInterface*, RTT::ReadPortInterface*&gt; &gt; ReadPortList;
+        // For the watch list, order matters
+        ReadPortList watch;
+        // For the peeking ports, it does not so much
+        std::map&lt;RTT::WritePortInterface*, RTT::ReadPortInterface*&gt; peeking_ports;
+
         int debug;
         /* A static variable for holding the line. */
         char *line_read;
@@ -141,6 +148,8 @@ namespace OCL
 #endif
         static RTT::TaskContext* findPeer( std::string comm );
 
+        bool addWatch(PortInterface* port);
+
     protected:
 
         void listText(std::stringstream&amp; txtss,int start, int end, int ln, char s);</diff>
      <filename>taskbrowser/TaskBrowser.hpp</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>a3dad9567b6a790f7b08c3d2707f515e28c55383</id>
    </parent>
  </parents>
  <author>
    <name>Sylvain Joyeux</name>
    <email>sylvain.joyeux@dfki.de</email>
  </author>
  <url>http://github.com/doudou/orocos-ocl/commit/02ef5c832d72fd5b85ead1680f9725ed815a4137</url>
  <id>02ef5c832d72fd5b85ead1680f9725ed815a4137</id>
  <committed-date>2009-03-12T07:31:48-07:00</committed-date>
  <authored-date>2009-03-12T07:27:13-07:00</authored-date>
  <message>update the task browser to use the new data flow interface

The following changes are in effect:
 * we don't change the TaskBrowser's task set, but use a set
   of PortInterface internally. Note that thanks to the
   auto-disconnect feature, we can remove the ports that are
   dead easily (they're not connected anymore).
 * remove the .connect command which was pretty useless
 * add two .watch and .unwatch commands that allow to display
   the value of given ports before each task browser prompts.</message>
  <tree>ad0bc8ab9ce7413e9fe746dcaa02f6e92d08c4bf</tree>
  <committer>
    <name>Sylvain Joyeux</name>
    <email>sylvain.joyeux@dfki.de</email>
  </committer>
</commit>
