@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
#include "addfriendform.h" |
||||
#include "ui_widget.h" |
||||
#include <QFont> |
||||
|
||||
AddFriendForm::AddFriendForm() |
||||
{ |
||||
main = new QWidget(), head = new QWidget(); |
||||
QFont bold; |
||||
bold.setBold(true); |
||||
headLabel.setText("Add Friends"); |
||||
headLabel.setFont(bold); |
||||
|
||||
toxIdLabel.setText("Tox ID"); |
||||
messageLabel.setText("Message"); |
||||
sendButton.setText("Send friend request"); |
||||
|
||||
main->setLayout(&layout); |
||||
layout.addWidget(&toxIdLabel); |
||||
layout.addWidget(&toxId); |
||||
layout.addWidget(&messageLabel); |
||||
layout.addWidget(&message); |
||||
layout.addWidget(&sendButton); |
||||
|
||||
head->setLayout(&headLayout); |
||||
headLayout.addWidget(&headLabel); |
||||
|
||||
connect(&sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered())); |
||||
} |
||||
|
||||
void AddFriendForm::show(Ui::Widget &ui) |
||||
{ |
||||
ui.mainContent->layout()->addWidget(main); |
||||
ui.mainHead->layout()->addWidget(head); |
||||
main->show(); |
||||
head->show(); |
||||
} |
||||
|
||||
void AddFriendForm::onSendTriggered() |
||||
{ |
||||
QString id = toxId.text(), msg = message.toPlainText(); |
||||
if (id.isEmpty()) |
||||
return; |
||||
|
||||
emit friendRequested(id, msg); |
||||
} |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
#ifndef ADDFRIENDFORM_H |
||||
#define ADDFRIENDFORM_H |
||||
|
||||
#include <QVBoxLayout> |
||||
#include <QLabel> |
||||
#include <QLineEdit> |
||||
#include <QTextEdit> |
||||
#include <QPushButton> |
||||
|
||||
#include "ui_widget.h" |
||||
|
||||
class AddFriendForm : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
AddFriendForm(); |
||||
|
||||
void show(Ui::Widget& ui); |
||||
|
||||
signals: |
||||
void friendRequested(const QString& friendAddress, const QString& message); |
||||
|
||||
private slots: |
||||
void onSendTriggered(); |
||||
|
||||
private: |
||||
QLabel headLabel, toxIdLabel, messageLabel; |
||||
QPushButton sendButton; |
||||
QLineEdit toxId; |
||||
QTextEdit message; |
||||
QVBoxLayout layout, headLayout; |
||||
QWidget *head, *main; |
||||
}; |
||||
|
||||
#endif // ADDFRIENDFORM_H
|
@ -0,0 +1,153 @@
@@ -0,0 +1,153 @@
|
||||
#include "chatform.h" |
||||
#include "friend.h" |
||||
#include "friendwidget.h" |
||||
#include "widget.h" |
||||
#include <QFont> |
||||
#include <QTime> |
||||
#include <QScrollBar> |
||||
|
||||
ChatForm::ChatForm(Friend* chatFriend) |
||||
: f(chatFriend), curRow{0}, lockSliderToBottom{true} |
||||
{ |
||||
main = new QWidget(), head = new QWidget(), chatAreaWidget = new QWidget(); |
||||
name = new QLabel(), avatar = new QLabel(), statusMessage = new QLabel(); |
||||
headLayout = new QHBoxLayout(), mainFootLayout = new QHBoxLayout(); |
||||
headTextLayout = new QVBoxLayout(), mainLayout = new QVBoxLayout(); |
||||
mainChatLayout = new QGridLayout(); |
||||
msgEdit = new ChatTextEdit(); |
||||
sendButton = new QPushButton(); |
||||
chatArea = new QScrollArea(); |
||||
|
||||
QFont bold; |
||||
bold.setBold(true); |
||||
name->setText(chatFriend->widget->name.text()); |
||||
name->setFont(bold); |
||||
statusMessage->setText(chatFriend->widget->statusMessage.text()); |
||||
avatar->setPixmap(*chatFriend->widget->avatar.pixmap()); |
||||
|
||||
chatAreaWidget->setLayout(mainChatLayout); |
||||
chatArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); |
||||
chatArea->setWidgetResizable(true); |
||||
mainChatLayout->setColumnStretch(1,1); |
||||
mainChatLayout->setSpacing(10); |
||||
|
||||
sendButton->setIcon(QIcon("img/button icons/sendmessage_2x.png")); |
||||
sendButton->setFlat(true); |
||||
QPalette pal; |
||||
pal.setColor(QPalette::Button, QColor(107,194,96)); // Tox Green
|
||||
sendButton->setPalette(pal); |
||||
sendButton->setAutoFillBackground(true); |
||||
msgEdit->setFixedHeight(50); |
||||
sendButton->setFixedSize(50, 50); |
||||
|
||||
main->setLayout(mainLayout); |
||||
mainLayout->addWidget(chatArea); |
||||
mainLayout->addLayout(mainFootLayout); |
||||
mainLayout->setMargin(0); |
||||
|
||||
mainFootLayout->addWidget(msgEdit); |
||||
mainFootLayout->addWidget(sendButton); |
||||
|
||||
head->setLayout(headLayout); |
||||
headLayout->addWidget(avatar); |
||||
headLayout->addLayout(headTextLayout); |
||||
headLayout->addStretch(); |
||||
|
||||
headTextLayout->addStretch(); |
||||
headTextLayout->addWidget(name); |
||||
headTextLayout->addWidget(statusMessage); |
||||
headTextLayout->addStretch(); |
||||
|
||||
chatArea->setWidget(chatAreaWidget); |
||||
|
||||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered())); |
||||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered())); |
||||
connect(chatArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged())); |
||||
} |
||||
|
||||
ChatForm::~ChatForm() |
||||
{ |
||||
delete main; |
||||
delete head; |
||||
} |
||||
|
||||
void ChatForm::show(Ui::Widget &ui) |
||||
{ |
||||
ui.mainContent->layout()->addWidget(main); |
||||
ui.mainHead->layout()->addWidget(head); |
||||
main->show(); |
||||
head->show(); |
||||
} |
||||
|
||||
void ChatForm::setName(QString newName) |
||||
{ |
||||
name->setText(newName); |
||||
} |
||||
|
||||
void ChatForm::setStatusMessage(QString newMessage) |
||||
{ |
||||
statusMessage->setText(newMessage); |
||||
} |
||||
|
||||
void ChatForm::onSendTriggered() |
||||
{ |
||||
QString msg = msgEdit->toPlainText(); |
||||
if (msg.isEmpty()) |
||||
return; |
||||
QString name = Widget::getInstance()->getUsername(); |
||||
msgEdit->clear(); |
||||
addMessage(name, msg); |
||||
emit sendMessage(f->friendId, msg); |
||||
} |
||||
|
||||
void ChatForm::addFriendMessage(QString message) |
||||
{ |
||||
QLabel *msgAuthor = new QLabel(name->text()); |
||||
QLabel *msgText = new QLabel(message); |
||||
QLabel *msgDate = new QLabel(QTime::currentTime().toString("hh:mm")); |
||||
|
||||
addMessage(msgAuthor, msgText, msgDate); |
||||
} |
||||
|
||||
void ChatForm::addMessage(QString author, QString message, QString date) |
||||
{ |
||||
addMessage(new QLabel(author), new QLabel(message), new QLabel(date)); |
||||
} |
||||
|
||||
void ChatForm::addMessage(QLabel* author, QLabel* message, QLabel* date) |
||||
{ |
||||
QScrollBar* scroll = chatArea->verticalScrollBar(); |
||||
lockSliderToBottom = scroll && scroll->value() == scroll->maximum(); |
||||
author->setAlignment(Qt::AlignTop | Qt::AlignRight); |
||||
date->setAlignment(Qt::AlignTop); |
||||
if (author->text() == Widget::getInstance()->getUsername()) |
||||
{ |
||||
QPalette pal; |
||||
pal.setColor(QPalette::WindowText, Qt::gray); |
||||
author->setPalette(pal); |
||||
message->setPalette(pal); |
||||
} |
||||
if (previousName.isEmpty() || previousName != author->text()) |
||||
{ |
||||
if (curRow) |
||||
{ |
||||
mainChatLayout->setRowStretch(curRow, 0); |
||||
mainChatLayout->addItem(new QSpacerItem(0,AUTHOR_CHANGE_SPACING),curRow,0,1,3); |
||||
curRow++; |
||||
} |
||||
mainChatLayout->addWidget(author, curRow, 0); |
||||
} |
||||
previousName = author->text(); |
||||
mainChatLayout->addWidget(message, curRow, 1); |
||||
mainChatLayout->addWidget(date, curRow, 3); |
||||
mainChatLayout->setRowStretch(curRow+1, 1); |
||||
mainChatLayout->setRowStretch(curRow, 0); |
||||
curRow++; |
||||
} |
||||
|
||||
void ChatForm::onSliderRangeChanged() |
||||
{ |
||||
QScrollBar* scroll = chatArea->verticalScrollBar(); |
||||
if (lockSliderToBottom) |
||||
scroll->setValue(scroll->maximum()); |
||||
} |
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
#ifndef CHATFORM_H |
||||
#define CHATFORM_H |
||||
|
||||
#include <QLabel> |
||||
#include <QWidget> |
||||
#include <QVBoxLayout> |
||||
#include <QHBoxLayout> |
||||
#include <QGridLayout> |
||||
#include <QTextEdit> |
||||
#include <QScrollArea> |
||||
#include <QTime> |
||||
|
||||
#include "chattextedit.h" |
||||
#include "ui_widget.h" |
||||
|
||||
// Spacing in px inserted when the author of the last message changes
|
||||
#define AUTHOR_CHANGE_SPACING 5 |
||||
|
||||
class Friend; |
||||
|
||||
class ChatForm : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
ChatForm(Friend* chatFriend); |
||||
~ChatForm(); |
||||
void show(Ui::Widget& ui); |
||||
void setName(QString newName); |
||||
void setStatusMessage(QString newMessage); |
||||
void addFriendMessage(QString message); |
||||
void addMessage(QString author, QString message, QString date=QTime::currentTime().toString("hh:mm")); |
||||
void addMessage(QLabel* author, QLabel* message, QLabel* date); |
||||
|
||||
|
||||
signals: |
||||
void sendMessage(int, QString); |
||||
|
||||
private slots: |
||||
void onSendTriggered(); |
||||
void onSliderRangeChanged(); |
||||
|
||||
private: |
||||
Friend* f; |
||||
QHBoxLayout *headLayout, *mainFootLayout; |
||||
QVBoxLayout *headTextLayout, *mainLayout; |
||||
QGridLayout *mainChatLayout; |
||||
QLabel *avatar, *name, *statusMessage; |
||||
ChatTextEdit *msgEdit; |
||||
QPushButton *sendButton; |
||||
QScrollArea *chatArea; |
||||
QWidget *main, *head, *chatAreaWidget; |
||||
QString previousName; |
||||
int curRow; |
||||
bool lockSliderToBottom; |
||||
}; |
||||
|
||||
#endif // CHATFORM_H
|
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
#include "chattextedit.h" |
||||
#include <QKeyEvent> |
||||
|
||||
ChatTextEdit::ChatTextEdit(QWidget *parent) : |
||||
QTextEdit(parent) |
||||
{ |
||||
} |
||||
|
||||
void ChatTextEdit::keyPressEvent(QKeyEvent * event) |
||||
{ |
||||
int key = event->key(); |
||||
if ((key == Qt::Key_Enter || key == Qt::Key_Return) |
||||
&& !(event->modifiers() && Qt::ShiftModifier)) |
||||
{ |
||||
emit enterPressed(); |
||||
return; |
||||
} |
||||
QTextEdit::keyPressEvent(event); |
||||
} |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
#ifndef CHATTEXTEDIT_H |
||||
#define CHATTEXTEDIT_H |
||||
|
||||
#include <QTextEdit> |
||||
|
||||
class ChatTextEdit : public QTextEdit |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit ChatTextEdit(QWidget *parent = 0); |
||||
virtual void keyPressEvent(QKeyEvent * event) override; |
||||
|
||||
signals: |
||||
void enterPressed(); |
||||
|
||||
public slots: |
||||
|
||||
}; |
||||
|
||||
#endif // CHATTEXTEDIT_H
|
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#include "copyableelidelabel.h" |
||||
|
||||
#include <QApplication> |
||||
#include <QMenu> |
||||
#include <QClipboard> |
||||
|
||||
CopyableElideLabel::CopyableElideLabel(QWidget* parent) : |
||||
ElideLabel(parent) |
||||
{ |
||||
setContextMenuPolicy(Qt::CustomContextMenu); |
||||
connect(this, &CopyableElideLabel::customContextMenuRequested, this, &CopyableElideLabel::showContextMenu); |
||||
|
||||
actionCopy = new QAction(tr("Copy"), this); |
||||
connect(actionCopy, &QAction::triggered, [this]() { |
||||
QApplication::clipboard()->setText(text()); |
||||
}); |
||||
} |
||||
|
||||
void CopyableElideLabel::showContextMenu(const QPoint& pos) |
||||
{ |
||||
if (text().length() == 0) { |
||||
return; |
||||
} |
||||
|
||||
QPoint globalPos = mapToGlobal(pos); |
||||
|
||||
QMenu contextMenu; |
||||
contextMenu.addAction(actionCopy); |
||||
|
||||
contextMenu.exec(globalPos); |
||||
} |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#ifndef COPYABLEELIDELABEL_HPP |
||||
#define COPYABLEELIDELABEL_HPP |
||||
|
||||
#include "elidelabel.h" |
||||
|
||||
class CopyableElideLabel : public ElideLabel |
||||
{ |
||||
public: |
||||
explicit CopyableElideLabel(QWidget* parent = 0); |
||||
|
||||
private: |
||||
QAction* actionCopy; |
||||
|
||||
private slots: |
||||
void showContextMenu(const QPoint& pos); |
||||
|
||||
}; |
||||
|
||||
#endif // COPYABLEELIDELABEL_HPP
|
@ -0,0 +1,568 @@
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#include "core.h" |
||||
|
||||
#include <cstdint> |
||||
|
||||
#include <QDebug> |
||||
#include <QDir> |
||||
#include <QFile> |
||||
#include <QSaveFile> |
||||
#include <QStandardPaths> |
||||
#include <QtEndian> |
||||
#include <QThread> |
||||
|
||||
#include "settings.h" |
||||
|
||||
const QString Core::CONFIG_FILE_NAME = "tox_save"; |
||||
|
||||
Core::Core() : |
||||
tox(nullptr) |
||||
{ |
||||
toxTimer = new QTimer(this); |
||||
toxTimer->setSingleShot(true); |
||||
saveTimer = new QTimer(this); |
||||
saveTimer->start(TOX_SAVE_INTERVAL); |
||||
connect(toxTimer, &QTimer::timeout, this, &Core::process); |
||||
connect(saveTimer, &QTimer::timeout, this, &Core::saveConfiguration); |
||||
connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::bootstrapDht); |
||||
} |
||||
|
||||
Core::~Core() |
||||
{ |
||||
if (tox) { |
||||
saveConfiguration(); |
||||
tox_kill(tox); |
||||
} |
||||
} |
||||
|
||||
void Core::onFriendRequest(Tox*/* tox*/, const uint8_t* cUserId, const uint8_t* cMessage, uint16_t cMessageSize, void* core) |
||||
{ |
||||
emit static_cast<Core*>(core)->friendRequestReceived(CUserId::toString(cUserId), CString::toString(cMessage, cMessageSize)); |
||||
} |
||||
|
||||
void Core::onFriendMessage(Tox*/* tox*/, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core) |
||||
{ |
||||
emit static_cast<Core*>(core)->friendMessageReceived(friendId, CString::toString(cMessage, cMessageSize)); |
||||
} |
||||
|
||||
void Core::onFriendNameChange(Tox*/* tox*/, int friendId, uint8_t* cName, uint16_t cNameSize, void* core) |
||||
{ |
||||
emit static_cast<Core*>(core)->friendUsernameChanged(friendId, CString::toString(cName, cNameSize)); |
||||
} |
||||
|
||||
void Core::onFriendTypingChange(Tox*/* tox*/, int friendId, uint8_t isTyping, void *core) |
||||
{ |
||||
emit static_cast<Core*>(core)->friendTypingChanged(friendId, isTyping ? true : false); |
||||
} |
||||
|
||||
void Core::onStatusMessageChanged(Tox*/* tox*/, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core) |
||||
{ |
||||
emit static_cast<Core*>(core)->friendStatusMessageChanged(friendId, CString::toString(cMessage, cMessageSize)); |
||||
} |
||||
|
||||
void Core::onUserStatusChanged(Tox*/* tox*/, int friendId, uint8_t userstatus, void* core) |
||||
{ |
||||
Status status; |
||||
switch (userstatus) { |
||||
case TOX_USERSTATUS_NONE: |
||||
status = Status::Online; |
||||
break; |
||||
case TOX_USERSTATUS_AWAY: |
||||
status = Status::Away; |
||||
break; |
||||
case TOX_USERSTATUS_BUSY: |
||||
status = Status::Busy; |
||||
break; |
||||
default: |
||||
status = Status::Online; |
||||
break; |
||||
} |
||||
emit static_cast<Core*>(core)->friendStatusChanged(friendId, status); |
||||
} |
||||
|
||||
void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, void* core) |
||||
{ |
||||
Status friendStatus = status ? Status::Online : Status::Offline; |
||||
emit static_cast<Core*>(core)->friendStatusChanged(friendId, friendStatus); |
||||
if (friendStatus == Status::Offline) { |
||||
static_cast<Core*>(core)->checkLastOnline(friendId); |
||||
} |
||||
} |
||||
|
||||
void Core::onAction(Tox*/* tox*/, int friendId, uint8_t *cMessage, uint16_t cMessageSize, void *core) |
||||
{ |
||||
emit static_cast<Core*>(core)->actionReceived(friendId, CString::toString(cMessage, cMessageSize)); |
||||
} |
||||
|
||||
void Core::onGroupInvite(Tox*, int friendnumber, uint8_t *group_public_key, void *core) |
||||
{ |
||||
qDebug() << QString("Core: Group invite by %1").arg(friendnumber); |
||||
emit static_cast<Core*>(core)->groupInviteReceived(friendnumber, group_public_key); |
||||
} |
||||
|
||||
void Core::onGroupMessage(Tox*, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *core) |
||||
{ |
||||
emit static_cast<Core*>(core)->groupMessageReceived(groupnumber, friendgroupnumber, CString::toString(message, length)); |
||||
} |
||||
|
||||
void Core::onGroupNamelistChange(Tox*, int groupnumber, int peernumber, uint8_t change, void *core) |
||||
{ |
||||
qDebug() << QString("Core: Group namelist change %1:%2 %3").arg(groupnumber).arg(peernumber).arg(change); |
||||
emit static_cast<Core*>(core)->groupNamelistChanged(groupnumber, peernumber, change); |
||||
} |
||||
|
||||
void Core::acceptFriendRequest(const QString& userId) |
||||
{ |
||||
int friendId = tox_add_friend_norequest(tox, CUserId(userId).data()); |
||||
if (friendId == -1) { |
||||
emit failedToAddFriend(userId); |
||||
} else { |
||||
emit friendAdded(friendId, userId); |
||||
} |
||||
} |
||||
|
||||
void Core::requestFriendship(const QString& friendAddress, const QString& message) |
||||
{ |
||||
CString cMessage(message); |
||||
|
||||
int friendId = tox_add_friend(tox, CFriendAddress(friendAddress).data(), cMessage.data(), cMessage.size()); |
||||
const QString userId = friendAddress.mid(0, TOX_CLIENT_ID_SIZE * 2); |
||||
// TODO: better error handling
|
||||
if (friendId < 0) { |
||||
emit failedToAddFriend(userId); |
||||
} else { |
||||
emit friendAdded(friendId, userId); |
||||
} |
||||
} |
||||
|
||||
void Core::sendMessage(int friendId, const QString& message) |
||||
{ |
||||
CString cMessage(message); |
||||
|
||||
int messageId = tox_send_message(tox, friendId, cMessage.data(), cMessage.size()); |
||||
emit messageSentResult(friendId, message, messageId); |
||||
} |
||||
|
||||
void Core::sendAction(int friendId, const QString &action) |
||||
{ |
||||
CString cMessage(action); |
||||
int ret = tox_send_action(tox, friendId, cMessage.data(), cMessage.size()); |
||||
emit actionSentResult(friendId, action, ret); |
||||
} |
||||
|
||||
void Core::sendTyping(int friendId, bool typing) |
||||
{ |
||||
int ret = tox_set_user_is_typing(tox, friendId, typing); |
||||
if (ret == -1) |
||||
emit failedToSetTyping(typing); |
||||
} |
||||
|
||||
void Core::sendGroupMessage(int groupId, const QString& message) |
||||
{ |
||||
CString cMessage(message); |
||||
|
||||
tox_group_message_send(tox, groupId, cMessage.data(), cMessage.size()); |
||||
} |
||||
|
||||
void Core::removeFriend(int friendId) |
||||
{ |
||||
if (tox_del_friend(tox, friendId) == -1) { |
||||
emit failedToRemoveFriend(friendId); |
||||
} else { |
||||
emit friendRemoved(friendId); |
||||
} |
||||
} |
||||
|
||||
void Core::removeGroup(int groupId) |
||||
{ |
||||
tox_del_groupchat(tox, groupId); |
||||
} |
||||
|
||||
void Core::setUsername(const QString& username) |
||||
{ |
||||
CString cUsername(username); |
||||
|
||||
if (tox_set_name(tox, cUsername.data(), cUsername.size()) == -1) { |
||||
emit failedToSetUsername(username); |
||||
} else { |
||||
emit usernameSet(username); |
||||
} |
||||
} |
||||
|
||||
void Core::setStatusMessage(const QString& message) |
||||
{ |
||||
CString cMessage(message); |
||||
|
||||
if (tox_set_status_message(tox, cMessage.data(), cMessage.size()) == -1) { |
||||
emit failedToSetStatusMessage(message); |
||||
} else { |
||||
emit statusMessageSet(message); |
||||
} |
||||
} |
||||
|
||||
void Core::setStatus(Status status) |
||||
{ |
||||
TOX_USERSTATUS userstatus; |
||||
switch (status) { |
||||
case Status::Online: |
||||
userstatus = TOX_USERSTATUS_NONE; |
||||
break; |
||||
case Status::Away: |
||||
userstatus = TOX_USERSTATUS_AWAY; |
||||
break; |
||||
case Status::Busy: |
||||
userstatus = TOX_USERSTATUS_BUSY; |
||||
break; |
||||
default: |
||||
userstatus = TOX_USERSTATUS_INVALID; |
||||
break; |
||||
} |
||||
|
||||
if (tox_set_user_status(tox, userstatus) == 0) { |
||||
emit statusSet(status); |
||||
} else { |
||||
emit failedToSetStatus(status); |
||||
} |
||||
} |
||||
|
||||
void Core::bootstrapDht() |
||||
{ |
||||
const Settings& s = Settings::getInstance(); |
||||
QList<Settings::DhtServer> dhtServerList = s.getDhtServerList(); |
||||
|
||||
for (const Settings::DhtServer& dhtServer : dhtServerList) { |
||||
tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), 0, qToBigEndian(dhtServer.port), CUserId(dhtServer.userId).data()); |
||||
} |
||||
} |
||||
|
||||
void Core::process() |
||||
{ |
||||
tox_do(tox); |
||||
#ifdef DEBUG |
||||
//we want to see the debug messages immediately
|
||||
fflush(stdout); |
||||
#endif |
||||
checkConnection(); |
||||
if (!tox_isconnected(tox)) |
||||
bootstrapDht(); |
||||
toxTimer->start(tox_do_interval(tox)); |
||||
} |
||||
|
||||
void Core::checkConnection() |
||||
{ |
||||
static bool isConnected = false; |
||||
|
||||
if (tox_isconnected(tox) && !isConnected) { |
||||
emit connected(); |
||||
isConnected = true; |
||||
} else if (!tox_isconnected(tox) && isConnected) { |
||||
emit disconnected(); |
||||
isConnected = false; |
||||
} |
||||
} |
||||
|
||||
void Core::loadConfiguration() |
||||
{ |
||||
QString path = Settings::getSettingsDirPath() + '/' + CONFIG_FILE_NAME; |
||||
|
||||
QFile configurationFile(path); |
||||
|
||||
if (!configurationFile.exists()) { |
||||
qWarning() << "The Tox configuration file was not found"; |
||||
return; |
||||
} |
||||
|
||||
if (!configurationFile.open(QIODevice::ReadOnly)) { |
||||
qCritical() << "File " << path << " cannot be opened"; |
||||
return; |
||||
} |
||||
|
||||
qint64 fileSize = configurationFile.size(); |
||||
if (fileSize > 0) { |
||||
QByteArray data = configurationFile.readAll(); |
||||
tox_load(tox, reinterpret_cast<uint8_t *>(data.data()), data.size()); |
||||
} |
||||
|
||||
configurationFile.close(); |
||||
|
||||
loadFriends(); |
||||
} |
||||
|
||||
void Core::saveConfiguration() |
||||
{ |
||||
QString path = Settings::getSettingsDirPath(); |
||||
|
||||
QDir directory(path); |
||||
|
||||
if (!directory.exists() && !directory.mkpath(directory.absolutePath())) { |
||||
qCritical() << "Error while creating directory " << path; |
||||
return; |
||||
} |
||||
|
||||
path += '/' + CONFIG_FILE_NAME; |
||||
QSaveFile configurationFile(path); |
||||
if (!configurationFile.open(QIODevice::WriteOnly)) { |
||||
qCritical() << "File " << path << " cannot be opened"; |
||||
return; |
||||
} |
||||
|
||||
qDebug() << "Core: writing tox_save"; |
||||
uint32_t fileSize = tox_size(tox); |
||||
if (fileSize > 0 && fileSize <= INT32_MAX) { |
||||
uint8_t *data = new uint8_t[fileSize]; |
||||
tox_save(tox, data); |
||||
configurationFile.write(reinterpret_cast<char *>(data), fileSize); |
||||
configurationFile.commit(); |
||||
delete[] data; |
||||
} |
||||
} |
||||
|
||||
void Core::loadFriends() |
||||
{ |
||||
const uint32_t friendCount = tox_count_friendlist(tox); |
||||
if (friendCount > 0) { |
||||
// assuming there are not that many friends to fill up the whole stack
|
||||
int32_t *ids = new int32_t[friendCount]; |
||||
tox_get_friendlist(tox, ids, friendCount); |
||||
uint8_t clientId[TOX_CLIENT_ID_SIZE]; |
||||
for (int32_t i = 0; i < static_cast<int32_t>(friendCount); ++i) { |
||||
if (tox_get_client_id(tox, ids[i], clientId) == 0) { |
||||
emit friendAdded(ids[i], CUserId::toString(clientId)); |
||||
|
||||
const int nameSize = tox_get_name_size(tox, ids[i]); |
||||
if (nameSize > 0) { |
||||
uint8_t *name = new uint8_t[nameSize]; |
||||
if (tox_get_name(tox, ids[i], name) == nameSize) { |
||||
emit friendUsernameLoaded(ids[i], CString::toString(name, nameSize)); |
||||
} |
||||
delete[] name; |
||||
} |
||||
|
||||
const int statusMessageSize = tox_get_status_message_size(tox, ids[i]); |
||||
if (statusMessageSize > 0) { |
||||
uint8_t *statusMessage = new uint8_t[statusMessageSize]; |
||||
if (tox_get_status_message(tox, ids[i], statusMessage, statusMessageSize) == statusMessageSize) { |
||||
emit friendStatusMessageLoaded(ids[i], CString::toString(statusMessage, statusMessageSize)); |
||||
} |
||||
delete[] statusMessage; |
||||
} |
||||
|
||||
checkLastOnline(ids[i]); |
||||
} |
||||
|
||||
} |
||||
delete[] ids; |
||||
} |
||||
} |
||||
|
||||
void Core::checkLastOnline(int friendId) { |
||||
const uint64_t lastOnline = tox_get_last_online(tox, friendId); |
||||
if (lastOnline > 0) { |
||||
emit friendLastSeenChanged(friendId, QDateTime::fromTime_t(lastOnline)); |
||||
} |
||||
} |
||||
|
||||
void Core::start() |
||||
{ |
||||
tox = tox_new(0); |
||||
|
||||
if (tox == nullptr) { |
||||
qCritical() << "Core failed to start"; |
||||
emit failedToStart(); |
||||
return; |
||||
} |
||||
|
||||
loadConfiguration(); |
||||
|
||||
tox_callback_friend_request(tox, onFriendRequest, this); |
||||
tox_callback_friend_message(tox, onFriendMessage, this); |
||||
tox_callback_friend_action(tox, onAction, this); |
||||
tox_callback_name_change(tox, onFriendNameChange, this); |
||||
tox_callback_typing_change(tox, onFriendTypingChange, this); |
||||
tox_callback_status_message(tox, onStatusMessageChanged, this); |
||||
tox_callback_user_status(tox, onUserStatusChanged, this); |
||||
tox_callback_connection_status(tox, onConnectionStatusChanged, this); |
||||
tox_callback_group_invite(tox, onGroupInvite, this); |
||||
tox_callback_group_message(tox, onGroupMessage, this); |
||||
tox_callback_group_namelist_change(tox, onGroupNamelistChange, this); |
||||
|
||||
uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE]; |
||||
tox_get_address(tox, friendAddress); |
||||
|
||||
emit friendAddressGenerated(CFriendAddress::toString(friendAddress)); |
||||
|
||||
CString cUsername(Settings::getInstance().getUsername()); |
||||
tox_set_name(tox, cUsername.data(), cUsername.size()); |
||||
|
||||
CString cStatusMessage(Settings::getInstance().getStatusMessage()); |
||||
tox_set_status_message(tox, cStatusMessage.data(), cStatusMessage.size()); |
||||
|
||||
bootstrapDht(); |
||||
|
||||
toxTimer->start(tox_do_interval(tox)); |
||||
} |
||||
|
||||
int Core::getGroupNumberPeers(int groupId) const |
||||
{ |
||||
return tox_group_number_peers(tox, groupId); |
||||
} |
||||
|
||||
QString Core::getGroupPeerName(int groupId, int peerId) const |
||||
{ |
||||
QString name; |
||||
uint8_t nameArray[TOX_MAX_NAME_LENGTH]; |
||||
int length = tox_group_peername(tox, groupId, peerId, nameArray); |
||||
if (length == -1) |
||||
{ |
||||
qWarning() << "Core::getGroupPeerName: Unknown error"; |
||||
return name; |
||||
} |
||||
name = CString::toString(nameArray, length); |
||||
return name; |
||||
} |
||||
|
||||
QList<QString> Core::getGroupPeerNames(int groupId) const |
||||
{ |
||||
QList<QString> names; |
||||
int nPeers = getGroupNumberPeers(groupId); |
||||
if (nPeers == -1) |
||||
{ |
||||
qWarning() << "Core::getGroupPeerNames: Unable to get number of peers"; |
||||
return names; |
||||
} |
||||
uint8_t namesArray[nPeers][TOX_MAX_NAME_LENGTH]; |
||||
uint16_t* lengths = new uint16_t[nPeers]; |
||||
int result = tox_group_get_names(tox, groupId, namesArray, lengths, nPeers); |
||||
if (result != nPeers) |
||||
{ |
||||
qWarning() << "Core::getGroupPeerNames: Unexpected result"; |
||||
return names; |
||||
} |
||||
for (int i=0; i<nPeers; i++) |
||||
names.push_back(CString::toString(namesArray[i], lengths[i])); |
||||
return names; |
||||
} |
||||
|
||||
int Core::joinGroupchat(int32_t friendnumber, uint8_t* friend_group_public_key) const |
||||
{ |
||||
return tox_join_groupchat(tox, friendnumber, friend_group_public_key); |
||||
} |
||||
|
||||
// CData
|
||||
|
||||
Core::CData::CData(const QString &data, uint16_t byteSize) |
||||
{ |
||||
cData = new uint8_t[byteSize]; |
||||
cDataSize = fromString(data, cData); |
||||
} |
||||
|
||||
Core::CData::~CData() |
||||
{ |
||||
delete[] cData; |
||||
} |
||||
|
||||
uint8_t* Core::CData::data() |
||||
{ |
||||
return cData; |
||||
} |
||||
|
||||
uint16_t Core::CData::size() |
||||
{ |
||||
return cDataSize; |
||||
} |
||||
|
||||
QString Core::CData::toString(const uint8_t *cData, const uint16_t cDataSize) |
||||
{ |
||||
return QString(QByteArray(reinterpret_cast<const char*>(cData), cDataSize).toHex()).toUpper(); |
||||
} |
||||
|
||||
uint16_t Core::CData::fromString(const QString& data, uint8_t* cData) |
||||
{ |
||||
QByteArray arr = QByteArray::fromHex(data.toLower().toLatin1()); |
||||
memcpy(cData, reinterpret_cast<uint8_t*>(arr.data()), arr.size()); |
||||
return arr.size(); |
||||
} |
||||
|
||||
|
||||
// CUserId
|
||||
|
||||
Core::CUserId::CUserId(const QString &userId) : |
||||
CData(userId, SIZE) |
||||
{ |
||||
// intentionally left empty
|
||||
} |
||||
|
||||
QString Core::CUserId::toString(const uint8_t* cUserId) |
||||
{ |
||||
return CData::toString(cUserId, SIZE); |
||||
} |
||||
|
||||
|
||||
// CFriendAddress
|
||||
|
||||
Core::CFriendAddress::CFriendAddress(const QString &friendAddress) : |
||||
CData(friendAddress, SIZE) |
||||
{ |
||||
// intentionally left empty
|
||||
} |
||||
|
||||
QString Core::CFriendAddress::toString(const uint8_t *cFriendAddress) |
||||
{ |
||||
return CData::toString(cFriendAddress, SIZE); |
||||
} |
||||
|
||||
|
||||
// CString
|
||||
|
||||
Core::CString::CString(const QString& string) |
||||
{ |
||||
cString = new uint8_t[string.length() * MAX_SIZE_OF_UTF8_ENCODED_CHARACTER](); |
||||
cStringSize = fromString(string, cString); |
||||
} |
||||
|
||||
Core::CString::~CString() |
||||
{ |
||||
delete[] cString; |
||||
} |
||||
|
||||
uint8_t* Core::CString::data() |
||||
{ |
||||
return cString; |
||||
} |
||||
|
||||
uint16_t Core::CString::size() |
||||
{ |
||||
return cStringSize; |
||||
} |
||||
|
||||
QString Core::CString::toString(const uint8_t* cString, uint16_t cStringSize) |
||||
{ |
||||
return QString::fromUtf8(reinterpret_cast<const char*>(cString), cStringSize); |
||||
} |
||||
|
||||
uint16_t Core::CString::fromString(const QString& string, uint8_t* cString) |
||||
{ |
||||
QByteArray byteArray = QByteArray(string.toUtf8()); |
||||
memcpy(cString, reinterpret_cast<uint8_t*>(byteArray.data()), byteArray.size()); |
||||
return byteArray.size(); |
||||
} |
||||
|
||||
void Core::quitGroupChat(int groupId) const |
||||
{ |
||||
tox_del_groupchat(tox, groupId); |
||||
} |
@ -0,0 +1,216 @@
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#ifndef CORE_HPP |
||||
#define CORE_HPP |
||||
|
||||
#include "status.h" |
||||
|
||||
#include <tox/tox.h> |
||||
|
||||
#include <QDateTime> |
||||
#include <QObject> |
||||
#include <QTimer> |
||||
#include <QString> |
||||
#include <QList> |
||||
|
||||
#define GROUPCHAT_MAX_SIZE 32 |
||||
#define TOX_SAVE_INTERVAL 10*1000 |
||||
|
||||
struct DhtServer |
||||
{ |
||||
QString name; |
||||
QString userId; |
||||
QString address; |
||||
int port; |
||||
}; |
||||
|
||||
class Core : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit Core(); |
||||
~Core(); |
||||
|
||||
private: |
||||
static void onFriendRequest(Tox* tox, const uint8_t* cUserId, const uint8_t* cMessage, uint16_t cMessageSize, void* core); |
||||
static void onFriendMessage(Tox* tox, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core); |
||||
static void onFriendNameChange(Tox* tox, int friendId, uint8_t* cName, uint16_t cNameSize, void* core); |
||||
static void onFriendTypingChange(Tox* tox, int friendId, uint8_t isTyping, void* core); |
||||
static void onStatusMessageChanged(Tox* tox, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core); |
||||
static void onUserStatusChanged(Tox* tox, int friendId, uint8_t userstatus, void* core); |
||||
static void onConnectionStatusChanged(Tox* tox, int friendId, uint8_t status, void* core); |
||||
static void onAction(Tox* tox, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core); |
||||
static void onGroupInvite(Tox *tox, int friendnumber, uint8_t *group_public_key, void *userdata); |
||||
static void onGroupMessage(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata); |
||||
static void onGroupNamelistChange(Tox *tox, int groupnumber, int peernumber, uint8_t change, void *userdata); |
||||
|
||||
void checkConnection(); |
||||
|
||||
void loadConfiguration(); |
||||
void saveConfiguration(); |
||||
void loadFriends(); |
||||
|
||||
void checkLastOnline(int friendId); |
||||
|
||||
Tox* tox; |
||||
QTimer *toxTimer, *saveTimer; |
||||
QList<DhtServer> dhtServerList; |
||||
int dhtServerId; |
||||
|
||||
static const QString CONFIG_FILE_NAME; |
||||
|
||||
class CData |
||||
{ |
||||
public: |
||||
uint8_t* data(); |
||||
uint16_t size(); |
||||
|
||||
protected: |
||||
explicit CData(const QString& data, uint16_t byteSize); |
||||
virtual ~CData(); |
||||
|
||||
static QString toString(const uint8_t* cData, const uint16_t cDataSize); |
||||
|
||||
private: |
||||
uint8_t* cData; |
||||
uint16_t cDataSize; |
||||
|
||||
static uint16_t fromString(const QString& userId, uint8_t* cData); |
||||
}; |
||||
|
||||
class CUserId : public CData |
||||
{ |
||||
public: |
||||
explicit CUserId(const QString& userId); |
||||
|
||||
static QString toString(const uint8_t *cUserId); |
||||
|
||||
private: |
||||
static const uint16_t SIZE = TOX_CLIENT_ID_SIZE; |
||||
|
||||
}; |
||||
|
||||
class CFriendAddress : public CData |
||||
{ |
||||
public: |
||||
explicit CFriendAddress(const QString& friendAddress); |
||||
|
||||
static QString toString(const uint8_t* cFriendAddress); |
||||
|
||||
private: |
||||
static const uint16_t SIZE = TOX_FRIEND_ADDRESS_SIZE; |
||||
|
||||
}; |
||||
|
||||
class CString |
||||
{ |
||||
public: |
||||
explicit CString(const QString& string); |
||||
~CString(); |
||||
|
||||
uint8_t* data(); |
||||
uint16_t size(); |
||||
|
||||
static QString toString(const uint8_t* cMessage, const uint16_t cMessageSize); |
||||
|
||||
private: |
||||
const static int MAX_SIZE_OF_UTF8_ENCODED_CHARACTER = 4; |
||||
|
||||
uint8_t* cString; |
||||
uint16_t cStringSize; |
||||
|
||||
static uint16_t fromString(const QString& message, uint8_t* cMessage); |
||||
}; |
||||
|
||||
public: |
||||
int getGroupNumberPeers(int groupId) const; |
||||
QString getGroupPeerName(int groupId, int peerId) const; |
||||
QList<QString> getGroupPeerNames(int groupId) const; |
||||
int joinGroupchat(int32_t friendnumber, uint8_t* friend_group_public_key) const; |
||||
void quitGroupChat(int groupId) const; |
||||
|
||||
public slots: |
||||
void start(); |
||||
|
||||
void acceptFriendRequest(const QString& userId); |
||||
void requestFriendship(const QString& friendAddress, const QString& message); |
||||
|
||||
void removeFriend(int friendId); |
||||
void removeGroup(int groupId); |
||||
|
||||
void sendMessage(int friendId, const QString& message); |
||||
void sendAction(int friendId, const QString& action); |
||||
void sendTyping(int friendId, bool typing); |
||||
void sendGroupMessage(int groupId, const QString& message); |
||||
|
||||
void setUsername(const QString& username); |
||||
void setStatusMessage(const QString& message); |
||||
void setStatus(Status status); |
||||
|
||||
void process(); |
||||
|
||||
void bootstrapDht(); |
||||
|
||||
signals: |
||||
void connected(); |
||||
void disconnected(); |
||||
|
||||
void friendRequestReceived(const QString& userId, const QString& message); |
||||
void friendMessageReceived(int friendId, const QString& message); |
||||
|
||||
void friendAdded(int friendId, const QString& userId); |
||||
|
||||
void friendStatusChanged(int friendId, Status status); |
||||
void friendStatusMessageChanged(int friendId, const QString& message); |
||||
void friendUsernameChanged(int friendId, const QString& username); |
||||
void friendTypingChanged(int friendId, bool isTyping); |
||||
|
||||
void friendStatusMessageLoaded(int friendId, const QString& message); |
||||
void friendUsernameLoaded(int friendId, const QString& username); |
||||
|
||||
void friendAddressGenerated(const QString& friendAddress); |
||||
|
||||
void friendRemoved(int friendId); |
||||
|
||||
void friendLastSeenChanged(int friendId, const QDateTime& dateTime); |
||||
|
||||
void groupInviteReceived(int friendnumber, uint8_t *group_public_key); |
||||
void groupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message); |
||||
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change); |
||||
|
||||
void usernameSet(const QString& username); |
||||
void statusMessageSet(const QString& message); |
||||
void statusSet(Status status); |
||||
|
||||
void messageSentResult(int friendId, const QString& message, int messageId); |
||||
void actionSentResult(int friendId, const QString& action, int success); |
||||
|
||||
void failedToAddFriend(const QString& userId); |
||||
void failedToRemoveFriend(int friendId); |
||||
void failedToSetUsername(const QString& username); |
||||
void failedToSetStatusMessage(const QString& message); |
||||
void failedToSetStatus(Status status); |
||||
void failedToSetTyping(bool typing); |
||||
|
||||
void actionReceived(int friendId, const QString& acionMessage); |
||||
|
||||
void failedToStart(); |
||||
|
||||
}; |
||||
|
||||
#endif // CORE_HPP
|
||||
|
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#include "editablelabelwidget.h" |
||||
|
||||
#include <QApplication> |
||||
#include <QEvent> |
||||
#include <QFontMetrics> |
||||
#include <QMouseEvent> |
||||
#include <QVBoxLayout> |
||||
|
||||
ClickableCopyableElideLabel::ClickableCopyableElideLabel(QWidget* parent) : |
||||
CopyableElideLabel(parent) |
||||
{ |
||||
} |
||||
|
||||
bool ClickableCopyableElideLabel::event(QEvent* event) |
||||
{ |
||||
if (event->type() == QEvent::MouseButtonRelease) { |
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); |
||||
if (mouseEvent->button() == Qt::LeftButton) { |
||||
emit clicked(); |
||||
} |
||||
} else if (event->type() == QEvent::Enter) { |
||||
QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); |
||||
} else if (event->type() == QEvent::Leave) { |
||||
QApplication::restoreOverrideCursor(); |
||||
} |
||||
|
||||
return CopyableElideLabel::event(event); |
||||
} |
||||
|
||||
EditableLabelWidget::EditableLabelWidget(QWidget* parent) : |
||||
QStackedWidget(parent), isSubmitting(false) |
||||
{ |
||||
label = new ClickableCopyableElideLabel(this); |
||||
|
||||
connect(label, &ClickableCopyableElideLabel::clicked, this, &EditableLabelWidget::onLabelClicked); |
||||
|
||||
lineEdit = new EscLineEdit(this); |
||||
lineEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); |
||||
lineEdit->setMinimumHeight(label->fontMetrics().lineSpacing() + LINE_SPACING_OFFSET); |
||||
|
||||
connect(lineEdit, &EscLineEdit::editingFinished, this, &EditableLabelWidget::onLabelChangeSubmited); |
||||
connect(lineEdit, &EscLineEdit::escPressed, this, &EditableLabelWidget::onLabelChangeCancelled); |
||||
|
||||
addWidget(label); |
||||
addWidget(lineEdit); |
||||
|
||||
setCurrentWidget(label); |
||||
} |
||||
|
||||
void EditableLabelWidget::setText(const QString& text) |
||||
{ |
||||
label->setText(text); |
||||
lineEdit->setText(text); |
||||
} |
||||
|
||||
QString EditableLabelWidget::text() |
||||
{ |
||||
return label->text(); |
||||
} |
||||
|
||||
void EditableLabelWidget::onLabelChangeSubmited() |
||||
{ |
||||
if (isSubmitting) { |
||||
return; |
||||
} |
||||
isSubmitting = true; |
||||
|
||||
QString oldText = label->text(); |
||||
QString newText = lineEdit->text(); |
||||
// `lineEdit->clearFocus()` triggers `onLabelChangeSubmited()`, we use `isSubmitting` as a workaround
|
||||
lineEdit->clearFocus(); |
||||
setCurrentWidget(label); |
||||
|
||||
if (oldText != newText) { |
||||
label->setText(newText); |
||||
emit textChanged(newText, oldText); |
||||
} |
||||
|
||||
isSubmitting = false; |
||||
} |
||||
|
||||
void EditableLabelWidget::onLabelChangeCancelled() |
||||
{ |
||||
// order of calls matters, since clearFocus() triggers EditableLabelWidget::onLabelChangeSubmited()
|
||||
lineEdit->setText(label->text()); |
||||
lineEdit->clearFocus(); |
||||
setCurrentWidget(label); |
||||
} |
||||
|
||||
void EditableLabelWidget::onLabelClicked() |
||||
{ |
||||
setCurrentWidget(lineEdit); |
||||
lineEdit->setFocus(); |
||||
} |
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#ifndef EDITABLELABELWIDGET_HPP |
||||
#define EDITABLELABELWIDGET_HPP |
||||
|
||||
#include "copyableelidelabel.h" |
||||
#include "esclineedit.h" |
||||
|
||||
#include <QLineEdit> |
||||
#include <QStackedWidget> |
||||
|
||||
class ClickableCopyableElideLabel : public CopyableElideLabel |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit ClickableCopyableElideLabel(QWidget* parent = 0); |
||||
|
||||
protected: |
||||
bool event(QEvent* event) Q_DECL_OVERRIDE; |
||||
|
||||
signals: |
||||
void clicked(); |
||||
|
||||
}; |
||||
|
||||
class EditableLabelWidget : public QStackedWidget |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit EditableLabelWidget(QWidget* parent = 0); |
||||
|
||||
ClickableCopyableElideLabel* label; |
||||
EscLineEdit* lineEdit; |
||||
|
||||
void setText(const QString& text); |
||||
QString text(); |
||||
|
||||
private: |
||||
static const int LINE_SPACING_OFFSET = 2; |
||||
bool isSubmitting; |
||||
|
||||
private slots: |
||||
void onLabelChangeSubmited(); |
||||
void onLabelChangeCancelled(); |
||||
void onLabelClicked(); |
||||
|
||||
signals: |
||||
void textChanged(QString newText, QString oldText); |
||||
|
||||
}; |
||||
|
||||
#endif // EDITABLELABELWIDGET_HPP
|
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#include "elidelabel.h" |
||||
|
||||
#include <QPainter> |
||||
#include <QEvent> |
||||
|
||||
ElideLabel::ElideLabel(QWidget *parent) : |
||||
QLabel(parent), _textElide(false), _textElideMode(Qt::ElideNone), _showToolTipOnElide(false) |
||||
{ |
||||
} |
||||
|
||||
void ElideLabel::paintEvent(QPaintEvent *event) |
||||
{ |
||||
QFrame::paintEvent(event); |
||||
QPainter p(this); |
||||
QFontMetrics metrics(font()); |
||||
if ((metrics.width(text()) > contentsRect().width()) && textElide()) { |
||||
QString elidedText = fontMetrics().elidedText(text(), textElideMode(), rect().width()); |
||||
p.drawText(rect(), alignment(), elidedText); |
||||
} else { |
||||
QLabel::paintEvent(event); |
||||
} |
||||
} |
||||
|
||||
bool ElideLabel::event(QEvent *event) |
||||
{ |
||||
if (event->type() == QEvent::ToolTip) { |
||||
QFontMetrics metrics(font()); |
||||
if ((metrics.width(text()) > contentsRect().width()) && textElide() && showToolTipOnElide()) { |
||||
setToolTip(text()); |
||||
} else { |
||||
setToolTip(""); |
||||
} |
||||
} |
||||
|
||||
return QLabel::event(event); |
||||
} |
||||
|
||||
void ElideLabel::setTextElide(bool set) |
||||
{ |
||||
_textElide = set; |
||||
} |
||||
|
||||
bool ElideLabel::textElide() const |
||||
{ |
||||
return _textElide; |
||||
} |
||||
|
||||
void ElideLabel::setTextElideMode(Qt::TextElideMode mode) |
||||
{ |
||||
_textElideMode = mode; |
||||
} |
||||
|
||||
Qt::TextElideMode ElideLabel::textElideMode() const |
||||
{ |
||||
return _textElideMode; |
||||
} |
||||
|
||||
void ElideLabel::setShowToolTipOnElide(bool show) |
||||
{ |
||||
_showToolTipOnElide = show; |
||||
} |
||||
|
||||
bool ElideLabel::showToolTipOnElide() |
||||
{ |
||||
return _showToolTipOnElide; |
||||
} |
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#ifndef ELIDELABEL_HPP |
||||
#define ELIDELABEL_HPP |
||||
|
||||
#include <QLabel> |
||||
|
||||
class ElideLabel : public QLabel |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit ElideLabel(QWidget *parent = 0); |
||||
|
||||
void setTextElide(bool set); |
||||
bool textElide() const; |
||||
|
||||
void setTextElideMode(Qt::TextElideMode mode); |
||||
Qt::TextElideMode textElideMode() const; |
||||
|
||||
void setShowToolTipOnElide(bool show); |
||||
bool showToolTipOnElide(); |
||||
|
||||
protected: |
||||
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; |
||||
bool event(QEvent *e) Q_DECL_OVERRIDE; |
||||
|
||||
private: |
||||
bool _textElide; |
||||
Qt::TextElideMode _textElideMode; |
||||
|
||||
bool _showToolTipOnElide; |
||||
|
||||
|
||||
}; |
||||
|
||||
#endif // ELIDELABEL_HPP
|
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#include "esclineedit.h" |
||||
|
||||
#include <QKeyEvent> |
||||
#include <QMouseEvent> |
||||
|
||||
EscLineEdit::EscLineEdit(QWidget* parent) : |
||||
QLineEdit(parent) |
||||
{ |
||||
} |
||||
|
||||
void EscLineEdit::keyPressEvent(QKeyEvent* event) |
||||
{ |
||||
if (event->key() == Qt::Key_Escape && event->modifiers() == Qt::NoModifier) { |
||||
emit escPressed(); |
||||
} else { |
||||
QLineEdit::keyPressEvent(event); |
||||
} |
||||
} |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#ifndef ESCLINEEDIT_HPP |
||||
#define ESCLINEEDIT_HPP |
||||
|
||||
#include <QLineEdit> |
||||
|
||||
class EscLineEdit : public QLineEdit |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit EscLineEdit(QWidget* parent); |
||||
|
||||
protected: |
||||
void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE; |
||||
|
||||
signals: |
||||
void escPressed(); |
||||
|
||||
}; |
||||
|
||||
#endif // ESCLINEEDIT_HPP
|
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
#include "friend.h" |
||||
#include "friendlist.h" |
||||
#include "friendwidget.h" |
||||
|
||||
Friend::Friend(int FriendId, QString UserId) |
||||
: friendId(FriendId), userId(UserId) |
||||
{ |
||||
widget = new FriendWidget(friendId, userId); |
||||
chatForm = new ChatForm(this); |
||||
} |
||||
|
||||
Friend::~Friend() |
||||
{ |
||||
delete chatForm; |
||||
delete widget; |
||||
} |
||||
|
||||
void Friend::setName(QString name) |
||||
{ |
||||
widget->name.setText(name); |
||||
chatForm->setName(name); |
||||
} |
||||
|
||||
void Friend::setStatusMessage(QString message) |
||||
{ |
||||
widget->statusMessage.setText(message); |
||||
chatForm->setStatusMessage(message); |
||||
} |
||||
|
||||
QString Friend::getName() |
||||
{ |
||||
return widget->name.text(); |
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
#ifndef FRIEND_H |
||||
#define FRIEND_H |
||||
|
||||
#include <QString> |
||||
#include "chatform.h" |
||||
|
||||
class FriendWidget; |
||||
|
||||
struct Friend |
||||
{ |
||||
public: |
||||
Friend(int FriendId, QString UserId); |
||||
~Friend(); |
||||
void setName(QString name); |
||||
void setStatusMessage(QString message); |
||||
QString getName(); |
||||
|
||||
public: |
||||
FriendWidget* widget; |
||||
int friendId; |
||||
QString userId; |
||||
ChatForm* chatForm; |
||||
}; |
||||
|
||||
#endif // FRIEND_H
|
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
#include "friend.h" |
||||
#include "friendlist.h" |
||||
#include <QMenu> |
||||
|
||||
QList<Friend*> FriendList::friendList; |
||||
|
||||
Friend* FriendList::addFriend(int friendId, QString userId) |
||||
{ |
||||
Friend* newfriend = new Friend(friendId, userId); |
||||
friendList.append(newfriend); |
||||
return newfriend; |
||||
} |
||||
|
||||
Friend* FriendList::findFriend(int friendId) |
||||
{ |
||||
for (Friend* f : friendList) |
||||
if (f->friendId == friendId) |
||||
return f; |
||||
return nullptr; |
||||
} |
||||
|
||||
void FriendList::removeFriend(int friendId) |
||||
{ |
||||
for (int i=0; i<friendList.size(); i++) |
||||
{ |
||||
if (friendList[i]->friendId == friendId) |
||||
{ |
||||
friendList.removeAt(i); |
||||
return; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
#ifndef FRIENDLIST_H |
||||
#define FRIENDLIST_H |
||||
|
||||
#include <QString> |
||||
#include <QList> |
||||
|
||||
class Friend; |
||||
|
||||
class FriendList |
||||
{ |
||||
public: |
||||
FriendList(); |
||||
static Friend* addFriend(int friendId, QString userId); |
||||
static Friend* findFriend(int friendId); |
||||
static void removeFriend(int friendId); |
||||
|
||||
public: |
||||
static QList<Friend*> friendList; |
||||
}; |
||||
|
||||
#endif // FRIENDLIST_H
|
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#include "friendrequestdialog.h" |
||||
|
||||
#include <QVBoxLayout> |
||||
#include <QDialogButtonBox> |
||||
#include <QLabel> |
||||
#include <QLineEdit> |
||||
#include <QPlainTextEdit> |
||||
#include <QPushButton> |
||||
|
||||
FriendRequestDialog::FriendRequestDialog(QWidget *parent, const QString &userId, const QString &message) : |
||||
QDialog(parent) |
||||
{ |
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); |
||||
setWindowTitle("Friend request"); |
||||
|
||||
QLabel *friendsLabel = new QLabel("Someone wants to make friends with you.", this); |
||||
QLabel *userIdLabel = new QLabel("User ID:", this); |
||||
QLineEdit *userIdEdit = new QLineEdit(userId, this); |
||||
userIdEdit->setCursorPosition(0); |
||||
userIdEdit->setReadOnly(true); |
||||
QLabel *messageLabel = new QLabel("Friend request message:", this); |
||||
QPlainTextEdit *messageEdit = new QPlainTextEdit(message, this); |
||||
messageEdit->setReadOnly(true); |
||||
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, this); |
||||
|
||||
buttonBox->addButton("Accept", QDialogButtonBox::AcceptRole); |
||||
buttonBox->addButton("Reject", QDialogButtonBox::RejectRole); |
||||
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &FriendRequestDialog::accept); |
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &FriendRequestDialog::reject); |
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this); |
||||
|
||||
layout->addWidget(friendsLabel); |
||||
layout->addSpacing(12); |
||||
layout->addWidget(userIdLabel); |
||||
layout->addWidget(userIdEdit); |
||||
layout->addWidget(messageLabel); |
||||
layout->addWidget(messageEdit); |
||||
layout->addWidget(buttonBox); |
||||
|
||||
resize(300, 200); |
||||
} |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#ifndef FRIENDREQUESTDIALOG_HPP |
||||
#define FRIENDREQUESTDIALOG_HPP |
||||
|
||||
#include <QDialog> |
||||
|
||||
class FriendRequestDialog : public QDialog |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit FriendRequestDialog(QWidget *parent, const QString &userId, const QString &message); |
||||
}; |
||||
|
||||
#endif // FRIENDREQUESTDIALOG_HPP
|
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
#include "friendwidget.h" |
||||
#include <QContextMenuEvent> |
||||
#include <QMenu> |
||||
|
||||
FriendWidget::FriendWidget(int FriendId, QString id) |
||||
: friendId(FriendId) |
||||
{ |
||||
this->setLayout(&layout); |
||||
this->setFixedWidth(225); |
||||
this->setFixedHeight(55); |
||||
layout.setSpacing(0); |
||||
layout.setMargin(0); |
||||
textLayout.setSpacing(0); |
||||
textLayout.setMargin(0); |
||||
|
||||
avatar.setPixmap(QPixmap("img/contact list icons/contact.png")); |
||||
name.setText(id); |
||||
statusPic.setPixmap(QPixmap("img/status/dot_away.png")); |
||||
QFont small; |
||||
small.setPixelSize(10); |
||||
statusMessage.setFont(small); |
||||
QPalette pal; |
||||
pal.setColor(QPalette::WindowText,Qt::gray); |
||||
statusMessage.setPalette(pal); |
||||
|
||||
textLayout.addStretch(); |
||||
textLayout.addWidget(&name); |
||||
textLayout.addWidget(&statusMessage); |
||||
textLayout.addStretch(); |
||||
|
||||
layout.addSpacing(20); |
||||
layout.addWidget(&avatar); |
||||
layout.addSpacing(5); |
||||
layout.addLayout(&textLayout); |
||||
layout.addStretch(); |
||||
layout.addSpacing(5); |
||||
layout.addWidget(&statusPic); |
||||
layout.addSpacing(5); |
||||
} |
||||
|
||||
void FriendWidget::mouseReleaseEvent (QMouseEvent*) |
||||
{ |
||||
emit friendWidgetClicked(this); |
||||
} |
||||
|
||||
void FriendWidget::contextMenuEvent(QContextMenuEvent * event) |
||||
{ |
||||
QPoint pos = event->globalPos(); |
||||
QMenu menu; |
||||
menu.addAction("Remove friend"); |
||||
|
||||
QAction* selectedItem = menu.exec(pos); |
||||
if (selectedItem) |
||||
{ |
||||
if (selectedItem->text() == "Remove friend") |
||||
{ |
||||
hide(); |
||||
emit removeFriend(friendId); |
||||
return; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
#ifndef FRIENDWIDGET_H |
||||
#define FRIENDWIDGET_H |
||||
|
||||
#include <QWidget> |
||||
#include <QLabel> |
||||
#include <QVBoxLayout> |
||||
#include <QHBoxLayout> |
||||
|
||||
struct FriendWidget : public QWidget |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
FriendWidget(int FriendId, QString id); |
||||
void mouseReleaseEvent (QMouseEvent* event); |
||||
void contextMenuEvent(QContextMenuEvent * event); |
||||
|
||||
signals: |
||||
void friendWidgetClicked(FriendWidget* widget); |
||||
void removeFriend(int friendId); |
||||
|
||||
public: |
||||
int friendId; |
||||
QLabel avatar, name, statusMessage, statusPic; |
||||
QHBoxLayout layout; |
||||
QVBoxLayout textLayout; |
||||
}; |
||||
|
||||
#endif // FRIENDWIDGET_H
|
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
#include "group.h" |
||||
#include "groupwidget.h" |
||||
#include "groupchatform.h" |
||||
#include "friendlist.h" |
||||
#include "friend.h" |
||||
#include "widget.h" |
||||
#include "core.h" |
||||
#include <QDebug> |
||||
|
||||
Group::Group(int GroupId, QString Name) |
||||
: groupId(GroupId), nPeers{0}, hasPeerInfo{false} |
||||
{ |
||||
widget = new GroupWidget(groupId, Name); |
||||
chatForm = new GroupChatForm(this); |
||||
connect(&peerInfoTimer, SIGNAL(timeout()), this, SLOT(queryPeerInfo())); |
||||
peerInfoTimer.setInterval(500); |
||||
peerInfoTimer.setSingleShot(false); |
||||
//peerInfoTimer.start();
|
||||
} |
||||
|
||||
Group::~Group() |
||||
{ |
||||
delete chatForm; |
||||
delete widget; |
||||
} |
||||
|
||||
void Group::queryPeerInfo() |
||||
{ |
||||
const Core* core = Widget::getInstance()->getCore(); |
||||
int nPeersResult = core->getGroupNumberPeers(groupId); |
||||
if (nPeersResult == -1) |
||||
{ |
||||
qDebug() << "Group::queryPeerInfo: Can't get number of peers"; |
||||
return; |
||||
} |
||||
nPeers = nPeersResult; |
||||
widget->onUserListChanged(); |
||||
chatForm->onUserListChanged(); |
||||
|
||||
if (nPeersResult == 0) |
||||
return; |
||||
|
||||
bool namesOk = true; |
||||
QList<QString> names = core->getGroupPeerNames(groupId); |
||||
if (names.isEmpty()) |
||||
{ |
||||
qDebug() << "Group::queryPeerInfo: Can't get names of peers"; |
||||
return; |
||||
} |
||||
for (int i=0; i<names.size(); i++) |
||||
{ |
||||
QString name = names[i]; |
||||
if (name.isEmpty()) |
||||
{ |
||||
name = "<Unknown>"; |
||||
namesOk = false; |
||||
} |
||||
peers[i] = name; |
||||
} |
||||
nPeers = names.size(); |
||||
|
||||
widget->onUserListChanged(); |
||||
chatForm->onUserListChanged(); |
||||
|
||||
if (namesOk) |
||||
{ |
||||
qDebug() << "Group::queryPeerInfo: Successfully loaded names"; |
||||
hasPeerInfo = true; |
||||
peerInfoTimer.stop(); |
||||
} |
||||
} |
||||
|
||||
void Group::addPeer(int peerId, QString name) |
||||
{ |
||||
if (peers.contains(peerId)) |
||||
qWarning() << "Group::addPeer: peerId already used, overwriting anyway"; |
||||
if (name.isEmpty()) |
||||
peers[peerId] = "<Unknown>"; |
||||
else |
||||
peers[peerId] = name; |
||||
nPeers++; |
||||
widget->onUserListChanged(); |
||||
chatForm->onUserListChanged(); |
||||
} |
||||
|
||||
void Group::removePeer(int peerId) |
||||
{ |
||||
peers.remove(peerId); |
||||
widget->onUserListChanged(); |
||||
chatForm->onUserListChanged(); |
||||
} |
||||
|
||||
void Group::updatePeer(int peerId, QString name) |
||||
{ |
||||
peers[peerId] = name; |
||||
widget->onUserListChanged(); |
||||
chatForm->onUserListChanged(); |
||||
} |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
#ifndef GROUP_H |
||||
#define GROUP_H |
||||
|
||||
#include <QList> |
||||
#include <QMap> |
||||
#include <QTimer> |
||||
|
||||
#define RETRY_PEER_INFO_INTERVAL 500 |
||||
|
||||
class Friend; |
||||
class GroupWidget; |
||||
class GroupChatForm; |
||||
|
||||
class Group : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
Group(int GroupId, QString Name); |
||||
~Group(); |
||||
void addPeer(int peerId, QString name); |
||||
void removePeer(int peerId); |
||||
void updatePeer(int peerId, QString newName); |
||||
|
||||
private slots: |
||||
void queryPeerInfo(); |
||||
|
||||
public: |
||||
int groupId; |
||||
QMap<int,QString> peers; |
||||
int nPeers; |
||||
GroupWidget* widget; |
||||
GroupChatForm* chatForm; |
||||
bool hasPeerInfo; |
||||
QTimer peerInfoTimer; |
||||
}; |
||||
|
||||
#endif // GROUP_H
|
@ -0,0 +1,175 @@
@@ -0,0 +1,175 @@
|
||||
#include "groupchatform.h" |
||||
#include "group.h" |
||||
#include "groupwidget.h" |
||||
#include "widget.h" |
||||
#include "friend.h" |
||||
#include "friendlist.h" |
||||
#include <QFont> |
||||
#include <QTime> |
||||
#include <QScrollBar> |
||||
|
||||
GroupChatForm::GroupChatForm(Group* chatGroup) |
||||
: group(chatGroup), curRow{0}, lockSliderToBottom{true} |
||||
{ |
||||
main = new QWidget(), head = new QWidget(), chatAreaWidget = new QWidget(); |
||||
headLayout = new QHBoxLayout(), mainFootLayout = new QHBoxLayout(); |
||||
headTextLayout = new QVBoxLayout(), mainLayout = new QVBoxLayout(); |
||||
mainChatLayout = new QGridLayout(); |
||||
avatar = new QLabel(), name = new QLabel(), nusers = new QLabel(), namesList = new QLabel(); |
||||
msgEdit = new ChatTextEdit(); |
||||
sendButton = new QPushButton(); |
||||
chatArea = new QScrollArea(); |
||||
QFont bold; |
||||
bold.setBold(true); |
||||
QFont small; |
||||
small.setPixelSize(10); |
||||
name->setText(group->widget->name.text()); |
||||
name->setFont(bold); |
||||
nusers->setFont(small); |
||||
nusers->setText(QString("%1 users in chat").arg(group->peers.size())); |
||||
avatar->setPixmap(QPixmap("img/contact list icons/group.png")); |
||||
QString names; |
||||
for (QString& s : group->peers) |
||||
names.append(s+", "); |
||||
names.chop(2); |
||||
namesList->setText(names); |
||||
namesList->setFont(small); |
||||
|
||||
chatAreaWidget->setLayout(mainChatLayout); |
||||
chatArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); |
||||
chatArea->setWidgetResizable(true); |
||||
mainChatLayout->setColumnStretch(1,1); |
||||
mainChatLayout->setHorizontalSpacing(10); |
||||
|
||||
sendButton->setIcon(QIcon("img/button icons/sendmessage_2x.png")); |
||||
sendButton->setFlat(true); |
||||
QPalette pal; |
||||
pal.setColor(QPalette::Button, QColor(107,194,96)); // Tox Green
|
||||
sendButton->setPalette(pal); |
||||
sendButton->setAutoFillBackground(true); |
||||
msgEdit->setFixedHeight(50); |
||||
sendButton->setFixedSize(50, 50); |
||||
|
||||
main->setLayout(mainLayout); |
||||
mainLayout->addWidget(chatArea); |
||||
mainLayout->addLayout(mainFootLayout); |
||||
mainLayout->setMargin(0); |
||||
|
||||
mainFootLayout->addWidget(msgEdit); |
||||
mainFootLayout->addWidget(sendButton); |
||||
|
||||
head->setLayout(headLayout); |
||||
headLayout->addWidget(avatar); |
||||
headLayout->addLayout(headTextLayout); |
||||
headLayout->addStretch(); |
||||
headLayout->setMargin(0); |
||||
|
||||
headTextLayout->addStretch(); |
||||
headTextLayout->addWidget(name); |
||||
headTextLayout->addWidget(nusers); |
||||
headTextLayout->addWidget(namesList); |
||||
headTextLayout->setMargin(0); |
||||
headTextLayout->setSpacing(0); |
||||
headTextLayout->addStretch(); |
||||
|
||||
chatArea->setWidget(chatAreaWidget); |
||||
|
||||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered())); |
||||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered())); |
||||
connect(chatArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged())); |
||||
} |
||||
|
||||
GroupChatForm::~GroupChatForm() |
||||
{ |
||||
delete head; |
||||
delete main; |
||||
} |
||||
|
||||
void GroupChatForm::show(Ui::Widget &ui) |
||||
{ |
||||
ui.mainContent->layout()->addWidget(main); |
||||
ui.mainHead->layout()->addWidget(head); |
||||
main->show(); |
||||
head->show(); |
||||
} |
||||
|
||||
void GroupChatForm::setName(QString newName) |
||||
{ |
||||
name->setText(newName); |
||||
} |
||||
|
||||
void GroupChatForm::onSendTriggered() |
||||
{ |
||||
QString msg = msgEdit->toPlainText(); |
||||
if (msg.isEmpty()) |
||||
return; |
||||
msgEdit->clear(); |
||||
emit sendMessage(group->groupId, msg); |
||||
} |
||||
|
||||
void GroupChatForm::addGroupMessage(QString message, int peerId) |
||||
{ |
||||
QLabel *msgAuthor; |
||||
if (group->peers.contains(peerId)) |
||||
msgAuthor = new QLabel(group->peers[peerId]); |
||||
else |
||||
msgAuthor = new QLabel("<Unknown>"); |
||||
|
||||
QLabel *msgText = new QLabel(message); |
||||
QLabel *msgDate = new QLabel(QTime::currentTime().toString("hh:mm")); |
||||
|
||||
addMessage(msgAuthor, msgText, msgDate); |
||||
} |
||||
|
||||
void GroupChatForm::addMessage(QString author, QString message, QString date) |
||||
{ |
||||
addMessage(new QLabel(author), new QLabel(message), new QLabel(date)); |
||||
} |
||||
|
||||
void GroupChatForm::addMessage(QLabel* author, QLabel* message, QLabel* date) |
||||
{ |
||||
QScrollBar* scroll = chatArea->verticalScrollBar(); |
||||
lockSliderToBottom = scroll && scroll->value() == scroll->maximum(); |
||||
author->setAlignment(Qt::AlignTop | Qt::AlignLeft); |
||||
date->setAlignment(Qt::AlignTop); |
||||
if (author->text() == Widget::getInstance()->getUsername()) |
||||
{ |
||||
QPalette pal; |
||||
pal.setColor(QPalette::WindowText, Qt::gray); |
||||
author->setPalette(pal); |
||||
message->setPalette(pal); |
||||
} |
||||
if (previousName.isEmpty() || previousName != author->text()) |
||||
{ |
||||
if (curRow) |
||||
{ |
||||
mainChatLayout->setRowStretch(curRow, 0); |
||||
mainChatLayout->addItem(new QSpacerItem(0,AUTHOR_CHANGE_SPACING),curRow,0,1,3); |
||||
curRow++; |
||||
} |
||||
mainChatLayout->addWidget(author, curRow, 0); |
||||
} |
||||
previousName = author->text(); |
||||
mainChatLayout->addWidget(message, curRow, 1); |
||||
mainChatLayout->addWidget(date, curRow, 3); |
||||
mainChatLayout->setRowStretch(curRow+1, 1); |
||||
mainChatLayout->setRowStretch(curRow, 0); |
||||
curRow++; |
||||
} |
||||
|
||||
void GroupChatForm::onSliderRangeChanged() |
||||
{ |
||||
QScrollBar* scroll = chatArea->verticalScrollBar(); |
||||
if (lockSliderToBottom) |
||||
scroll->setValue(scroll->maximum()); |
||||
} |
||||
|
||||
void GroupChatForm::onUserListChanged() |
||||
{ |
||||
nusers->setText(QString("%1 users in chat").arg(group->nPeers)); |
||||
QString names; |
||||
for (QString& s : group->peers) |
||||
names.append(s+", "); |
||||
names.chop(2); |
||||
namesList->setText(names); |
||||
} |
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
#ifndef GROUPCHATFORM_H |
||||
#define GROUPCHATFORM_H |
||||
|
||||
#include <QLabel> |
||||
#include <QWidget> |
||||
#include <QVBoxLayout> |
||||
#include <QHBoxLayout> |
||||
#include <QGridLayout> |
||||
#include <QTextEdit> |
||||
#include <QScrollArea> |
||||
#include <QTime> |
||||
|
||||
#include "chattextedit.h" |
||||
#include "ui_widget.h" |
||||
|
||||
// Spacing in px inserted when the author of the last message changes
|
||||
#define AUTHOR_CHANGE_SPACING 5 |
||||
|
||||
class Group; |
||||
|
||||
class GroupChatForm : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
GroupChatForm(Group* chatGroup); |
||||
~GroupChatForm(); |
||||
void show(Ui::Widget& ui); |
||||
void setName(QString newName); |
||||
void addGroupMessage(QString message, int peerId); |
||||
void addMessage(QString author, QString message, QString date=QTime::currentTime().toString("hh:mm")); |
||||
void addMessage(QLabel* author, QLabel* message, QLabel* date); |
||||
void onUserListChanged(); |
||||
|
||||
signals: |
||||
void sendMessage(int, QString); |
||||
|
||||
private slots: |
||||
void onSendTriggered(); |
||||
void onSliderRangeChanged(); |
||||
|
||||
private: |
||||
Group* group; |
||||
QHBoxLayout *headLayout, *mainFootLayout; |
||||
QVBoxLayout *headTextLayout, *mainLayout; |
||||
QGridLayout *mainChatLayout; |
||||
QLabel *avatar, *name, *nusers, *namesList; |
||||
ChatTextEdit *msgEdit; |
||||
QPushButton *sendButton; |
||||
QScrollArea *chatArea; |
||||
QWidget *main, *head, *chatAreaWidget; |
||||
QString previousName; |
||||
int curRow; |
||||
bool lockSliderToBottom; |
||||
}; |
||||
|
||||
#endif // GROUPCHATFORM_H
|
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
#include "grouplist.h" |
||||
#include "group.h" |
||||
|
||||
QList<Group*> GroupList::groupList; |
||||
|
||||
Group* GroupList::addGroup(int groupId, QString name) |
||||
{ |
||||
Group* newGroup = new Group(groupId, name); |
||||
groupList.append(newGroup); |
||||
return newGroup; |
||||
} |
||||
|
||||
Group* GroupList::findGroup(int groupId) |
||||
{ |
||||
for (Group* g : groupList) |
||||
if (g->groupId == groupId) |
||||
return g; |
||||
return nullptr; |
||||
} |
||||
|
||||
void GroupList::removeGroup(int groupId) |
||||
{ |
||||
for (int i=0; i<groupList.size(); i++) |
||||
{ |
||||
if (groupList[i]->groupId == groupId) |
||||
{ |
||||
groupList.removeAt(i); |
||||
return; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
#ifndef GROUPLIST_H |
||||
#define GROUPLIST_H |
||||
|
||||
#include <QString> |
||||
#include <QList> |
||||
#include <QMap> |
||||
|
||||
class Group; |
||||
|
||||
class GroupList |
||||
{ |
||||
public: |
||||
GroupList(); |
||||
static Group* addGroup(int groupId, QString name); |
||||
static Group* findGroup(int groupId); |
||||
static void removeGroup(int groupId); |
||||
|
||||
public: |
||||
static QList<Group*> groupList; |
||||
}; |
||||
|
||||
#endif // GROUPLIST_H
|
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
#include "groupwidget.h" |
||||
#include "grouplist.h" |
||||
#include "group.h" |
||||
#include <QPalette> |
||||
#include <QMenu> |
||||
#include <QContextMenuEvent> |
||||
|
||||
GroupWidget::GroupWidget(int GroupId, QString Name) |
||||
: groupId{GroupId} |
||||
{ |
||||
this->setLayout(&layout); |
||||
this->setFixedWidth(225); |
||||
this->setFixedHeight(55); |
||||
layout.setSpacing(0); |
||||
layout.setMargin(0); |
||||
textLayout.setSpacing(0); |
||||
textLayout.setMargin(0); |
||||
|
||||
avatar.setPixmap(QPixmap("img/contact list icons/group_2x.png")); |
||||
name.setText(Name); |
||||
QFont small; |
||||
small.setPixelSize(10); |
||||
nusers.setFont(small); |
||||
QPalette pal; |
||||
pal.setColor(QPalette::WindowText,Qt::gray); |
||||
nusers.setPalette(pal); |
||||
Group* g = GroupList::findGroup(groupId); |
||||
if (g) |
||||
nusers.setText(QString("%1 users in chat").arg(g->peers.size())); |
||||
else |
||||
nusers.setText("0 users in chat"); |
||||
|
||||
textLayout.addStretch(); |
||||
textLayout.addWidget(&name); |
||||
textLayout.addWidget(&nusers); |
||||
textLayout.addStretch(); |
||||
|
||||
layout.addSpacing(20); |
||||
layout.addWidget(&avatar); |
||||
layout.addSpacing(5); |
||||
layout.addLayout(&textLayout); |
||||
layout.addStretch(); |
||||
} |
||||
|
||||
void GroupWidget::mouseReleaseEvent (QMouseEvent*) |
||||
{ |
||||
emit groupWidgetClicked(this); |
||||
} |
||||
|
||||
void GroupWidget::contextMenuEvent(QContextMenuEvent * event) |
||||
{ |
||||
QPoint pos = event->globalPos(); |
||||
QMenu menu; |
||||
menu.addAction("Quit group"); |
||||
|
||||
QAction* selectedItem = menu.exec(pos); |
||||
if (selectedItem) |
||||
{ |
||||
if (selectedItem->text() == "Quit group") |
||||
{ |
||||
hide(); |
||||
emit removeGroup(groupId); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void GroupWidget::onUserListChanged() |
||||
{ |
||||
Group* g = GroupList::findGroup(groupId); |
||||
if (g) |
||||
nusers.setText(QString("%1 users in chat").arg(g->nPeers)); |
||||
else |
||||
nusers.setText("0 users in chat"); |
||||
} |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
#ifndef GROUPWIDGET_H |
||||
#define GROUPWIDGET_H |
||||
|
||||
#include <QWidget> |
||||
#include <QLabel> |
||||
#include <QHBoxLayout> |
||||
#include <QVBoxLayout> |
||||
|
||||
class GroupWidget : public QWidget |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
GroupWidget(int GroupId, QString Name); |
||||
void onUserListChanged(); |
||||
void mouseReleaseEvent (QMouseEvent* event); |
||||
void contextMenuEvent(QContextMenuEvent * event); |
||||
|
||||
signals: |
||||
void groupWidgetClicked(GroupWidget* widget); |
||||
void removeGroup(int groupId); |
||||
|
||||
public: |
||||
int groupId; |
||||
QLabel avatar, name, nusers; |
||||
QHBoxLayout layout; |
||||
QVBoxLayout textLayout; |
||||
}; |
||||
|
||||
#endif // GROUPWIDGET_H
|
After Width: | Height: | Size: 172 B |
After Width: | Height: | Size: 249 B |
After Width: | Height: | Size: 152 B |
After Width: | Height: | Size: 214 B |
After Width: | Height: | Size: 274 B |
After Width: | Height: | Size: 432 B |
After Width: | Height: | Size: 307 B |
After Width: | Height: | Size: 510 B |
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 323 B |
After Width: | Height: | Size: 178 B |
After Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 129 B |
After Width: | Height: | Size: 327 B |
After Width: | Height: | Size: 533 B |
After Width: | Height: | Size: 248 B |
After Width: | Height: | Size: 382 B |
After Width: | Height: | Size: 183 B |
After Width: | Height: | Size: 267 B |
After Width: | Height: | Size: 164 B |
After Width: | Height: | Size: 192 B |
After Width: | Height: | Size: 790 B |
After Width: | Height: | Size: 314 B |
After Width: | Height: | Size: 512 B |
After Width: | Height: | Size: 291 B |
After Width: | Height: | Size: 474 B |
After Width: | Height: | Size: 288 B |
After Width: | Height: | Size: 433 B |
After Width: | Height: | Size: 361 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 407 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 472 B |
After Width: | Height: | Size: 852 B |
After Width: | Height: | Size: 240 B |
After Width: | Height: | Size: 376 B |
After Width: | Height: | Size: 458 B |
After Width: | Height: | Size: 825 B |
After Width: | Height: | Size: 272 B |
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 766 B |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
#include "widget.h" |
||||
#include <QApplication> |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
QApplication a(argc, argv); |
||||
a.setApplicationName("Toxgui"); |
||||
a.setOrganizationName("Tox"); |
||||
Widget* w = Widget::getInstance(); |
||||
w->show(); |
||||
|
||||
int errorcode = a.exec(); |
||||
|
||||
delete w; |
||||
|
||||
return errorcode; |
||||
} |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
<RCC> |
||||
<qresource prefix="/conf"> |
||||
<file alias="settings.ini">res/settings.ini</file> |
||||
</qresource> |
||||
</RCC> |
@ -0,0 +1,55 @@
@@ -0,0 +1,55 @@
|
||||
[DHT%20Server] |
||||
dhtServerList\size=13 |
||||
dhtServerList\1\name=benwaffle |
||||
dhtServerList\1\userId=8E6667FF967EA30B3DC3DB57A4B533152476E7AAE090158B9C2D9DF58ECC7B78 |
||||
dhtServerList\1\address=192.3.30.132 |
||||
dhtServerList\1\port=33445 |
||||
dhtServerList\2\name=zlacki RU #1 |
||||
dhtServerList\2\userId=D59F99384592DE4C8AB9D534D5197DB90F4755CC9E975ED0C565E18468A1445B |
||||
dhtServerList\2\address=31.192.105.19 |
||||
dhtServerList\2\port=33445 |
||||
dhtServerList\3\name=aitjcize |
||||
dhtServerList\3\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029 |
||||
dhtServerList\3\address=54.199.139.199 |
||||
dhtServerList\3\port=33445 |
||||
dhtServerList\4\name=zlacki US |
||||
dhtServerList\4\userId=9430A83211A7AD1C294711D069D587028CA0B4782FA43CB9B30008247A43C944 |
||||
dhtServerList\4\address=69.42.220.58 |
||||
dhtServerList\4\port=33445 |
||||
dhtServerList\5\name=platos |
||||
dhtServerList\5\userId=B24E2FB924AE66D023FE1E42A2EE3B432010206F751A2FFD3E297383ACF1572E |
||||
dhtServerList\5\address=66.175.223.88 |
||||
dhtServerList\5\port=33445 |
||||
dhtServerList\6\name=stqism |
||||
dhtServerList\6\userId=951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F |
||||
dhtServerList\6\address=192.254.75.98 |
||||
dhtServerList\6\port=33445 |
||||
dhtServerList\7\name=nurupo |
||||
dhtServerList\7\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67 |
||||
dhtServerList\7\address=192.210.149.121 |
||||
dhtServerList\7\port=33445 |
||||
dhtServerList\8\name=JmanGuy |
||||
dhtServerList\8\userId=20C797E098701A848B07D0384222416B0EFB60D08CECB925B860CAEAAB572067 |
||||
dhtServerList\8\address=66.74.15.98 |
||||
dhtServerList\8\port=33445 |
||||
dhtServerList\9\name=zlacki NL |
||||
dhtServerList\9\userId=CC2B02636A2ADBC2871D6EC57C5E9589D4FD5E6F98A14743A4B949914CF26D39 |
||||
dhtServerList\9\address=5.39.218.35 |
||||
dhtServerList\9\port=33445 |
||||
dhtServerList\10\name=zlacki RU #2 |
||||
dhtServerList\10\userId=AE27E1E72ADA3DC423C60EEBACA241456174048BE76A283B41AD32D953182D49 |
||||
dhtServerList\10\address=193.107.16.73 |
||||
dhtServerList\10\port=33445 |
||||
dhtServerList\11\name=stal |
||||
dhtServerList\11\userId=A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074 |
||||
dhtServerList\11\address=23.226.230.47 |
||||
dhtServerList\11\port=33445 |
||||
dhtServerList\12\name=sonOfRa |
||||
dhtServerList\12\userId=DDCF277B8B45B0D357D78AA4E201766932DF6CDB7179FC7D5C9F3C2E8E705326 |
||||
dhtServerList\12\address=144.76.60.215 |
||||
dhtServerList\12\port=33445 |
||||
dhtServerList\13\name=anonymous |
||||
dhtServerList\13\userId=5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143 |
||||
dhtServerList\13\address=192.184.81.118 |
||||
dhtServerList\13\port=33445 |
||||
|
@ -0,0 +1,343 @@
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#include "settings.h" |
||||
|
||||
#include <QApplication> |
||||
#include <QDir> |
||||
#include <QFile> |
||||
#include <QSettings> |
||||
#include <QStandardPaths> |
||||
|
||||
const QString Settings::FILENAME = "settings.ini"; |
||||
|
||||
Settings::Settings() : |
||||
loaded(false) |
||||
{ |
||||
load(); |
||||
} |
||||
|
||||
Settings::~Settings() |
||||
{ |
||||
save(); |
||||
} |
||||
|
||||
Settings& Settings::getInstance() |
||||
{ |
||||
static Settings settings; |
||||
return settings; |
||||
} |
||||
|
||||
void Settings::load() |
||||
{ |
||||
if (loaded) { |
||||
return; |
||||
} |
||||
|
||||
QString filePath = getSettingsDirPath() + '/' + FILENAME; |
||||
|
||||
//if no settings file exist -- use the default one
|
||||
QFile file(filePath); |
||||
if (!file.exists()) { |
||||
filePath = ":/conf/" + FILENAME; |
||||
} |
||||
|
||||
QSettings s(filePath, QSettings::IniFormat); |
||||
s.beginGroup("DHT Server"); |
||||
int serverListSize = s.beginReadArray("dhtServerList"); |
||||
for (int i = 0; i < serverListSize; i ++) { |
||||
s.setArrayIndex(i); |
||||
DhtServer server; |
||||
server.name = s.value("name").toString(); |
||||
server.userId = s.value("userId").toString(); |
||||
server.address = s.value("address").toString(); |
||||
server.port = s.value("port").toInt(); |
||||
dhtServerList << server; |
||||
} |
||||
s.endArray(); |
||||
s.endGroup(); |
||||
|
||||
//NOTE: uncomment when logging will be implemented
|
||||
/*
|
||||
s.beginGroup("Logging"); |
||||
enableLogging = s.value("enableLogging", false).toBool(); |
||||
encryptLogs = s.value("encryptLogs", true).toBool(); |
||||
s.endGroup(); |
||||
*/ |
||||
|
||||
s.beginGroup("General"); |
||||
username = s.value("username", "My name").toString(); |
||||
statusMessage = s.value("statusMessage", "My status").toString(); |
||||
s.endGroup(); |
||||
|
||||
s.beginGroup("Widgets"); |
||||
QList<QString> objectNames = s.childKeys(); |
||||
for (const QString& name : objectNames) { |
||||
widgetSettings[name] = s.value(name).toByteArray(); |
||||
} |
||||
s.endGroup(); |
||||
|
||||
s.beginGroup("GUI"); |
||||
enableSmoothAnimation = s.value("smoothAnimation", true).toBool(); |
||||
smileyPack = s.value("smileyPack").toByteArray(); |
||||
customEmojiFont = s.value("customEmojiFont", true).toBool(); |
||||
emojiFontFamily = s.value("emojiFontFamily", "DejaVu Sans").toString(); |
||||
emojiFontPointSize = s.value("emojiFontPointSize", QApplication::font().pointSize()).toInt(); |
||||
firstColumnHandlePos = s.value("firstColumnHandlePos", 50).toInt(); |
||||
secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt(); |
||||
timestampFormat = s.value("timestampFormat", "hh:mm").toString(); |
||||
minimizeOnClose = s.value("minimizeOnClose", false).toBool(); |
||||
s.endGroup(); |
||||
|
||||
s.beginGroup("Privacy"); |
||||
typingNotification = s.value("typingNotification", false).toBool(); |
||||
s.endGroup(); |
||||
|
||||
loaded = true; |
||||
} |
||||
|
||||
void Settings::save() |
||||
{ |
||||
QString filePath = getSettingsDirPath() + '/' + FILENAME; |
||||
|
||||
QSettings s(filePath, QSettings::IniFormat); |
||||
|
||||
s.clear(); |
||||
|
||||
s.beginGroup("DHT Server"); |
||||
s.beginWriteArray("dhtServerList", dhtServerList.size()); |
||||
for (int i = 0; i < dhtServerList.size(); i ++) { |
||||
s.setArrayIndex(i); |
||||
s.setValue("name", dhtServerList[i].name); |
||||
s.setValue("userId", dhtServerList[i].userId); |
||||
s.setValue("address", dhtServerList[i].address); |
||||
s.setValue("port", dhtServerList[i].port); |
||||
} |
||||
s.endArray(); |
||||
s.endGroup(); |
||||
|
||||
//NOTE: uncomment when logging will be implemented
|
||||
/*
|
||||
s.beginGroup("Logging"); |
||||
s.setValue("storeLogs", enableLogging); |
||||
s.setValue("encryptLogs", encryptLogs); |
||||
s.endGroup(); |
||||
*/ |
||||
|
||||
s.beginGroup("General"); |
||||
s.setValue("username", username); |
||||
s.setValue("statusMessage", statusMessage); |
||||
s.endGroup(); |
||||
|
||||
s.beginGroup("Widgets"); |
||||
const QList<QString> widgetNames = widgetSettings.keys(); |
||||
for (const QString& name : widgetNames) { |
||||
s.setValue(name, widgetSettings.value(name)); |
||||
} |
||||
s.endGroup(); |
||||
|
||||
s.beginGroup("GUI"); |
||||
s.setValue("smoothAnimation", enableSmoothAnimation); |
||||
s.setValue("smileyPack", smileyPack); |
||||
s.setValue("customEmojiFont", customEmojiFont); |
||||
s.setValue("emojiFontFamily", emojiFontFamily); |
||||
s.setValue("emojiFontPointSize", emojiFontPointSize); |
||||
s.setValue("firstColumnHandlePos", firstColumnHandlePos); |
||||
s.setValue("secondColumnHandlePosFromRight", secondColumnHandlePosFromRight); |
||||
s.setValue("timestampFormat", timestampFormat); |
||||
s.setValue("minimizeOnClose", minimizeOnClose); |
||||
s.endGroup(); |
||||
|
||||
s.beginGroup("Privacy"); |
||||
s.setValue("typingNotification", typingNotification); |
||||
s.endGroup(); |
||||
} |
||||
|
||||
QString Settings::getSettingsDirPath() |
||||
{ |
||||
// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845
|
||||
#ifdef Q_OS_WIN |
||||
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); |
||||
#else |
||||
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + '/' + qApp->organizationName() + '/' + qApp->applicationName(); |
||||
#endif |
||||
} |
||||
|
||||
const QList<Settings::DhtServer>& Settings::getDhtServerList() const |
||||
{ |
||||
return dhtServerList; |
||||
} |
||||
|
||||
void Settings::setDhtServerList(const QList<DhtServer>& newDhtServerList) |
||||
{ |
||||
dhtServerList = newDhtServerList; |
||||
emit dhtServerListChanged(); |
||||
} |
||||
|
||||
QString Settings::getUsername() const |
||||
{ |
||||
return username; |
||||
} |
||||
|
||||
void Settings::setUsername(const QString& newUsername) |
||||
{ |
||||
username = newUsername; |
||||
} |
||||
|
||||
QString Settings::getStatusMessage() const |
||||
{ |
||||
return statusMessage; |
||||
} |
||||
|
||||
void Settings::setStatusMessage(const QString& newMessage) |
||||
{ |
||||
statusMessage = newMessage; |
||||
} |
||||
|
||||
bool Settings::getEnableLogging() const |
||||
{ |
||||
return enableLogging; |
||||
} |
||||
|
||||
void Settings::setEnableLogging(bool newValue) |
||||
{ |
||||
enableLogging = newValue; |
||||
} |
||||
|
||||
bool Settings::getEncryptLogs() const |
||||
{ |
||||
return encryptLogs; |
||||
} |
||||
|
||||
void Settings::setEncryptLogs(bool newValue) |
||||
{ |
||||
encryptLogs = newValue; |
||||
} |
||||
|
||||
void Settings::setWidgetData(const QString& uniqueName, const QByteArray& data) |
||||
{ |
||||
widgetSettings[uniqueName] = data; |
||||
} |
||||
|
||||
QByteArray Settings::getWidgetData(const QString& uniqueName) const |
||||
{ |
||||
return widgetSettings.value(uniqueName); |
||||
} |
||||
|
||||
bool Settings::isAnimationEnabled() const |
||||
{ |
||||
return enableSmoothAnimation; |
||||
} |
||||
|
||||
void Settings::setAnimationEnabled(bool newValue) |
||||
{ |
||||
enableSmoothAnimation = newValue; |
||||
} |
||||
|
||||
QByteArray Settings::getSmileyPack() const |
||||
{ |
||||
return smileyPack; |
||||
} |
||||
|
||||
void Settings::setSmileyPack(const QByteArray &value) |
||||
{ |
||||
smileyPack = value; |
||||
emit smileyPackChanged(); |
||||
} |
||||
|
||||
bool Settings::isCurstomEmojiFont() const |
||||
{ |
||||
return customEmojiFont; |
||||
} |
||||
|
||||
void Settings::setCurstomEmojiFont(bool value) |
||||
{ |
||||
customEmojiFont = value; |
||||
emit emojiFontChanged(); |
||||
} |
||||
|
||||
int Settings::getEmojiFontPointSize() const |
||||
{ |
||||
return emojiFontPointSize; |
||||
} |
||||
|
||||
void Settings::setEmojiFontPointSize(int value) |
||||
{ |
||||
emojiFontPointSize = value; |
||||
emit emojiFontChanged(); |
||||
} |
||||
|
||||
int Settings::getFirstColumnHandlePos() const |
||||
{ |
||||
return firstColumnHandlePos; |
||||
} |
||||
|
||||
void Settings::setFirstColumnHandlePos(const int pos) |
||||
{ |
||||
firstColumnHandlePos = pos; |
||||
} |
||||
|
||||
int Settings::getSecondColumnHandlePosFromRight() const |
||||
{ |
||||
return secondColumnHandlePosFromRight; |
||||
} |
||||
|
||||
void Settings::setSecondColumnHandlePosFromRight(const int pos) |
||||
{ |
||||
secondColumnHandlePosFromRight = pos; |
||||
} |
||||
|
||||
const QString &Settings::getTimestampFormat() const |
||||
{ |
||||
return timestampFormat; |
||||
} |
||||
|
||||
void Settings::setTimestampFormat(const QString &format) |
||||
{ |
||||
timestampFormat = format; |
||||
emit timestampFormatChanged(); |
||||
} |
||||
|
||||
QString Settings::getEmojiFontFamily() const |
||||
{ |
||||
return emojiFontFamily; |
||||
} |
||||
|
||||
void Settings::setEmojiFontFamily(const QString &value) |
||||
{ |
||||
emojiFontFamily = value; |
||||
emit emojiFontChanged(); |
||||
} |
||||
|
||||
bool Settings::isMinimizeOnCloseEnabled() const |
||||
{ |
||||
return minimizeOnClose; |
||||
} |
||||
|
||||
void Settings::setMinimizeOnClose(bool newValue) |
||||
{ |
||||
minimizeOnClose = newValue; |
||||
} |
||||
|
||||
bool Settings::isTypingNotificationEnabled() const |
||||
{ |
||||
return typingNotification; |
||||
} |
||||
|
||||
void Settings::setTypingNotification(bool enabled) |
||||
{ |
||||
typingNotification = enabled; |
||||
} |
@ -0,0 +1,163 @@
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com> |
||||
|
||||
This file is part of Tox Qt GUI. |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
This program 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 COPYING file for more details. |
||||
*/ |
||||
|
||||
#ifndef SETTINGS_HPP |
||||
#define SETTINGS_HPP |
||||
|
||||
#include <QHash> |
||||
#include <QMainWindow> |
||||
#include <QSplitter> |
||||
|
||||
class Settings : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
static Settings& getInstance(); |
||||
~Settings(); |
||||
|
||||
void executeSettingsDialog(QWidget* parent); |
||||
|
||||
static QString getSettingsDirPath(); |
||||
|
||||
struct DhtServer |
||||
{ |
||||
QString name; |
||||
QString userId; |
||||
QString address; |
||||
int port; |
||||
}; |
||||
|
||||
const QList<DhtServer>& getDhtServerList() const; |
||||
void setDhtServerList(const QList<DhtServer>& newDhtServerList); |
||||
|
||||
QString getUsername() const; |
||||
void setUsername(const QString& newUsername); |
||||
|
||||
QString getStatusMessage() const; |
||||
void setStatusMessage(const QString& newMessage); |
||||
|
||||
bool getEnableLogging() const; |
||||
void setEnableLogging(bool newValue); |
||||
|
||||
bool getEncryptLogs() const; |
||||
void setEncryptLogs(bool newValue); |
||||
|
||||
// Assume all widgets have unique names
|
||||
// Don't use it to save every single thing you want to save, use it
|
||||
// for some general purpose widgets, such as MainWindows or Splitters,
|
||||
// which have widget->saveX() and widget->loadX() methods.
|
||||
QByteArray getWidgetData(const QString& uniqueName) const; |
||||
void setWidgetData(const QString& uniqueName, const QByteArray& data); |
||||
|
||||
// Wrappers around getWidgetData() and setWidgetData()
|
||||
// Assume widget has a unique objectName set
|
||||
template <class T> |
||||
void restoreGeometryState(T* widget) const |
||||
{ |
||||
widget->restoreGeometry(getWidgetData(widget->objectName() + "Geometry")); |
||||
widget->restoreState(getWidgetData(widget->objectName() + "State")); |
||||
} |
||||
template <class T> |
||||
void saveGeometryState(const T* widget) |
||||
{ |
||||
setWidgetData(widget->objectName() + "Geometry", widget->saveGeometry()); |
||||
setWidgetData(widget->objectName() + "State", widget->saveState()); |
||||
} |
||||
|
||||
bool isAnimationEnabled() const; |
||||
void setAnimationEnabled(bool newValue); |
||||
|
||||
QByteArray getSmileyPack() const; |
||||
void setSmileyPack(const QByteArray &value); |
||||
|
||||
bool isCurstomEmojiFont() const; |
||||
void setCurstomEmojiFont(bool value); |
||||
|
||||
QString getEmojiFontFamily() const; |
||||
void setEmojiFontFamily(const QString &value); |
||||
|
||||
int getEmojiFontPointSize() const; |
||||
void setEmojiFontPointSize(int value); |
||||
|
||||
// ChatView
|
||||
int getFirstColumnHandlePos() const; |
||||
void setFirstColumnHandlePos(const int pos); |
||||
|
||||
int getSecondColumnHandlePosFromRight() const; |
||||
void setSecondColumnHandlePosFromRight(const int pos); |
||||
|
||||
const QString &getTimestampFormat() const; |
||||
void setTimestampFormat(const QString &format); |
||||
|
||||
bool isMinimizeOnCloseEnabled() const; |
||||
void setMinimizeOnClose(bool newValue); |
||||
|
||||
// Privacy
|
||||
bool isTypingNotificationEnabled() const; |
||||
void setTypingNotification(bool enabled); |
||||
|
||||
private: |
||||
Settings(); |
||||
Settings(Settings &settings) = delete; |
||||
Settings& operator=(const Settings&) = delete; |
||||
|
||||
void save(); |
||||
void load(); |
||||
|
||||
|
||||
|
||||
static const QString FILENAME; |
||||
|
||||
bool loaded; |
||||
|
||||
QList<DhtServer> dhtServerList; |
||||
int dhtServerId; |
||||
bool dontShowDhtDialog; |
||||
|
||||
QString username; |
||||
QString statusMessage; |
||||
|
||||
bool enableLogging; |
||||
bool encryptLogs; |
||||
|
||||
QHash<QString, QByteArray> widgetSettings; |
||||
|
||||
// GUI
|
||||
bool enableSmoothAnimation; |
||||
QByteArray smileyPack; |
||||
bool customEmojiFont; |
||||
QString emojiFontFamily; |
||||
int emojiFontPointSize; |
||||
bool minimizeOnClose; |
||||
|
||||
// ChatView
|
||||
int firstColumnHandlePos; |
||||
int secondColumnHandlePosFromRight; |
||||
QString timestampFormat; |
||||
|
||||
// Privacy
|
||||
bool typingNotification; |
||||
|
||||
signals: |
||||
//void dataChanged();
|
||||
void dhtServerListChanged(); |
||||
void logStorageOptsChanged(); |
||||
void smileyPackChanged(); |
||||
void emojiFontChanged(); |
||||
void timestampFormatChanged(); |
||||
}; |
||||
|
||||
#endif // SETTINGS_HPP
|