#include <ace/OS_main.h>
#include <ace/Thread_Manager.h>
#include <qrect.h>
#include <qwidget.h>
#include <qtimer.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qprogressbar.h>
#include <qdial.h>
#include <qtooltip.h>
#include <qapplication.h>
#include <qstatusbar.h>
#include <qslider.h>
#include <so_4/rt/h/rt.hpp>
#include <so_4/api/h/api.hpp>
#include <so_4/timer_thread/simple/h/pub.hpp>
#include <so_4/disp/active_obj/h/pub.hpp>
#include <so_4/disp/qt_ui/h/pub.hpp>
#include <string>
#include <cstdlib>
const int c_max = 99;
class sobj_thread_t
{
private :
so_4::rt::agent_coop_t * m_start_coop;
public :
sobj_thread_t( so_4::rt::agent_coop_t * start_coop = 0 )
: m_start_coop( start_coop )
{}
virtual ~sobj_thread_t()
{}
virtual void
start()
{
if( -1 == ACE_Thread_Manager::instance()->spawn(
entry_point,
this ) )
{
ACE_ERROR(( LM_ERROR, "unable to spawn work thread\n" ));
}
}
virtual void
wait()
{
ACE_Thread_Manager::instance()->wait();
}
protected :
virtual void
body()
{
so_4::ret_code_t rc = so_4::api::start(
so_4::disp::qt_ui::create_disp(
so_4::disp::active_obj::create_disp(
so_4::timer_thread::simple::create_timer_thread(),
so_4::auto_destroy_timer ) ),
so_4::auto_destroy_disp,
m_start_coop
);
if( rc )
{
std::cerr << "start: " << rc << std::endl;
}
}
static ACE_THR_FUNC_RETURN
entry_point( void * self_object )
{
sobj_thread_t * sobj_thread = ACE_reinterpret_cast(
sobj_thread_t *,
self_object );
sobj_thread->body();
return 0;
}
};
class a_msg_owner_t
: public so_4::rt::agent_t
{
typedef so_4::rt::agent_t base_type_t;
public :
a_msg_owner_t()
: base_type_t( agent_name() )
, m_interval( 1000 )
{};
virtual ~a_msg_owner_t()
{};
virtual const char *
so_query_type() const;
virtual void
so_on_subscription()
{
so_subscribe( "evt_start",
so_4::rt::sobjectizer_agent_name(), "msg_start" );
so_subscribe( "evt_random", "msg_random" );
so_subscribe( "evt_interval", "msg_interval" );
};
static std::string
agent_name()
{
return "a_msg_owner";
};
struct msg_interval {
int m_interval;
std::string m_sender;
msg_interval() {};
msg_interval( int interval,
const std::string & sender )
: m_interval( interval )
, m_sender( sender )
{}
static bool
check( const msg_interval * msg )
{
return ( 0 != msg &&
msg->m_sender.length() );
}
};
struct msg_random {
int m_random;
msg_random()
: m_random( ( double( rand() ) / RAND_MAX ) * c_max )
{}
};
struct msg_ping_pong {
std::string m_sender;
std::string m_value;
msg_ping_pong() {}
msg_ping_pong( const std::string & sender,
const std::string & value )
: m_sender( sender )
, m_value( value )
{}
static bool
check( const msg_ping_pong * msg )
{
return ( 0 != msg &&
msg->m_sender.length() &&
msg->m_value.length() );
}
};
void evt_start()
{
so_4::api::send_msg_safely(
agent_name(),
"msg_random",
new msg_random() );
};
void evt_random( const msg_random & msg )
{
so_4::api::send_msg_safely(
agent_name(),
"msg_random",
new msg_random(),
"", m_interval, 0 );
};
void evt_interval( const msg_interval & msg )
{
m_interval = msg.m_interval;
};
private:
int m_interval;
};
SOL4_CLASS_START( a_msg_owner_t )
SOL4_MSG_START( msg_shutdown, a_msg_owner_t::msg_ping_pong )
SOL4_MSG_FIELD( m_sender )
SOL4_MSG_FIELD( m_value )
SOL4_MSG_CHECKER( a_msg_owner_t::msg_ping_pong::check )
SOL4_MSG_FINISH()
SOL4_MSG_START( msg_ping_pong, a_msg_owner_t::msg_ping_pong )
SOL4_MSG_FIELD( m_sender )
SOL4_MSG_CHECKER( a_msg_owner_t::msg_ping_pong::check )
SOL4_MSG_FINISH()
SOL4_MSG_START( msg_random, a_msg_owner_t::msg_random )
SOL4_MSG_FIELD( m_random )
SOL4_MSG_FINISH()
SOL4_MSG_START( msg_interval, a_msg_owner_t::msg_interval )
SOL4_MSG_FIELD( m_interval )
SOL4_MSG_FIELD( m_sender )
SOL4_MSG_CHECKER( a_msg_owner_t::msg_interval::check )
SOL4_MSG_FINISH()
SOL4_EVENT( evt_start )
SOL4_EVENT_STC(
evt_random,
a_msg_owner_t::msg_random )
SOL4_EVENT_STC(
evt_interval,
a_msg_owner_t::msg_interval )
SOL4_STATE_START( st_initial )
SOL4_STATE_EVENT( evt_start )
SOL4_STATE_EVENT( evt_random )
SOL4_STATE_EVENT( evt_interval )
SOL4_STATE_FINISH()
SOL4_CLASS_FINISH( )
class a_qt_widget_t
: public QWidget
, public so_4::rt::agent_t
{
typedef so_4::rt::agent_t base_type_t;
Q_OBJECT
protected:
a_qt_widget_t( const std::string & agent_name,
const std::string & ping_or_pong,
QWidget * parent = 0 )
: base_type_t( agent_name )
, QWidget( parent, agent_name.c_str() )
, m_button( 0 )
, m_label( 0 )
, m_status_bar( 0 )
{
so_add_traits( so_4::disp::qt_ui::query_gui_thread_traits() );
};
public:
virtual ~a_qt_widget_t()
{};
virtual const char *
so_query_type() const;
virtual void
so_on_subscription()
{
so_subscribe( "evt_ping_pong",
a_msg_owner_t::agent_name(),
"msg_ping_pong" );
so_subscribe( "evt_shutdown",
a_msg_owner_t::agent_name(),
"msg_shutdown" );
so_subscribe( "evt_random",
a_msg_owner_t::agent_name(),
"msg_random" );
so_subscribe( "evt_interval",
a_msg_owner_t::agent_name(),
"msg_interval" );
};
void
evt_ping_pong( const a_msg_owner_t::msg_ping_pong & msg )
{
if( so_query_name() != msg.m_sender )
{
m_button->setEnabled( TRUE );
m_button->setFocus();
setActiveWindow();
if( "ping" == msg.m_value )
m_status_bar->message( "Ping was received...", 2000 );
else
m_status_bar->message( "Pong was received...", 2000 );
}
else
m_button->setEnabled( FALSE );
};
void
evt_random( const a_msg_owner_t::msg_random & msg )
{
m_label->setProgress( msg.m_random );
};
virtual void
evt_interval( const a_msg_owner_t::msg_interval & msg )
{};
void
evt_shutdown( const a_msg_owner_t::msg_ping_pong & msg )
{
if( msg.m_sender != so_query_name() )
close();
};
public slots:
void
slot_ping_pong()
{
so_4::api::send_msg_safely(
a_msg_owner_t::agent_name(), "msg_ping_pong",
new a_msg_owner_t::msg_ping_pong( so_query_name(),
m_button->text().ascii() ) );
};
void
slot_interval( int interval )
{
so_4::api::send_msg_safely(
a_msg_owner_t::agent_name(), "msg_interval",
new a_msg_owner_t::msg_interval( interval, so_query_name() ) );
};
protected:
virtual void
closeEvent( QCloseEvent * e )
{
if( !isHidden() )
{
so_4::api::send_msg_safely(
a_msg_owner_t::agent_name(), "msg_shutdown",
new a_msg_owner_t::msg_ping_pong( so_query_name(), "shutdown" ) );
e->accept();
}
};
QPushButton * m_button;
QProgressBar * m_label;
QStatusBar * m_status_bar;
};
SOL4_CLASS_START( a_qt_widget_t )
SOL4_EVENT_STC(
evt_ping_pong,
a_msg_owner_t::msg_ping_pong )
SOL4_EVENT_STC(
evt_random,
a_msg_owner_t::msg_random )
SOL4_EVENT_STC(
evt_interval,
a_msg_owner_t::msg_interval )
SOL4_EVENT_STC(
evt_shutdown,
a_msg_owner_t::msg_ping_pong )
SOL4_STATE_START( st_initial )
SOL4_STATE_EVENT( evt_ping_pong )
SOL4_STATE_EVENT( evt_shutdown )
SOL4_STATE_EVENT( evt_random )
SOL4_STATE_EVENT( evt_interval )
SOL4_STATE_FINISH()
SOL4_CLASS_FINISH( )
#include "moc/main.moc"
struct slider_traits_t
{
typedef QSlider control_type_t;
static control_type_t *
make( QWidget * parent )
{
control_type_t * r = new control_type_t( parent );
r->setOrientation( Qt::Horizontal );
return r;
}
};
struct dial_traits_t
{
typedef QDial control_type_t;
static control_type_t *
make( QWidget * parent )
{
control_type_t * r = new control_type_t( parent );
return r;
}
};
template< class TRAITS >
class a_qt_widget_impl_t
: public a_qt_widget_t
{
public:
a_qt_widget_impl_t( const std::string & agent_name,
const std::string & ping_or_pong,
QWidget * parent = 0 )
: a_qt_widget_t( agent_name, ping_or_pong, parent )
, m_dial( 0 )
{
QVBoxLayout * layout = new QVBoxLayout( this );
m_dial = TRAITS::make( this );
m_dial->setMinValue( 50 );
m_dial->setMaxValue( 3000 );
m_dial->setLineStep( 50 );
m_dial->setPageStep( 100 );
m_dial->setValue( 1000 );
QToolTip::add( m_dial, QString::fromLocal8Bit(
"Регулятор скорости генерации случайных чисел" ) );
layout->addWidget( m_dial );
m_button = new QPushButton( this, "Ping Pong Button" );
if( "pong" == ping_or_pong )
m_button->setEnabled( FALSE );
m_button->setText( ping_or_pong.c_str() );
m_button->setFocus();
m_button->setAutoDefault( TRUE );
QToolTip::add( m_button, QString::fromLocal8Bit(
"Отсылает сообщение msg_ping_pong другому окошку" ) );
layout->addWidget( m_button );
m_label = new QProgressBar( this );
m_label->setTotalSteps( 99 );
m_label->setPercentageVisible( TRUE );
QToolTip::add( m_label, QString::fromLocal8Bit(
"Отображает случайные числа от 0 до 99 в виде QProgressBar-а" ) );
layout->addWidget( m_label );
m_status_bar = new QStatusBar( this );
layout->addWidget( m_status_bar );
connect( m_button, SIGNAL( clicked() ), this, SLOT( slot_ping_pong() ) );
connect( m_dial, SIGNAL( valueChanged( int ) ), this,
SLOT( slot_interval( int ) ) );
};
virtual ~a_qt_widget_impl_t()
{};
virtual void
evt_interval( const a_msg_owner_t::msg_interval & msg )
{
if( msg.m_sender != so_query_name() )
if( m_dial )
m_dial->setValue( msg.m_interval );
};
private:
typename TRAITS::control_type_t * m_dial;
};
int main( int argc, char ** argv )
{
QApplication app( argc, argv );
app.connect( &app, SIGNAL( lastWindowClosed() ),
&app, SLOT( quit() ) );
a_msg_owner_t a_msg_owner;
a_qt_widget_impl_t< dial_traits_t > a_widget_1( "widget_1", "ping" );
a_qt_widget_impl_t< slider_traits_t > a_widget_2( "widget_2", "pong" );
so_4::rt::agent_t * g_coop_agents[] = {
&a_msg_owner,
&a_widget_1,
&a_widget_2,
};
so_4::rt::agent_coop_t a_coop( "a_coop", g_coop_agents,
sizeof( g_coop_agents ) / sizeof( g_coop_agents[ 0 ] ) );
sobj_thread_t sobj_thread( &a_coop );
sobj_thread.start();
app.setMainWidget( &a_widget_1 );
a_widget_1.show();
a_widget_2.show();
a_widget_2.move( a_widget_1.pos().x() + a_widget_1.frameSize().width(),
a_widget_1.pos().y() + a_widget_1.frameSize().height() );
int q_result = app.exec();
so_4::api::send_msg( so_4::rt::sobjectizer_agent_name(),
"msg_normal_shutdown" );
so_4::api::shutdown();
sobj_thread.wait();
return q_result;
}