Permalink
Browse files

Qt example highlighting actor_widget_mixin

this example optionally builds when Qt4 is found during CMake
invokation and illustrates how to use actor_widget_mixin to send
and receive messages from a QWidget-based class
  • Loading branch information...
1 parent 59134a6 commit 6bad5f9837bbb8fed72e8341e0b988292f13d78c @Neverlord Neverlord committed Nov 6, 2012
View
@@ -281,3 +281,8 @@ src/recursive_queue_node.cpp
cppa/intrusive_fwd_ptr.hpp
cppa/memory_managed.hpp
src/memory_managed.cpp
+examples/qtsupport/group_chat.cpp
+examples/qtsupport/chatwindow.ui
+examples/qtsupport/chatwidget.hpp
+examples/qtsupport/chatwidget.cpp
+cppa/util/scope_guard.hpp
View
@@ -3,3 +3,4 @@
./third_party/boost_context/include/
/opt/local/include/gcc46/c++
/opt/local/include/
+/opt/local/Library/Frameworks/QtGui.framework/Versions/4/Headers/
@@ -21,3 +21,22 @@ add(math_actor message_passing)
add(distributed_math_actor remote_actors)
add(group_server remote_actors)
add(group_chat remote_actors)
+
+find_package(Qt4)
+
+if (QT4_FOUND)
+ include(${QT_USE_FILE})
+ QT4_WRAP_UI(GROUP_CHAT_UI_HDR qtsupport/chatwindow.ui)
+ QT4_WRAP_CPP(GROUP_CHAT_MOC_SRC qtsupport/chatwidget.hpp)
+ include_directories(. qtsupport ${CMAKE_BINARY_DIR}/examples ${CPPA_INCLUDE})
+ add_executable(qt_group_chat
+ qtsupport/group_chat.cpp
+ qtsupport/chatwidget.cpp
+ ${GROUP_CHAT_MOC_SRC}
+ ${GROUP_CHAT_UI_HDR})
+ target_link_libraries(qt_group_chat
+ ${CMAKE_DL_LIBS}
+ ${CPPA_LIBRARY}
+ ${QT_LIBRARIES})
+ add_dependencies(qt_group_chat all_examples)
+endif (QT4_FOUND)
@@ -0,0 +1,126 @@
+#include <string>
+#include <utility>
+
+#include <QMessageBox>
+#include <QInputDialog>
+
+#include "chatwidget.hpp"
+
+#include "cppa/cppa.hpp"
+#include "cppa/util/scope_guard.hpp"
+
+using namespace std;
+using namespace cppa;
+
+ChatWidget::ChatWidget(QWidget* parent, Qt::WindowFlags f)
+: super(parent, f), m_input(nullptr), m_output(nullptr) {
+ set_message_handler (
+ on(atom("join"), arg_match) >> [=](const group_ptr& what) {
+ for (auto g : self->joined_groups()) {
+ send(g, m_name + " has left the chatroom");
+ self->leave(g);
+ }
+ self->join(what);
+ print(("*** joined " + to_string(what)).c_str());
+ m_chatroom = what;
+ send(what, m_name + " has entered the chatroom");
+ },
+ on(atom("setName"), arg_match) >> [=](string& name) {
+ send(m_chatroom, m_name + " is now known as " + name);
+ m_name = std::move(name);
+ print("*** changed name to "
+ + QString::fromUtf8(m_name.c_str()));
+ },
+ on(atom("quit")) >> [=] {
+ close(); // close widget
+ },
+ on<string>() >> [=](const string& txt) {
+ // don't print own messages
+ if (self != self->last_sender()) {
+ print(QString::fromUtf8(txt.c_str()));
+ }
+ }
+ );
+}
+
+void ChatWidget::sendChatMessage() {
+ auto cleanup = util::make_scope_guard([=] {
+ input()->setText(QString());
+ });
+ QString line = input()->text();
+ if (line.startsWith('/')) {
+ match_split(line.midRef(1).toUtf8().constData(), ' ') (
+ on("join", arg_match) >> [=](const string& mod, const string& g) {
+ group_ptr gptr;
+ try { gptr = group::get(mod, g); }
+ catch (exception& e) {
+ print("*** exception: " + QString::fromUtf8((e.what())));
+ }
+ if (gptr != nullptr) {
+ send_as(as_actor(), as_actor(), atom("join"), gptr);
+ }
+ },
+ on("setName", arg_match) >> [=](const string& str) {
+ send_as(as_actor(), as_actor(), atom("setName"), str);
+ },
+ others() >> [=] {
+ print("*** list of commands:\n"
+ "/join <module> <group id>\n"
+ "/setName <new name>\n");
+ }
+ );
+ return;
+ }
+ if (m_name.empty()) {
+ print("*** please set a name before sending messages");
+ return;
+ }
+ if (m_chatroom == nullptr) {
+ print("*** no one is listening... please join a group");
+ return;
+ }
+ string msg = m_name;
+ msg += ": ";
+ msg += line.toUtf8().constData();
+ print("<you>: " + input()->text());
+ // NOTE: we have to use send_as(as_actor(), ...) outside of our
+ // message handler, because `self` is *not* set properly
+ // in this context
+ send_as(as_actor(), m_chatroom, std::move(msg));
+}
+
+void ChatWidget::joinGroup() {
+ if (m_name.empty()) {
+ QMessageBox::information(this,
+ "No Name, No Chat",
+ "Please set a name first.");
+ return;
+ }
+ auto gname = QInputDialog::getText(this,
+ "Join Group",
+ "Please enter a group as <module>:<id>",
+ QLineEdit::Normal,
+ "remote:chatroom@localhost:4242");
+ int pos = gname.indexOf(':');
+ if (pos < 0) {
+ QMessageBox::warning(this, "Not a Group", "Invalid format");
+ return;
+ }
+ string mod = gname.left(pos).toUtf8().constData();
+ string gid = gname.midRef(pos+1).toUtf8().constData();
+ group_ptr gptr;
+ try {
+ auto gptr = group::get(mod, gid);
+ send_as(as_actor(), as_actor(), atom("join"), gptr);
+ }
+ catch (exception& e) {
+ QMessageBox::critical(this, "Exception", e.what());
+ }
+}
+
+void ChatWidget::changeName() {
+ auto name = QInputDialog::getText(this, "Change Name", "Please enter a new name");
+ if (!name.isEmpty()) {
+ send_as(as_actor(), as_actor(), atom("setName"), name.toUtf8().constData());
+ }
+}
@@ -0,0 +1,56 @@
+#include <exception>
+
+#include <QWidget>
+#include <QLineEdit>
+#include <QTextEdit>
+
+#include "cppa/group.hpp"
+#include "cppa/qtsupport/actor_widget_mixin.hpp"
+
+class ChatWidget : public cppa::actor_widget_mixin<QWidget> {
+
+ Q_OBJECT
+
+ typedef cppa::actor_widget_mixin<QWidget> super;
+
+ public:
+
+ ChatWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0);
+
+ public slots:
+
+ void sendChatMessage();
+ void joinGroup();
+ void changeName();
+
+ private:
+
+ template<typename T>
+ T* get(T*& member, const char* name) {
+ if (member == nullptr) {
+ member = findChild<T*>(name);
+ if (member == nullptr)
+ throw std::runtime_error("unable to find child: "
+ + std::string(name));
+ }
+ return member;
+ }
+
+ inline QLineEdit* input() {
+ return get(m_input, "input");
+ }
+
+ inline QTextEdit* output() {
+ return get(m_output, "output");
+ }
+
+ inline void print(const QString& what) {
+ output()->append(what);
+ }
+
+ QLineEdit* m_input;
+ QTextEdit* m_output;
+ std::string m_name;
+ cppa::group_ptr m_chatroom;
+
+};
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChatWindow</class>
+ <widget class="QMainWindow" name="ChatWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="ChatWidget" name="chatwidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTextEdit" name="output">
+ <property name="focusPolicy">
+ <enum>Qt::ClickFocus</enum>
+ </property>
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="input">
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>File</string>
+ </property>
+ <addaction name="actionJoin_Group"/>
+ <addaction name="actionSet_Name"/>
+ </widget>
+ <addaction name="menuFile"/>
+ </widget>
+ <action name="actionJoin_Group">
+ <property name="text">
+ <string>Join Group</string>
+ </property>
+ </action>
+ <action name="actionSet_Name">
+ <property name="text">
+ <string>Set Name</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ChatWidget</class>
+ <extends>QWidget</extends>
+ <header>chatwidget.hpp</header>
+ <container>1</container>
+ <slots>
+ <slot>sendChatMessage()</slot>
+ <slot>changeName()</slot>
+ <slot>joinGroup()</slot>
+ </slots>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>actionJoin_Group</sender>
+ <signal>activated()</signal>
+ <receiver>chatwidget</receiver>
+ <slot>joinGroup()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>399</x>
+ <y>300</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>actionSet_Name</sender>
+ <signal>activated()</signal>
+ <receiver>chatwidget</receiver>
+ <slot>changeName()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>399</x>
+ <y>300</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>input</sender>
+ <signal>returnPressed()</signal>
+ <receiver>chatwidget</receiver>
+ <slot>sendChatMessage()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>362</x>
+ <y>547</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>399</x>
+ <y>310</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
Oops, something went wrong.

0 comments on commit 6bad5f9

Please sign in to comment.