Commit 366ba6bc authored by Alex Mantel's avatar Alex Mantel

Add qtsupport with Qt5 and Qt4

Reimplement example from V0.9.4.
parent a9b54271
...@@ -108,7 +108,7 @@ else() ...@@ -108,7 +108,7 @@ else()
message(STATUS "NOTE: Automatically added -stdlib=libc++ flag, " message(STATUS "NOTE: Automatically added -stdlib=libc++ flag, "
"you can override this by defining CMAKE_CXX_FLAGS " "you can override this by defining CMAKE_CXX_FLAGS "
"(see 'configure --help')") "(see 'configure --help')")
set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++") set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ -fPIC")
if(MORE_CLANG_WARNINGS) if(MORE_CLANG_WARNINGS)
set(CMAKE_CXX_FLAGS "-pedantic -Weverything -Wno-c++98-compat " set(CMAKE_CXX_FLAGS "-pedantic -Weverything -Wno-c++98-compat "
"-Wno-padded -Wno-documentation-unknown-command " "-Wno-padded -Wno-documentation-unknown-command "
...@@ -118,7 +118,7 @@ else() ...@@ -118,7 +118,7 @@ else()
"-Wno-unused-const-variable") "-Wno-unused-const-variable")
endif() endif()
else() else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic") set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic -fPIC")
endif() endif()
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
......
...@@ -5,11 +5,11 @@ add_custom_target(all_examples) ...@@ -5,11 +5,11 @@ add_custom_target(all_examples)
include_directories(${LIBCAF_INCLUDE_DIRS}) include_directories(${LIBCAF_INCLUDE_DIRS})
if (${CMAKE_SYSTEM_NAME} MATCHES "Window") if(${CMAKE_SYSTEM_NAME} MATCHES "Window")
set(WSLIB -lws2_32) set(WSLIB -lws2_32)
else () else ()
set(WSLIB) set(WSLIB)
endif () endif()
macro(add name folder) macro(add name folder)
add_executable(${name} ${folder}/${name}.cpp ${ARGN}) add_executable(${name} ${folder}/${name}.cpp ${ARGN})
...@@ -37,9 +37,9 @@ add(group_server remote_actors) ...@@ -37,9 +37,9 @@ add(group_server remote_actors)
add(group_chat remote_actors) add(group_chat remote_actors)
add(simple_broker remote_actors) add(simple_broker remote_actors)
if (NOT "${CAF_NO_PROTOBUF_EXAMPLES}" STREQUAL "yes") if(NOT CAF_NO_PROTOBUF_EXAMPLES)
find_package(Protobuf) find_package(Protobuf)
if (PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) if(PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders "${CMAKE_CURRENT_SOURCE_DIR}/remote_actors/pingpong.proto") PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders "${CMAKE_CURRENT_SOURCE_DIR}/remote_actors/pingpong.proto")
include_directories(${PROTOBUF_INCLUDE_DIR}) include_directories(${PROTOBUF_INCLUDE_DIR})
# add binary dir as include path as generated headers will be located there # add binary dir as include path as generated headers will be located there
...@@ -47,14 +47,66 @@ if (NOT "${CAF_NO_PROTOBUF_EXAMPLES}" STREQUAL "yes") ...@@ -47,14 +47,66 @@ if (NOT "${CAF_NO_PROTOBUF_EXAMPLES}" STREQUAL "yes")
add_executable(protobuf_broker remote_actors/protobuf_broker.cpp ${ProtoSources}) add_executable(protobuf_broker remote_actors/protobuf_broker.cpp ${ProtoSources})
target_link_libraries(protobuf_broker ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${PROTOBUF_LIBRARIES}) target_link_libraries(protobuf_broker ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${PROTOBUF_LIBRARIES})
add_dependencies(protobuf_broker all_examples) add_dependencies(protobuf_broker all_examples)
endif (PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE) endif(PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
endif () endif()
if (NOT "${CAF_NO_CURL_EXAMPLES}" STREQUAL "yes") if(NOT CAF_NO_QT_EXAMPLES)
find_package(Qt5 COMPONENTS Core Gui Widgets)
if(Qt5_FOUND)
message(STATUS "Found Qt5")
#include(${QT_USE_FILE})
QT5_ADD_RESOURCES(GROUP_CHAT_RCS )
QT5_WRAP_UI(GROUP_CHAT_UI_HDR qtsupport/chatwindow.ui)
QT5_WRAP_CPP(GROUP_CHAT_MOC_SRC qtsupport/chatwidget.hpp)
# generated headers will be in cmake build directory
#include_directories(. qtsupport ${CMAKE_CURRENT_BINARY_DIR} ${CPPA_INCLUDE})
include_directories(qtsupport
${CMAKE_CURRENT_BINARY_DIR}
${Qt5Core_INCLUDE_DIRS}
${Qt5Gui_INCLUDE_DIRS}
${Qt5Widgets_INCLUDE_DIRS})
set(GROUP_CHAT_SRC qtsupport/qt_group_chat.cpp qtsupport/chatwidget.cpp)
add_executable(qt_group_chat
${GROUP_CHAT_SRC}
${GROUP_CHAT_MOC_SRC}
${GROUP_CHAT_UI_HDR})
target_link_libraries(qt_group_chat
${CMAKE_DL_LIBS}
${LIBCAF_LIBRARIES}
Qt5::Core
Qt5::Gui
Qt5::Widgets)
add_dependencies(qt_group_chat all_examples)
else()
find_package(Qt4)
if(QT4_FOUND)
message(STATUS "Found Qt4")
include(${QT_USE_FILE})
QT4_ADD_RESOURCES(GROUP_CHAT_RCS )
QT4_WRAP_UI(GROUP_CHAT_UI_HDR qtsupport/chatwindow.ui)
QT4_WRAP_CPP(GROUP_CHAT_MOC_SRC qtsupport/chatwidget.hpp)
# generated headers will be in cmake build directory
#include_directories(. qtsupport ${CMAKE_CURRENT_BINARY_DIR} ${CPPA_INCLUDE})
include_directories(qtsupport ${CMAKE_CURRENT_BINARY_DIR})
set(GROUP_CHAT_SRCS qtsupport/qt_group_chat.cpp qtsupport/chatwidget.cpp)
add_executable(qt_group_chat
${GROUP_CHAT_SRCS}
${GROUP_CHAT_MOC_SRC}
${GROUP_CHAT_UI_HDR})
target_link_libraries(qt_group_chat
${CMAKE_DL_LIBS}
${LIBCAF_LIBRARIES}
${QT_LIBRARIES})
add_dependencies(qt_group_chat all_examples)
endif()
endif()
endif()
if(NOT CAF_NO_CURL_EXAMPLES)
find_package(CURL) find_package(CURL)
if (CURL_FOUND) if(CURL_FOUND)
add_executable(curl_fuse curl/curl_fuse.cpp) add_executable(curl_fuse curl/curl_fuse.cpp)
target_link_libraries(curl_fuse ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${CURL_LIBRARY}) target_link_libraries(curl_fuse ${CMAKE_DL_LIBS} ${LIBCAF_LIBRARIES} ${PTHREAD_LIBRARIES} ${CURL_LIBRARY})
add_dependencies(curl_fuse all_examples) add_dependencies(curl_fuse all_examples)
endif (CURL_FOUND) endif(CURL_FOUND)
endif () endif()
#include <string>
#include <utility>
#include <QMessageBox>
#include <QInputDialog>
#include "chatwidget.hpp"
#include "caf/all.hpp"
#include "caf/detail/scope_guard.hpp"
using namespace std;
using namespace caf;
ChatWidget::ChatWidget(QWidget* parent, Qt::WindowFlags f)
: super(parent, f), m_input(nullptr), m_output(nullptr) {
set_message_handler ([=](local_actor* self) -> message_handler {
return {
on(atom("join"), arg_match) >> [=](const group& what) {
if (m_chatroom) {
self->send(m_chatroom, m_name + " has left the chatroom");
self->leave(m_chatroom);
}
self->join(what);
print(("*** joined " + to_string(what)).c_str());
m_chatroom = what;
self->send(what, m_name + " has entered the chatroom");
},
on(atom("setName"), arg_match) >> [=](string& name) {
self->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
},
[=](const string& txt) {
// don't print own messages
if (self != self->last_sender()) {
print(QString::fromUtf8(txt.c_str()));
}
},
[=](const group_down_msg& gdm) {
print("*** chatroom offline: "
+ QString::fromUtf8(to_string(gdm.source).c_str()));
}
};
});
}
void ChatWidget::sendChatMessage() {
auto cleanup = detail::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 gptr;
try { gptr = group::get(mod, g); }
catch (exception& e) {
print("*** exception: " + QString::fromUtf8((e.what())));
}
if (gptr) {
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) {
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();
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());
}
}
#include <exception>
#include <QWidget>
#include <QLineEdit>
#include <QTextEdit>
#include "caf/all.hpp"
#include "caf/mixin/actor_widget.hpp"
class ChatWidget : public caf::mixin::actor_widget<QWidget> {
Q_OBJECT
typedef caf::mixin::actor_widget<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;
caf::group m_chatroom;
};
<?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>
/******************************************************************************\
* This example program represents a minimal GUI chat program *
* based on group communication. This chat program is compatible to the *
* terminal version in remote_actors/group_chat.cpp. *
* *
* Setup for a minimal chat between "alice" and "bob": *
* - ./build/bin/group_server -p 4242 *
* - ./build/bin/qt_group_chat -g remote:chatroom@localhost:4242 -n alice *
* - ./build/bin/qt_group_chat -g remote:chatroom@localhost:4242 -n bob *
\******************************************************************************/
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <sstream>
#include <time.h>
#include <cstdlib>
#include <QMainWindow>
#include <QApplication>
#include "caf/all.hpp"
#include "cppa/opt.hpp"
#include "ui_chatwindow.h" // auto generated from chatwindow.ui
using namespace std;
using namespace caf;
/*
namespace {
struct line { string str; };
istream& operator>>(istream& is, line& l) {
getline(is, l.str);
return is;
}
any_tuple s_last_line;
any_tuple split_line(const line& l) {
vector<string> result;
stringstream strs(l.str);
string tmp;
while (getline(strs, tmp, ' ')) {
if (!tmp.empty()) result.push_back(std::move(tmp));
}
s_last_line = any_tuple::view(std::move(result));
return s_last_line;
}
} // namespace <anonymous>
*/
int main(int argc, char** argv) {
string name;
string group_id;
options_description desc;
bool args_valid = match_stream<string>(argv + 1, argv + argc) (
on_opt1('n', "name", &desc, "set name") >> rd_arg(name),
on_opt1('g', "group", &desc, "join group <arg1>") >> rd_arg(group_id),
on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
group gptr;
// evaluate group parameter
if (!group_id.empty()) {
auto p = group_id.find(':');
if (p == std::string::npos) {
cerr << "*** error parsing argument " << group_id
<< ", expected format: <module_name>:<group_id>";
}
else {
try {
gptr = group::get(group_id.substr(0, p),
group_id.substr(p + 1));
}
catch (exception& e) {
ostringstream err;
cerr << "*** exception: group::get(\"" << group_id.substr(0, p)
<< "\", \"" << group_id.substr(p + 1) << "\") failed; "
<< to_verbose_string(e) << endl;
}
}
}
if (!args_valid) print_desc_and_exit(&desc)();
QApplication app(argc, argv);
app.setQuitOnLastWindowClosed(true);
QMainWindow mw;
Ui::ChatWindow helper;
helper.setupUi(&mw);
auto client = helper.chatwidget->as_actor();
if (!name.empty()) {
send_as(client, client, atom("setName"), move(name));
}
if (gptr) {
send_as(client, client, atom("join"), gptr);
}
mw.show();
auto res = app.exec();
shutdown();
await_all_actors_done();
return res;
}
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcaf. *
* libcaf is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcaf is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcaf. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_ACTOR_WIDGET_MIXIN_HPP
#define CPPA_ACTOR_WIDGET_MIXIN_HPP
#include <QEvent>
#include <QApplication>
#include "caf/actor_companion.hpp"
#include "caf/message_handler.hpp"
#include "caf/policy/sequential_invoke.hpp"
namespace caf {
namespace mixin {
template<typename Base, int EventId = static_cast<int>(QEvent::User + 31337)>
class actor_widget : public Base {
public:
typedef typename actor_companion::message_pointer message_pointer;
struct event_type : public QEvent {
message_pointer mptr;
event_type(message_pointer ptr)
: QEvent(static_cast<QEvent::Type>(EventId)), mptr(std::move(ptr)) { }
};
template<typename... Ts>
actor_widget(Ts&&... args) : Base(std::forward<Ts>(args)...) {
m_companion.reset(detail::memory::create<actor_companion>());
m_companion->on_enqueue([=](message_pointer ptr) {
qApp->postEvent(this, new event_type(std::move(ptr)));
});
}
template<typename T>
void set_message_handler(T pfun) {
m_companion->become(pfun(m_companion.get()));
}
virtual bool event(QEvent* event) {
if (event->type() == static_cast<QEvent::Type>(EventId)) {
auto ptr = dynamic_cast<event_type*>(event);
if (ptr) {
m_invoke.handle_message(m_companion.get(),
ptr->mptr.release(),
m_companion->bhvr_stack().back(),
m_companion->bhvr_stack().back_id());
return true;
}
}
return Base::event(event);
}
actor as_actor() const {
return m_companion;
}
private:
policy::sequential_invoke m_invoke;
actor_companion_ptr m_companion;
};
} // namespace mixin
} // namespace caf
#endif // CPPA_ACTOR_WIDGET_MIXIN_HPP
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment