mirror of
https://github.com/boostorg/signals.git
synced 2026-01-19 04:42:10 +00:00
Slot blocking/unblocking, from Frantz Maerten
[SVN r27439]
This commit is contained in:
@@ -69,6 +69,30 @@
|
||||
</method>
|
||||
</method-group>
|
||||
|
||||
<method-group name="blocking">
|
||||
<method name="block">
|
||||
<type>void</type>
|
||||
<parameter name="should_block">
|
||||
<paramtype>bool</paramtype>
|
||||
<default>true</default>
|
||||
</parameter>
|
||||
<requires><simpara><code>connected()</code></simpara></requires>
|
||||
<postconditions><simpara><code>blocked() == should_block</code></simpara></postconditions>
|
||||
<throws><simpara>Will not throw.</simpara></throws>
|
||||
</method>
|
||||
<method name="unblock">
|
||||
<type>void</type>
|
||||
<requires><simpara><code>connected()</code></simpara></requires>
|
||||
<postconditions><simpara><code>!blocked()</code></simpara></postconditions>
|
||||
<throws><simpara>Will not throw.</simpara></throws>
|
||||
</method>
|
||||
<method name="blocked" cv="const">
|
||||
<type>bool</type>
|
||||
<returns><simpara><code>true</code> if the associated slot is either disconnected or blocked, <code>false</code> otherwise.</simpara></returns>
|
||||
<throws><simpara>Will not throw.</simpara></throws>
|
||||
</method>
|
||||
</method-group>
|
||||
|
||||
<method-group name="modifiers">
|
||||
<method name="swap">
|
||||
<type>void</type>
|
||||
|
||||
@@ -676,6 +676,29 @@ sig(); <emphasis>// Does nothing: there are no connected slots</emphasis>
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section><title>Blocking Slots (Beginner)</title>
|
||||
|
||||
<para>Slots can be temporarily "blocked", meaning that they will be
|
||||
ignored when the signal is invoked but have not been disconnected. The
|
||||
<code><methodname>block</methodname></code> member function
|
||||
temporarily blocks a slot, which can be unblocked via
|
||||
<code><methodname>unblock</methodname></code>. Here is an example of
|
||||
blocking/unblocking slots:</para>
|
||||
|
||||
<programlisting>
|
||||
boost::signals::connection c = sig.<methodname>connect</methodname>(HelloWorld());
|
||||
sig(); <emphasis>// Prints "Hello, World!"</emphasis>
|
||||
|
||||
c.<methodname>block</methodname>(); <emphasis>// block the slot</emphasis>
|
||||
assert(c.<methodname>blocked</methodname>());
|
||||
sig(); <emphasis>// No output: the slot is blocked</emphasis>
|
||||
|
||||
c.<methodname>unblock</methodname>(); <emphasis>// unblock the slot</emphasis>
|
||||
sig(); <emphasis>// Prints "Hello, World!"</emphasis>
|
||||
</programlisting>
|
||||
|
||||
</section>
|
||||
|
||||
<section><title>Scoped connections (Intermediate)</title>
|
||||
<para>The <code>boost::signals::scoped_connection</code> class
|
||||
references a signal/slot connection that will be disconnected when
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace boost {
|
||||
void* signal;
|
||||
void* signal_data;
|
||||
void (*signal_disconnect)(void*, void*);
|
||||
bool blocked_;
|
||||
|
||||
std::list<bound_object> bound_objects;
|
||||
};
|
||||
@@ -69,6 +70,12 @@ namespace boost {
|
||||
connection(const connection&);
|
||||
~connection();
|
||||
|
||||
// Block he connection: if the connection is still active, there
|
||||
// will be no notification
|
||||
void block(bool should_block = true) { con->blocked_ = should_block; }
|
||||
void unblock() { con->blocked_ = false; }
|
||||
bool blocked() const { return !connected() || con->blocked_; }
|
||||
|
||||
// Disconnect the signal and slot, if they are connected
|
||||
void disconnect() const;
|
||||
|
||||
@@ -87,11 +94,11 @@ namespace boost {
|
||||
|
||||
public: // TBD: CHANGE THIS
|
||||
// Set whether this connection object is controlling or not
|
||||
void set_controlling(bool control = true)
|
||||
void set_controlling(bool control = true)
|
||||
{ controlling_connection = control; }
|
||||
|
||||
shared_ptr<BOOST_SIGNALS_NAMESPACE::detail::basic_connection>
|
||||
get_connection() const
|
||||
get_connection() const
|
||||
{ return con; }
|
||||
|
||||
private:
|
||||
@@ -162,6 +169,18 @@ namespace boost {
|
||||
}
|
||||
};
|
||||
|
||||
// Determines if the underlying connection is callable, ie if
|
||||
// it is connected and not blocked
|
||||
struct is_callable {
|
||||
typedef connection_slot_pair argument_type;
|
||||
typedef bool result_type;
|
||||
|
||||
inline bool operator()(const argument_type& c) const
|
||||
{
|
||||
return c.first.connected() && !c.first.blocked() ;
|
||||
}
|
||||
};
|
||||
|
||||
// Autodisconnects the bound object when it is destroyed unless the
|
||||
// release method is invoked.
|
||||
class auto_disconnect_bound_object {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#define BOOST_SIGNALS_SLOT_CALL_ITERATOR
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/smart_ptr.hpp>
|
||||
#include <boost/signals/detail/config.hpp>
|
||||
@@ -49,33 +48,33 @@ namespace boost {
|
||||
|
||||
public:
|
||||
slot_call_iterator(Iterator iter_in, Iterator end_in, Function f,
|
||||
optional<result_type> &c)
|
||||
optional<result_type> &c)
|
||||
: iter(iter_in), end(end_in), f(f), cache(&c)
|
||||
{
|
||||
iter = std::find_if(iter, end, std::not1(is_disconnected()));
|
||||
iter = std::find_if(iter, end, is_callable());
|
||||
}
|
||||
|
||||
typename inherited::reference
|
||||
dereference() const
|
||||
{
|
||||
if (!cache->is_initialized()) {
|
||||
cache->reset(f(*iter));
|
||||
}
|
||||
if (!cache->is_initialized()) {
|
||||
cache->reset(f(*iter));
|
||||
}
|
||||
|
||||
return cache->get();
|
||||
}
|
||||
|
||||
void increment()
|
||||
{
|
||||
iter = std::find_if(++iter, end, std::not1(is_disconnected()));
|
||||
cache->reset();
|
||||
iter = std::find_if(++iter, end, is_callable());
|
||||
cache->reset();
|
||||
}
|
||||
|
||||
bool equal(const slot_call_iterator& other) const
|
||||
{
|
||||
iter = std::find_if(iter, end, std::not1(is_disconnected()));
|
||||
iter = std::find_if(iter, end, is_callable());
|
||||
other.iter = std::find_if(other.iter, other.end,
|
||||
std::not1(is_disconnected()));
|
||||
is_callable());
|
||||
return iter == other.iter;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace boost {
|
||||
// signal for the connection to be connected.
|
||||
con->signal = static_cast<void*>(this);
|
||||
con->signal_data = 0;
|
||||
con->blocked_ = false ;
|
||||
con->signal_disconnect = &bound_object_destructed;
|
||||
}
|
||||
|
||||
@@ -38,8 +39,8 @@ namespace boost {
|
||||
|
||||
// Now notify each of the bound objects that they are connected to this
|
||||
// slot.
|
||||
for(std::vector<const trackable*>::iterator i =
|
||||
data->bound_objects.begin();
|
||||
for(std::vector<const trackable*>::iterator i =
|
||||
data->bound_objects.begin();
|
||||
i != data->bound_objects.end(); ++i) {
|
||||
// Notify the object that the slot is connecting to it
|
||||
BOOST_SIGNALS_NAMESPACE::detail::bound_object binding;
|
||||
|
||||
@@ -92,6 +92,20 @@ test_remove_self()
|
||||
s0(); std::cout << std::endl;
|
||||
BOOST_CHECK(test_output == "123");
|
||||
|
||||
std::cout << "Blocking 2" << std::endl;
|
||||
|
||||
connections[2].block();
|
||||
test_output = "";
|
||||
s0(); std::cout << std::endl;
|
||||
BOOST_CHECK(test_output == "13");
|
||||
|
||||
std::cout << "Unblocking 2" << std::endl;
|
||||
|
||||
connections[2].unblock();
|
||||
test_output = "";
|
||||
s0(); std::cout << std::endl;
|
||||
BOOST_CHECK(test_output == "123");
|
||||
|
||||
s0.disconnect_all_slots();
|
||||
BOOST_CHECK(s0.empty());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user