first commit

This commit is contained in:
sanya
2025-09-01 14:20:39 +00:00
committed by ExternPointer
commit 490fc11f6a
4328 changed files with 1796224 additions and 0 deletions

View File

@@ -0,0 +1 @@
SioChatDemo.pro.user

View File

@@ -0,0 +1,44 @@
#-------------------------------------------------
#
# Project created by QtCreator 2015-03-30T19:25:23
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = SioChatDemo
TEMPLATE = app
CONFIG+=no_keywords
CONFIG+=c++11
SOURCES += main.cpp\
mainwindow.cpp \
nicknamedialog.cpp
HEADERS += mainwindow.h \
nicknamedialog.h
FORMS += mainwindow.ui \
nicknamedialog.ui
CONFIG(debug, debug|release):DEFINES +=DEBUG=1
INCLUDEPATH += $$PWD/../../../build/include
DEPENDPATH += $$PWD/../../../build/lib
CONFIG(release, debug|release): LIBS += -L$$PWD/../../../build/lib/Release/ -lsioclient
else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../build/lib/Debug/ -lsioclient
CONFIG(release, debug|release): LIBS += -L$$PWD/../../../build/lib/Release/ -lboost_random
else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../build/lib/Debug/ -lboost_random
CONFIG(release, debug|release): LIBS += -L$$PWD/../../../build/lib/Release/ -lboost_system
else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../build/lib/Debug/ -lboost_system
CONFIG(release, debug|release): LIBS += -L$$PWD/../../../build/lib/Release/ -lboost_date_time
else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../build/lib/Debug/ -lboost_date_time

View File

@@ -0,0 +1,4 @@
osx/*
src/*
src
osx

View File

@@ -0,0 +1,378 @@
#===============================================================================
# Filename: boost.sh
# Author: Pete Goodliffe
# Copyright: (c) Copyright 2009 Pete Goodliffe
# Licence: Please feel free to use this, with attribution
# Modified version
#===============================================================================
#
# Builds a Boost framework for the iPhone.
# Creates a set of universal libraries that can be used on an iPhone and in the
# iPhone simulator. Then creates a pseudo-framework to make using boost in Xcode
# less painful.
#
# To configure the script, define:
# BOOST_LIBS: which libraries to build
# IPHONE_SDKVERSION: iPhone SDK version (e.g. 5.1)
#
# Then go get the source tar.bz of the boost you want to build, shove it in the
# same directory as this script, and run "./boost.sh". Grab a cuppa. And voila.
#===============================================================================
: ${BOOST_LIBS:="random regex graph random chrono thread signals filesystem system date_time"}
: ${IPHONE_SDKVERSION:=`xcodebuild -showsdks | grep iphoneos | egrep "[[:digit:]]+\.[[:digit:]]+" -o | tail -1`}
: ${OSX_SDKVERSION:=10.8}
: ${XCODE_ROOT:=`xcode-select -print-path`}
: ${EXTRA_CPPFLAGS:="-DBOOST_AC_USE_PTHREADS -DBOOST_SP_USE_PTHREADS -std=c++11 -stdlib=libc++"}
# The EXTRA_CPPFLAGS definition works around a thread race issue in
# shared_ptr. I encountered this historically and have not verified that
# the fix is no longer required. Without using the posix thread primitives
# an invalid compare-and-swap ARM instruction (non-thread-safe) was used for the
# shared_ptr use count causing nasty and subtle bugs.
#
# Should perhaps also consider/use instead: -BOOST_SP_USE_PTHREADS
: ${TARBALLDIR:=`pwd`}
: ${SRCDIR:=`pwd`/src}
: ${IOSBUILDDIR:=`pwd`/ios/build}
: ${OSXBUILDDIR:=`pwd`/osx/build}
: ${PREFIXDIR:=`pwd`/ios/prefix}
: ${IOSFRAMEWORKDIR:=`pwd`/ios/framework}
: ${OSXFRAMEWORKDIR:=`pwd`/osx/framework}
: ${COMPILER:="clang++"}
: ${BOOST_VERSION:=1.55.0}
: ${BOOST_VERSION2:=1_55_0}
BOOST_TARBALL=$TARBALLDIR/boost_$BOOST_VERSION2.tar.bz2
BOOST_SRC=$SRCDIR/boost_${BOOST_VERSION2}
#===============================================================================
ARM_DEV_CMD="xcrun --sdk iphoneos"
SIM_DEV_CMD="xcrun --sdk iphonesimulator"
OSX_DEV_CMD="xcrun --sdk macosx"
ARM_COMBINED_LIB=$IOSBUILDDIR/lib_boost_arm.a
SIM_COMBINED_LIB=$IOSBUILDDIR/lib_boost_x86.a
#===============================================================================
#===============================================================================
# Functions
#===============================================================================
abort()
{
echo
echo "Aborted: $@"
exit 1
}
doneSection()
{
echo
echo "================================================================="
echo "Done"
echo
}
#===============================================================================
cleanEverythingReadyToStart()
{
echo Cleaning everything before we start to build...
rm -rf iphone-build iphonesim-build osx-build
rm -rf $IOSBUILDDIR
rm -rf $OSXBUILDDIR
rm -rf $PREFIXDIR
rm -rf $IOSFRAMEWORKDIR/$FRAMEWORK_NAME.framework
rm -rf $OSXFRAMEWORKDIR/$FRAMEWORK_NAME.framework
doneSection
}
#===============================================================================
downloadBoost()
{
if [ ! -s $TARBALLDIR/boost_${BOOST_VERSION2}.tar.bz2 ]; then
echo "Downloading boost ${BOOST_VERSION}"
curl -L -o $TARBALLDIR/boost_${BOOST_VERSION2}.tar.bz2 http://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/boost_${BOOST_VERSION2}.tar.bz2/download
fi
doneSection
}
#===============================================================================
unpackBoost()
{
[ -f "$BOOST_TARBALL" ] || abort "Source tarball missing."
echo Unpacking boost into $SRCDIR...
[ -d $SRCDIR ] || mkdir -p $SRCDIR
[ -d $BOOST_SRC ] || ( cd $SRCDIR; tar xfj $BOOST_TARBALL )
[ -d $BOOST_SRC ] && echo " ...unpacked as $BOOST_SRC"
doneSection
}
#===============================================================================
restoreBoost()
{
cp $BOOST_SRC/tools/build/v2/user-config.jam-bk $BOOST_SRC/tools/build/v2/user-config.jam
}
#===============================================================================
updateBoost()
{
echo Updating boost into $BOOST_SRC...
cp $BOOST_SRC/tools/build/v2/user-config.jam $BOOST_SRC/tools/build/v2/user-config.jam-bk
cat >> $BOOST_SRC/tools/build/v2/user-config.jam <<EOF
using darwin : ${IPHONE_SDKVERSION}~iphone
: $XCODE_ROOT/Toolchains/XcodeDefault.xctoolchain/usr/bin/$COMPILER -arch armv6 -arch armv7 -arch armv7s -arch arm64 -fvisibility=hidden -fvisibility-inlines-hidden $EXTRA_CPPFLAGS
: <striper> <root>$XCODE_ROOT/Platforms/iPhoneOS.platform/Developer
: <architecture>arm <target-os>iphone
;
using darwin : ${IPHONE_SDKVERSION}~iphonesim
: $XCODE_ROOT/Toolchains/XcodeDefault.xctoolchain/usr/bin/$COMPILER -arch i386 -arch x86_64 -fvisibility=hidden -fvisibility-inlines-hidden $EXTRA_CPPFLAGS
: <striper> <root>$XCODE_ROOT/Platforms/iPhoneSimulator.platform/Developer
: <architecture>x86 <target-os>iphone
;
EOF
doneSection
}
#===============================================================================
inventMissingHeaders()
{
# These files are missing in the ARM iPhoneOS SDK, but they are in the simulator.
# They are supported on the device, so we copy them from x86 SDK to a staging area
# to use them on ARM, too.
echo Invent missing headers
cp $XCODE_ROOT/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${IPHONE_SDKVERSION}.sdk/usr/include/{crt_externs,bzlib}.h $BOOST_SRC
}
#===============================================================================
bootstrapBoost()
{
cd $BOOST_SRC
BOOST_LIBS_COMMA=$(echo $BOOST_LIBS | sed -e "s/ /,/g")
echo "Bootstrapping (with libs $BOOST_LIBS_COMMA)"
./bootstrap.sh --with-libraries=$BOOST_LIBS_COMMA
doneSection
}
#===============================================================================
buildBoostForIPhoneOS()
{
cd $BOOST_SRC
# Install this one so we can copy the includes for the frameworks...
./bjam -j16 --build-dir=iphone-build --stagedir=iphone-build/stage --prefix=$PREFIXDIR toolset=darwin architecture=arm target-os=iphone macosx-version=iphone-${IPHONE_SDKVERSION} define=_LITTLE_ENDIAN link=static stage
./bjam -j16 --build-dir=iphone-build --stagedir=iphone-build/stage --prefix=$PREFIXDIR toolset=darwin architecture=arm target-os=iphone macosx-version=iphone-${IPHONE_SDKVERSION} define=_LITTLE_ENDIAN link=static install
doneSection
./bjam -j16 --build-dir=iphonesim-build --stagedir=iphonesim-build/stage --toolset=darwin-${IPHONE_SDKVERSION}~iphonesim architecture=x86 target-os=iphone macosx-version=iphonesim-${IPHONE_SDKVERSION} link=static stage
doneSection
# ./b2 -j16 --build-dir=osx-build --stagedir=osx-build/stage toolset=clang cxxflags="-std=c++11 -stdlib=libc++ -arch i386 -arch x86_64" linkflags="-stdlib=libc++" link=static threading=multi stage
doneSection
}
#===============================================================================
scrunchAllLibsTogetherInOneLibPerPlatform()
{
cd $BOOST_SRC
mkdir -p $IOSBUILDDIR/armv6/obj
mkdir -p $IOSBUILDDIR/armv7/obj
mkdir -p $IOSBUILDDIR/armv7s/obj
mkdir -p $IOSBUILDDIR/arm64/obj
mkdir -p $IOSBUILDDIR/i386/obj
mkdir -p $IOSBUILDDIR/x86_64/obj
mkdir -p $OSXBUILDDIR/i386/obj
mkdir -p $OSXBUILDDIR/x86_64/obj
ALL_LIBS=""
echo Splitting all existing fat binaries...
for NAME in $BOOST_LIBS; do
ALL_LIBS="$ALL_LIBS libboost_$NAME.a"
$ARM_DEV_CMD lipo "iphone-build/stage/lib/libboost_$NAME.a" -thin armv6 -o $IOSBUILDDIR/armv6/libboost_$NAME.a
$ARM_DEV_CMD lipo "iphone-build/stage/lib/libboost_$NAME.a" -thin armv7 -o $IOSBUILDDIR/armv7/libboost_$NAME.a
$ARM_DEV_CMD lipo "iphone-build/stage/lib/libboost_$NAME.a" -thin armv7s -o $IOSBUILDDIR/armv7s/libboost_$NAME.a
$ARM_DEV_CMD lipo "iphone-build/stage/lib/libboost_$NAME.a" -thin arm64 -o $IOSBUILDDIR/arm64/libboost_$NAME.a
$ARM_DEV_CMD lipo "iphonesim-build/stage/lib/libboost_$NAME.a" -thin i386 -o $IOSBUILDDIR/i386/libboost_$NAME.a
$ARM_DEV_CMD lipo "iphonesim-build/stage/lib/libboost_$NAME.a" -thin x86_64 -o $IOSBUILDDIR/x86_64/libboost_$NAME.a
$ARM_DEV_CMD lipo "osx-build/stage/lib/libboost_$NAME.a" -thin i386 -o $OSXBUILDDIR/i386/libboost_$NAME.a
$ARM_DEV_CMD lipo "osx-build/stage/lib/libboost_$NAME.a" -thin x86_64 -o $OSXBUILDDIR/x86_64/libboost_$NAME.a
done
echo "Decomposing each architecture's .a files"
for NAME in $ALL_LIBS; do
echo Decomposing $NAME...
(cd $IOSBUILDDIR/armv6/obj; ar -x ../$NAME );
(cd $IOSBUILDDIR/armv7/obj; ar -x ../$NAME );
(cd $IOSBUILDDIR/armv7s/obj; ar -x ../$NAME );
(cd $IOSBUILDDIR/arm64/obj; ar -x ../$NAME );
(cd $IOSBUILDDIR/i386/obj; ar -x ../$NAME );
(cd $IOSBUILDDIR/x86_64/obj; ar -x ../$NAME );
(cd $OSXBUILDDIR/i386/obj; ar -x ../$NAME );
(cd $OSXBUILDDIR/x86_64/obj; ar -x ../$NAME );
done
echo "Linking each architecture into an uberlib ($ALL_LIBS => libboost.a )"
rm $IOSBUILDDIR/*/libboost.a
echo ...armv6
(cd $IOSBUILDDIR/armv6; $ARM_DEV_CMD ar crus libboost.a obj/*.o; )
echo ...armv7
(cd $IOSBUILDDIR/armv7; $ARM_DEV_CMD ar crus libboost.a obj/*.o; )
echo ...armv7s
(cd $IOSBUILDDIR/armv7s; $ARM_DEV_CMD ar crus libboost.a obj/*.o; )
echo ...arm64
(cd $IOSBUILDDIR/arm64; $ARM_DEV_CMD ar crus libboost.a obj/*.o; )
echo ...i386
(cd $IOSBUILDDIR/i386; $SIM_DEV_CMD ar crus libboost.a obj/*.o; )
echo ...x86_64
(cd $IOSBUILDDIR/x86_64; $SIM_DEV_CMD ar crus libboost.a obj/*.o; )
rm $OSXBUILDDIR/*/libboost.a
echo ...osx-i386
(cd $OSXBUILDDIR/i386; $SIM_DEV_CMD ar crus libboost.a obj/*.o; )
echo ...x86_64
(cd $OSXBUILDDIR/x86_64; $SIM_DEV_CMD ar crus libboost.a obj/*.o; )
}
#===============================================================================
buildFramework()
{
: ${1:?}
FRAMEWORKDIR=$1
BUILDDIR=$2
VERSION_TYPE=Alpha
FRAMEWORK_NAME=boost
FRAMEWORK_VERSION=A
FRAMEWORK_CURRENT_VERSION=$BOOST_VERSION
FRAMEWORK_COMPATIBILITY_VERSION=$BOOST_VERSION
FRAMEWORK_BUNDLE=$FRAMEWORKDIR/$FRAMEWORK_NAME.framework
echo "Framework: Building $FRAMEWORK_BUNDLE from $BUILDDIR..."
rm -rf $FRAMEWORK_BUNDLE
echo "Framework: Setting up directories..."
mkdir -p $FRAMEWORK_BUNDLE
mkdir -p $FRAMEWORK_BUNDLE/Versions
mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION
mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/Resources
mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/Headers
mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/Documentation
echo "Framework: Creating symlinks..."
ln -s $FRAMEWORK_VERSION $FRAMEWORK_BUNDLE/Versions/Current
ln -s Versions/Current/Headers $FRAMEWORK_BUNDLE/Headers
ln -s Versions/Current/Resources $FRAMEWORK_BUNDLE/Resources
ln -s Versions/Current/Documentation $FRAMEWORK_BUNDLE/Documentation
ln -s Versions/Current/$FRAMEWORK_NAME $FRAMEWORK_BUNDLE/$FRAMEWORK_NAME
FRAMEWORK_INSTALL_NAME=$FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/$FRAMEWORK_NAME
echo "Lipoing library into $FRAMEWORK_INSTALL_NAME..."
$ARM_DEV_CMD lipo -create $BUILDDIR/*/libboost.a -o "$FRAMEWORK_INSTALL_NAME" || abort "Lipo $1 failed"
echo "Framework: Copying includes..."
cp -r $PREFIXDIR/include/boost/* $FRAMEWORK_BUNDLE/Headers/
echo "Framework: Creating plist..."
cat > $FRAMEWORK_BUNDLE/Resources/Info.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${FRAMEWORK_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.boost</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${FRAMEWORK_CURRENT_VERSION}</string>
</dict>
</plist>
EOF
doneSection
}
#===============================================================================
# Execution starts here
#===============================================================================
mkdir -p $IOSBUILDDIR
cleanEverythingReadyToStart #may want to comment if repeatedly running during dev
restoreBoost
echo "BOOST_VERSION: $BOOST_VERSION"
echo "BOOST_LIBS: $BOOST_LIBS"
echo "BOOST_SRC: $BOOST_SRC"
echo "IOSBUILDDIR: $IOSBUILDDIR"
echo "OSXBUILDDIR: $OSXBUILDDIR"
echo "PREFIXDIR: $PREFIXDIR"
echo "IOSFRAMEWORKDIR: $IOSFRAMEWORKDIR"
echo "OSXFRAMEWORKDIR: $OSXFRAMEWORKDIR"
echo "IPHONE_SDKVERSION: $IPHONE_SDKVERSION"
echo "XCODE_ROOT: $XCODE_ROOT"
echo "COMPILER: $COMPILER"
echo
downloadBoost
unpackBoost
inventMissingHeaders
bootstrapBoost
updateBoost
buildBoostForIPhoneOS
scrunchAllLibsTogetherInOneLibPerPlatform
buildFramework $IOSFRAMEWORKDIR $IOSBUILDDIR
buildFramework $OSXFRAMEWORKDIR $OSXBUILDDIR
restoreBoost
echo "Completed successfully"
#===============================================================================

View File

@@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

View File

@@ -0,0 +1,291 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <functional>
#include <mutex>
#include <cstdlib>
#define kURL "ws://localhost:3000"
#ifdef WIN32
#define BIND_EVENT(IO,EV,FN) \
do{ \
socket::event_listener_aux l = FN;\
IO->on(EV,l);\
} while(0)
#else
#define BIND_EVENT(IO,EV,FN) \
IO->on(EV,FN)
#endif
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
_io(new client()),
m_typingItem(NULL),
m_dialog()
{
ui->setupUi(this);
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;
socket::ptr sock = _io->socket();
BIND_EVENT(sock,"new message",std::bind(&MainWindow::OnNewMessage,this,_1,_2,_3,_4));
BIND_EVENT(sock,"user joined",std::bind(&MainWindow::OnUserJoined,this,_1,_2,_3,_4));
BIND_EVENT(sock,"user left",std::bind(&MainWindow::OnUserLeft,this,_1,_2,_3,_4));
BIND_EVENT(sock,"typing",std::bind(&MainWindow::OnTyping,this,_1,_2,_3,_4));
BIND_EVENT(sock,"stop typing",std::bind(&MainWindow::OnStopTyping,this,_1,_2,_3,_4));
BIND_EVENT(sock,"login",std::bind(&MainWindow::OnLogin,this,_1,_2,_3,_4));
_io->set_socket_open_listener(std::bind(&MainWindow::OnConnected,this,std::placeholders::_1));
_io->set_close_listener(std::bind(&MainWindow::OnClosed,this,_1));
_io->set_fail_listener(std::bind(&MainWindow::OnFailed,this));
connect(this,SIGNAL(RequestAddListItem(QListWidgetItem*)),this,SLOT(AddListItem(QListWidgetItem*)));
connect(this,SIGNAL(RequestRemoveListItem(QListWidgetItem*)),this,SLOT(RemoveListItem(QListWidgetItem*)));
connect(this,SIGNAL(RequestToggleInputs(bool)),this,SLOT(ToggleInputs(bool)));
}
MainWindow::~MainWindow()
{
_io->socket()->off_all();
_io->socket()->off_error();
delete ui;
}
void MainWindow::SendBtnClicked()
{
QLineEdit* messageEdit = this->findChild<QLineEdit*>("messageEdit");
QString text = messageEdit->text();
if(text.length()>0)
{
QByteArray bytes = text.toUtf8();
std::string msg(bytes.data(),bytes.length());
_io->socket()->emit("new message",msg);
text.append(" : You");
QListWidgetItem *item = new QListWidgetItem(text);
item->setTextAlignment(Qt::AlignRight);
Q_EMIT RequestAddListItem(item);
messageEdit->clear();
}
}
void MainWindow::OnMessageReturn()
{
this->SendBtnClicked();
}
void MainWindow::ShowLoginDialog()
{
m_dialog.reset(new NicknameDialog(this));
connect(m_dialog.get(),SIGNAL(accepted()),this,SLOT(NicknameAccept()));
connect(m_dialog.get(),SIGNAL(rejected()),this,SLOT(NicknameCancelled()));
m_dialog->exec();
}
void MainWindow::showEvent(QShowEvent *event)
{
ShowLoginDialog();
}
void MainWindow::TypingStop()
{
m_timer.reset();
_io->socket()->emit("stop typing");
}
void MainWindow::TypingChanged()
{
if(m_timer&&m_timer->isActive())
{
m_timer->stop();
}
else
{
_io->socket()->emit("typing");
}
m_timer.reset(new QTimer(this));
connect(m_timer.get(),SIGNAL(timeout()),this,SLOT(TypingStop()));
m_timer->setSingleShot(true);
m_timer->start(1000);
}
void MainWindow::NicknameAccept()
{
m_name = m_dialog->getNickname();
if(m_name.length()>0)
{
_io->connect(kURL);
}
}
void MainWindow::NicknameCancelled()
{
QApplication::exit();
}
void MainWindow::AddListItem(QListWidgetItem* item)
{
this->findChild<QListWidget*>("listView")->addItem(item);
}
void MainWindow::RemoveListItem(QListWidgetItem* item)
{
QListWidget* list = this->findChild<QListWidget*>("listView");
int row = list->row(item);
delete list->takeItem(row);
}
void MainWindow::OnNewMessage(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp)
{
if(data->get_flag() == message::flag_object)
{
std::string msg = data->get_map()["message"]->get_string();
std::string username = data->get_map()["username"]->get_string();
QString label = QString::fromUtf8(username.data(),username.length());
label.append(" : ");
label.append(QString::fromUtf8(msg.data(),msg.length()));
QListWidgetItem *item= new QListWidgetItem(label);
Q_EMIT RequestAddListItem(item);
}
}
void MainWindow::OnUserJoined(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp)
{
if(data->get_flag() == message::flag_object)
{
std::string name = data->get_map()["username"]->get_string();
int numUser = data->get_map()["numUsers"]->get_int();
QString label = QString::fromUtf8(name.data(),name.length());
bool plural = numUser != 1;
label.append(" joined\n");
label.append(plural?"there are ":"there's ");
QString digits;
while(numUser>=10)
{
digits.insert(0,QChar((numUser%10)+'0'));
numUser/=10;
}
digits.insert(0,QChar(numUser+'0'));
label.append(digits);
label.append(plural?" participants":" participant");
QListWidgetItem *item= new QListWidgetItem(label);
item->setTextAlignment(Qt::AlignHCenter);
QFont font;
font.setPointSize(9);
item->setFont(font);
Q_EMIT RequestAddListItem(item);
}
}
void MainWindow::OnUserLeft(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp)
{
if(data->get_flag() == message::flag_object)
{
std::string name = data->get_map()["username"]->get_string();
int numUser = data->get_map()["numUsers"]->get_int();
QString label = QString::fromUtf8(name.data(),name.length());
bool plural = numUser != 1;
label.append(" left\n");
label.append(plural?"there are ":"there's ");
QString digits;
while(numUser>=10)
{
digits.insert(0,QChar((numUser%10)+'0'));
numUser/=10;
}
digits.insert(0,QChar(numUser+'0'));
label.append(digits);
label.append(plural?" participants":" participant");
QListWidgetItem *item= new QListWidgetItem(label);
item->setTextAlignment(Qt::AlignHCenter);
QFont font;
font.setPointSize(9);
item->setFont(font);
Q_EMIT RequestAddListItem(item);
}
}
void MainWindow::OnTyping(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp)
{
if(m_typingItem == NULL)
{
std::string name = data->get_map()["username"]->get_string();
QString label = QString::fromUtf8(name.data(),name.length());
label.append(" is typing...");
QListWidgetItem *item = new QListWidgetItem(label);
item->setTextColor(QColor(200,200,200,255));
m_typingItem = item;
Q_EMIT RequestAddListItem(item);
}
}
void MainWindow::OnStopTyping(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp)
{
if(m_typingItem != NULL)
{
Q_EMIT RequestRemoveListItem(m_typingItem);
m_typingItem = NULL;
}
}
void MainWindow::OnLogin(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp)
{
Q_EMIT RequestToggleInputs(true);
int numUser = data->get_map()["numUsers"]->get_int();
QString digits;
bool plural = numUser !=1;
while(numUser>=10)
{
digits.insert(0,QChar((numUser%10)+'0'));
numUser/=10;
}
digits.insert(0,QChar(numUser+'0'));
digits.insert(0,plural?"there are ":"there's ");
digits.append(plural? " participants":" participant");
QListWidgetItem *item = new QListWidgetItem(digits);
item->setTextAlignment(Qt::AlignHCenter);
QFont font;
font.setPointSize(9);
item->setFont(font);
Q_EMIT RequestAddListItem(item);
}
void MainWindow::OnConnected(std::string const& nsp)
{
QByteArray bytes = m_name.toUtf8();
std::string nickName(bytes.data(),bytes.length());
_io->socket()->emit("add user", nickName);
}
void MainWindow::OnClosed(client::close_reason const& reason)
{
Q_EMIT RequestToggleInputs(false);
}
void MainWindow::OnFailed()
{
Q_EMIT RequestToggleInputs(false);
}
void MainWindow::ToggleInputs(bool loginOrNot)
{
if(loginOrNot)//already login
{
this->findChild<QWidget*>("messageEdit")->setEnabled(true);
this->findChild<QWidget*>("listView")->setEnabled(true);
// this->findChild<QWidget*>("sendBtn")->setEnabled(true);
}
else
{
this->findChild<QWidget*>("messageEdit")->setEnabled(false);
this->findChild<QWidget*>("listView")->setEnabled(false);
// this->findChild<QWidget*>("sendBtn")->setEnabled(false);
ShowLoginDialog();
}
}

View File

@@ -0,0 +1,68 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QListWidget>
#include <QPushButton>
#include <QPlainTextEdit>
#include <QTimer>
#include <sio_client.h>
#include "nicknamedialog.h"
namespace Ui {
class MainWindow;
}
using namespace sio;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public Q_SLOTS:
void SendBtnClicked();
void TypingChanged();
void OnMessageReturn();
protected:
void showEvent(QShowEvent* event);
Q_SIGNALS:
void RequestAddListItem(QListWidgetItem *item);
void RequestRemoveListItem(QListWidgetItem *item);
void RequestToggleInputs(bool loginOrNot);
private Q_SLOTS:
void AddListItem(QListWidgetItem *item);
void RemoveListItem(QListWidgetItem *item);
void ToggleInputs(bool loginOrNot);
void TypingStop();
void NicknameAccept();
void NicknameCancelled();
private:
void OnNewMessage(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp);
void OnUserJoined(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp);
void OnUserLeft(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp);
void OnTyping(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp);
void OnStopTyping(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp);
void OnLogin(std::string const& name,message::ptr const& data,bool hasAck,message::list &ack_resp);
void OnConnected(std::string const& nsp);
void OnClosed(client::close_reason const& reason);
void OnFailed();
void ShowLoginDialog();
Ui::MainWindow *ui;
std::unique_ptr<client> _io;
std::unique_ptr<NicknameDialog> m_dialog;
QString m_name;
std::unique_ptr<QTimer> m_timer;
QListWidgetItem *m_typingItem;
};
#endif // MAINWINDOW_H

View File

@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>366</width>
<height>549</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Socket.IO Chat</string>
</property>
<property name="unifiedTitleAndToolBarOnMac">
<bool>false</bool>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QListWidget" name="listView">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>8</x>
<y>11</y>
<width>350</width>
<height>461</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
<widget class="QLineEdit" name="messageEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>8</x>
<y>480</y>
<width>350</width>
<height>21</height>
</rect>
</property>
<property name="placeholderText">
<string>Type here...</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>366</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections>
<connection>
<sender>messageEdit</sender>
<signal>returnPressed()</signal>
<receiver>MainWindow</receiver>
<slot>OnMessageReturn()</slot>
<hints>
<hint type="sourcelabel">
<x>116</x>
<y>524</y>
</hint>
<hint type="destinationlabel">
<x>30</x>
<y>545</y>
</hint>
</hints>
</connection>
<connection>
<sender>messageEdit</sender>
<signal>textChanged(QString)</signal>
<receiver>MainWindow</receiver>
<slot>TypingChanged()</slot>
<hints>
<hint type="sourcelabel">
<x>73</x>
<y>531</y>
</hint>
<hint type="destinationlabel">
<x>70</x>
<y>510</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>SendBtnClicked(bool)</slot>
<slot>TypingChanged()</slot>
<slot>LoginClicked()</slot>
<slot>OnMessageReturn()</slot>
<slot>SendBtnClicked()</slot>
</slots>
</ui>

View File

@@ -0,0 +1,38 @@
#include "nicknamedialog.h"
#include "ui_nicknamedialog.h"
#include <QTimer>
NicknameDialog::NicknameDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::NicknameDialog)
{
ui->setupUi(this);
}
NicknameDialog::~NicknameDialog()
{
delete ui;
}
const QString& NicknameDialog::getNickname() const
{
return m_nickName;
}
void NicknameDialog::exitApp()
{
QApplication::quit();
}
void NicknameDialog::closeEvent(QCloseEvent *event)
{
QTimer::singleShot(0,this,SLOT(exitApp()));
}
void NicknameDialog::accept()
{
if(this->findChild<QLineEdit*>("nicknameEdit")->text().length()>0)
{
m_nickName = this->findChild<QLineEdit*>("nicknameEdit")->text();
done(QDialog::Accepted);
}
}

View File

@@ -0,0 +1,28 @@
#ifndef NICKNAMEDIALOG_H
#define NICKNAMEDIALOG_H
#include <QDialog>
namespace Ui {
class NicknameDialog;
}
class NicknameDialog : public QDialog
{
Q_OBJECT
public Q_SLOTS:
void accept();
void exitApp();
public:
explicit NicknameDialog(QWidget *parent = 0);
~NicknameDialog();
const QString& getNickname() const;
void closeEvent(QCloseEvent *);
private:
Ui::NicknameDialog *ui;
QString m_nickName;
};
#endif // NICKNAMEDIALOG_H

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NicknameDialog</class>
<widget class="QDialog" name="NicknameDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>366</width>
<height>151</height>
</rect>
</property>
<property name="windowTitle">
<string>Login</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>30</x>
<y>99</y>
<width>311</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QLineEdit" name="nicknameEdit">
<property name="geometry">
<rect>
<x>27</x>
<y>60</y>
<width>311</width>
<height>20</height>
</rect>
</property>
<property name="placeholderText">
<string>Type nickname here...</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>44</x>
<y>23</y>
<width>271</width>
<height>21</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>15</pointsize>
</font>
</property>
<property name="text">
<string>What's your nickname?</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NicknameDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>298</x>
<y>97</y>
</hint>
<hint type="destinationlabel">
<x>298</x>
<y>108</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NicknameDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>210</x>
<y>125</y>
</hint>
<hint type="destinationlabel">
<x>202</x>
<y>84</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>checkAccept()</slot>
<slot>checkAcc()</slot>
</slots>
</ui>