2019-08-14 14:54:46 +00:00
|
|
|
/*
|
|
|
|
* Squawk messenger.
|
|
|
|
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2019-03-29 14:54:34 +00:00
|
|
|
#include "squawk.h"
|
|
|
|
#include "ui_squawk.h"
|
2019-04-02 15:46:18 +00:00
|
|
|
#include <QDebug>
|
2019-04-07 20:14:15 +00:00
|
|
|
#include <QIcon>
|
2019-03-29 14:54:34 +00:00
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
Squawk::Squawk(Models::Roster& p_rosterModel, QWidget *parent) :
|
2019-03-29 14:54:34 +00:00
|
|
|
QMainWindow(parent),
|
|
|
|
m_ui(new Ui::Squawk),
|
2022-04-03 20:53:46 +00:00
|
|
|
accounts(nullptr),
|
|
|
|
preferences(nullptr),
|
|
|
|
about(nullptr),
|
2022-04-22 15:26:18 +00:00
|
|
|
rosterModel(p_rosterModel),
|
2019-06-18 15:08:03 +00:00
|
|
|
contextMenu(new QMenu()),
|
2020-04-07 20:33:03 +00:00
|
|
|
vCards(),
|
2022-04-03 20:53:46 +00:00
|
|
|
currentConversation(nullptr),
|
2020-04-14 16:30:33 +00:00
|
|
|
restoreSelection(),
|
|
|
|
needToRestore(false)
|
2019-03-29 14:54:34 +00:00
|
|
|
{
|
|
|
|
m_ui->setupUi(this);
|
2019-03-31 21:05:09 +00:00
|
|
|
m_ui->roster->setModel(&rosterModel);
|
2019-06-12 17:18:18 +00:00
|
|
|
m_ui->roster->setContextMenuPolicy(Qt::CustomContextMenu);
|
2022-01-08 22:28:29 +00:00
|
|
|
if (QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1) {
|
|
|
|
m_ui->roster->setColumnWidth(1, 52);
|
|
|
|
} else {
|
|
|
|
m_ui->roster->setColumnWidth(1, 26);
|
|
|
|
}
|
2019-10-16 19:38:35 +00:00
|
|
|
m_ui->roster->setIconSize(QSize(20, 20));
|
|
|
|
m_ui->roster->header()->setStretchLastSection(false);
|
|
|
|
m_ui->roster->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
2019-03-29 14:54:34 +00:00
|
|
|
|
2020-04-04 16:40:32 +00:00
|
|
|
for (int i = static_cast<int>(Shared::AvailabilityLowest); i < static_cast<int>(Shared::AvailabilityHighest) + 1; ++i) {
|
2019-07-01 13:53:01 +00:00
|
|
|
Shared::Availability av = static_cast<Shared::Availability>(i);
|
2020-04-03 22:28:15 +00:00
|
|
|
m_ui->comboBox->addItem(Shared::availabilityIcon(av), Shared::Global::getName(av));
|
2019-04-07 20:14:15 +00:00
|
|
|
}
|
2020-04-03 22:28:15 +00:00
|
|
|
m_ui->comboBox->setCurrentIndex(static_cast<int>(Shared::Availability::offline));
|
2022-05-31 18:04:36 +00:00
|
|
|
createTrayIcon();
|
|
|
|
|
2019-11-02 20:50:25 +00:00
|
|
|
connect(m_ui->actionAccounts, &QAction::triggered, this, &Squawk::onAccounts);
|
2022-01-16 19:54:57 +00:00
|
|
|
connect(m_ui->actionPreferences, &QAction::triggered, this, &Squawk::onPreferences);
|
2019-11-02 20:50:25 +00:00
|
|
|
connect(m_ui->actionAddContact, &QAction::triggered, this, &Squawk::onNewContact);
|
|
|
|
connect(m_ui->actionAddConference, &QAction::triggered, this, &Squawk::onNewConference);
|
2022-05-31 18:04:36 +00:00
|
|
|
connect(m_ui->actionQuit, &QAction::triggered, [this]() { hide(); close(); }); // Actually closing
|
2019-11-02 20:50:25 +00:00
|
|
|
connect(m_ui->comboBox, qOverload<int>(&QComboBox::activated), this, &Squawk::onComboboxActivated);
|
2020-04-12 15:55:05 +00:00
|
|
|
//connect(m_ui->roster, &QTreeView::doubleClicked, this, &Squawk::onRosterItemDoubleClicked);
|
2019-11-02 20:50:25 +00:00
|
|
|
connect(m_ui->roster, &QTreeView::customContextMenuRequested, this, &Squawk::onRosterContextMenu);
|
2019-12-25 10:24:20 +00:00
|
|
|
connect(m_ui->roster, &QTreeView::collapsed, this, &Squawk::onItemCollepsed);
|
2020-04-11 20:00:15 +00:00
|
|
|
connect(m_ui->roster->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &Squawk::onRosterSelectionChanged);
|
2019-06-15 15:29:15 +00:00
|
|
|
|
2019-11-02 20:50:25 +00:00
|
|
|
connect(rosterModel.accountsModel, &Models::Accounts::sizeChanged, this, &Squawk::onAccountsSizeChanged);
|
2020-04-12 15:55:05 +00:00
|
|
|
connect(contextMenu, &QMenu::aboutToHide, this, &Squawk::onContextAboutToHide);
|
2022-04-03 20:53:46 +00:00
|
|
|
connect(m_ui->actionAboutSquawk, &QAction::triggered, this, &Squawk::onAboutSquawkCalled);
|
2019-03-31 21:05:09 +00:00
|
|
|
//m_ui->mainToolBar->addWidget(m_ui->comboBox);
|
2019-10-23 14:49:56 +00:00
|
|
|
|
2020-03-30 21:17:10 +00:00
|
|
|
if (testAttribute(Qt::WA_TranslucentBackground)) {
|
|
|
|
m_ui->roster->viewport()->setAutoFillBackground(false);
|
|
|
|
}
|
2020-04-07 20:33:03 +00:00
|
|
|
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup("ui");
|
|
|
|
settings.beginGroup("window");
|
|
|
|
if (settings.contains("geometry")) {
|
|
|
|
restoreGeometry(settings.value("geometry").toByteArray());
|
|
|
|
}
|
|
|
|
if (settings.contains("state")) {
|
|
|
|
restoreState(settings.value("state").toByteArray());
|
|
|
|
}
|
|
|
|
settings.endGroup();
|
2020-04-11 20:00:15 +00:00
|
|
|
|
|
|
|
if (settings.contains("splitter")) {
|
|
|
|
m_ui->splitter->restoreState(settings.value("splitter").toByteArray());
|
|
|
|
}
|
2020-04-07 20:33:03 +00:00
|
|
|
settings.endGroup();
|
2019-03-29 14:54:34 +00:00
|
|
|
}
|
|
|
|
|
2022-05-31 18:04:36 +00:00
|
|
|
QSystemTrayIcon* Squawk::trayIcon;
|
|
|
|
|
2019-03-29 14:54:34 +00:00
|
|
|
Squawk::~Squawk() {
|
2019-06-12 17:18:18 +00:00
|
|
|
delete contextMenu;
|
2022-05-31 18:04:36 +00:00
|
|
|
delete trayIcon;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Squawk::createTrayIcon()
|
|
|
|
{
|
|
|
|
QSettings settings;
|
|
|
|
trayIcon = new QSystemTrayIcon(this);
|
|
|
|
trayIcon->setIcon(QApplication::windowIcon());
|
|
|
|
|
|
|
|
QMenu * menu = new QMenu(this);
|
|
|
|
QAction * viewWindow = new QAction("Open Main Window", this);//TODO add translations
|
|
|
|
QAction * quitAction = new QAction("Quit", this);
|
|
|
|
|
|
|
|
connect(viewWindow, SIGNAL(triggered()), this, SLOT(show()));
|
|
|
|
connect(quitAction, &QAction::triggered, [this]() { hide(); close(); }); // Actually closing
|
|
|
|
|
|
|
|
menu->addAction(viewWindow);
|
|
|
|
menu->addAction(quitAction);
|
|
|
|
|
|
|
|
trayIcon->setContextMenu(menu);
|
|
|
|
if(settings.value("trayIconCheckbox").toBool())
|
|
|
|
trayIcon->show();
|
2019-03-29 14:54:34 +00:00
|
|
|
}
|
|
|
|
|
2022-05-31 18:04:36 +00:00
|
|
|
|
2019-03-29 14:54:34 +00:00
|
|
|
void Squawk::onAccounts()
|
|
|
|
{
|
2022-04-03 20:53:46 +00:00
|
|
|
if (accounts == nullptr) {
|
2020-04-04 16:40:32 +00:00
|
|
|
accounts = new Accounts(rosterModel.accountsModel);
|
2019-03-29 14:54:34 +00:00
|
|
|
accounts->setAttribute(Qt::WA_DeleteOnClose);
|
2019-11-03 18:46:40 +00:00
|
|
|
connect(accounts, &Accounts::destroyed, this, &Squawk::onAccountsClosed);
|
|
|
|
connect(accounts, &Accounts::newAccount, this, &Squawk::newAccountRequest);
|
|
|
|
connect(accounts, &Accounts::changeAccount, this, &Squawk::modifyAccountRequest);
|
|
|
|
connect(accounts, &Accounts::connectAccount, this, &Squawk::connectAccount);
|
|
|
|
connect(accounts, &Accounts::disconnectAccount, this, &Squawk::disconnectAccount);
|
|
|
|
connect(accounts, &Accounts::removeAccount, this, &Squawk::removeAccountRequest);
|
2019-03-30 20:13:13 +00:00
|
|
|
|
2019-03-29 14:54:34 +00:00
|
|
|
accounts->show();
|
|
|
|
} else {
|
2019-03-30 20:13:13 +00:00
|
|
|
accounts->show();
|
|
|
|
accounts->raise();
|
|
|
|
accounts->activateWindow();
|
2019-03-29 14:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-16 19:54:57 +00:00
|
|
|
void Squawk::onPreferences()
|
|
|
|
{
|
2022-04-03 20:53:46 +00:00
|
|
|
if (preferences == nullptr) {
|
2022-01-16 19:54:57 +00:00
|
|
|
preferences = new Settings();
|
|
|
|
preferences->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
connect(preferences, &Settings::destroyed, this, &Squawk::onPreferencesClosed);
|
2022-02-19 18:31:49 +00:00
|
|
|
connect(preferences, &Settings::changeDownloadsPath, this, &Squawk::changeDownloadsPath);
|
2022-01-16 19:54:57 +00:00
|
|
|
|
|
|
|
preferences->show();
|
|
|
|
} else {
|
|
|
|
preferences->show();
|
|
|
|
preferences->raise();
|
|
|
|
preferences->activateWindow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-15 15:29:15 +00:00
|
|
|
void Squawk::onAccountsSizeChanged(unsigned int size)
|
|
|
|
{
|
|
|
|
if (size > 0) {
|
|
|
|
m_ui->actionAddContact->setEnabled(true);
|
2019-09-04 16:38:52 +00:00
|
|
|
m_ui->actionAddConference->setEnabled(true);
|
2019-06-15 15:29:15 +00:00
|
|
|
} else {
|
|
|
|
m_ui->actionAddContact->setEnabled(false);
|
2019-09-04 16:38:52 +00:00
|
|
|
m_ui->actionAddConference->setEnabled(false);
|
2019-06-15 15:29:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Squawk::onNewContact()
|
|
|
|
{
|
|
|
|
NewContact* nc = new NewContact(rosterModel.accountsModel, this);
|
|
|
|
|
2019-11-03 18:46:40 +00:00
|
|
|
connect(nc, &NewContact::accepted, this, &Squawk::onNewContactAccepted);
|
|
|
|
connect(nc, &NewContact::rejected, nc, &NewContact::deleteLater);
|
2019-06-15 15:29:15 +00:00
|
|
|
|
|
|
|
nc->exec();
|
|
|
|
}
|
|
|
|
|
2019-09-04 16:38:52 +00:00
|
|
|
void Squawk::onNewConference()
|
|
|
|
{
|
|
|
|
JoinConference* jc = new JoinConference(rosterModel.accountsModel, this);
|
|
|
|
|
2019-11-03 18:46:40 +00:00
|
|
|
connect(jc, &JoinConference::accepted, this, &Squawk::onJoinConferenceAccepted);
|
|
|
|
connect(jc, &JoinConference::rejected, jc, &JoinConference::deleteLater);
|
2019-09-04 16:38:52 +00:00
|
|
|
|
|
|
|
jc->exec();
|
|
|
|
}
|
|
|
|
|
2019-06-15 15:29:15 +00:00
|
|
|
void Squawk::onNewContactAccepted()
|
|
|
|
{
|
|
|
|
NewContact* nc = static_cast<NewContact*>(sender());
|
|
|
|
NewContact::Data value = nc->value();
|
|
|
|
|
|
|
|
emit addContactRequest(value.account, value.jid, value.name, value.groups);
|
|
|
|
|
|
|
|
nc->deleteLater();
|
|
|
|
}
|
|
|
|
|
2019-09-04 16:38:52 +00:00
|
|
|
void Squawk::onJoinConferenceAccepted()
|
|
|
|
{
|
|
|
|
JoinConference* jc = static_cast<JoinConference*>(sender());
|
|
|
|
JoinConference::Data value = jc->value();
|
|
|
|
|
|
|
|
emit addRoomRequest(value.account, value.jid, value.nick, value.password, value.autoJoin);
|
|
|
|
|
|
|
|
jc->deleteLater();
|
|
|
|
}
|
|
|
|
|
2019-03-29 14:54:34 +00:00
|
|
|
void Squawk::closeEvent(QCloseEvent* event)
|
|
|
|
{
|
2022-05-31 18:04:36 +00:00
|
|
|
QSettings settings;
|
|
|
|
if(this->isVisible() && settings.value("trayIconCheckbox").toBool()){
|
|
|
|
event->ignore();
|
|
|
|
this->hide();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (accounts != nullptr) {
|
|
|
|
accounts->close();
|
|
|
|
}
|
|
|
|
if (preferences != nullptr) {
|
|
|
|
preferences->close();
|
|
|
|
}
|
|
|
|
if (about != nullptr) {
|
|
|
|
about->close();
|
|
|
|
}
|
2022-04-22 15:26:18 +00:00
|
|
|
|
2022-05-31 18:04:36 +00:00
|
|
|
for (std::map<QString, VCard*>::const_iterator itr = vCards.begin(), end = vCards.end(); itr != end; ++itr) {
|
|
|
|
disconnect(itr->second, &VCard::destroyed, this, &Squawk::onVCardClosed);
|
|
|
|
itr->second->close();
|
|
|
|
}
|
|
|
|
vCards.clear();
|
|
|
|
writeSettings();
|
|
|
|
emit closing();
|
|
|
|
|
|
|
|
QMainWindow::closeEvent(event);
|
|
|
|
}
|
2019-03-29 14:54:34 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
void Squawk::onAccountsClosed() {
|
|
|
|
accounts = nullptr;}
|
2019-03-29 14:54:34 +00:00
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
void Squawk::onPreferencesClosed() {
|
|
|
|
preferences = nullptr;}
|
2019-03-30 20:13:13 +00:00
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
void Squawk::onAboutSquawkClosed() {
|
|
|
|
about = nullptr;}
|
2019-03-31 21:05:09 +00:00
|
|
|
|
|
|
|
void Squawk::onComboboxActivated(int index)
|
|
|
|
{
|
2020-04-03 22:28:15 +00:00
|
|
|
Shared::Availability av = Shared::Global::fromInt<Shared::Availability>(index);
|
2022-04-12 20:33:10 +00:00
|
|
|
emit changeState(av);
|
2019-03-31 21:05:09 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
void Squawk::expand(const QModelIndex& index) {
|
|
|
|
m_ui->roster->expand(index);}
|
2019-04-07 14:02:41 +00:00
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
void Squawk::stateChanged(Shared::Availability state) {
|
|
|
|
m_ui->comboBox->setCurrentIndex(static_cast<int>(state));}
|
2019-04-03 21:23:51 +00:00
|
|
|
|
2019-04-09 15:04:08 +00:00
|
|
|
void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
|
|
|
|
{
|
|
|
|
if (item.isValid()) {
|
|
|
|
Models::Item* node = static_cast<Models::Item*>(item.internalPointer());
|
2020-04-17 23:17:47 +00:00
|
|
|
if (node->type == Models::Item::reference) {
|
|
|
|
node = static_cast<Models::Reference*>(node)->dereference();
|
|
|
|
}
|
2022-04-03 20:53:46 +00:00
|
|
|
Models::Contact* contact = nullptr;
|
|
|
|
Models::Room* room = nullptr;
|
2019-04-09 15:04:08 +00:00
|
|
|
switch (node->type) {
|
|
|
|
case Models::Item::contact:
|
|
|
|
contact = static_cast<Models::Contact*>(node);
|
2022-04-22 15:26:18 +00:00
|
|
|
emit openConversation(Models::Roster::ElId(contact->getAccountName(), contact->getJid()));
|
2019-04-09 15:04:08 +00:00
|
|
|
break;
|
|
|
|
case Models::Item::presence:
|
|
|
|
contact = static_cast<Models::Contact*>(node->parentItem());
|
2022-04-22 15:26:18 +00:00
|
|
|
emit openConversation(Models::Roster::ElId(contact->getAccountName(), contact->getJid()), node->getName());
|
2019-04-09 15:04:08 +00:00
|
|
|
break;
|
2019-08-28 11:40:55 +00:00
|
|
|
case Models::Item::room:
|
|
|
|
room = static_cast<Models::Room*>(node);
|
2022-04-22 15:26:18 +00:00
|
|
|
emit openConversation(Models::Roster::ElId(room->getAccountName(), room->getJid()));
|
2019-08-28 11:40:55 +00:00
|
|
|
break;
|
2019-04-09 15:04:08 +00:00
|
|
|
default:
|
|
|
|
m_ui->roster->expand(item);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-05-15 17:36:37 +00:00
|
|
|
}
|
2019-05-29 15:05:54 +00:00
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
void Squawk::closeCurrentConversation()
|
2019-05-29 15:05:54 +00:00
|
|
|
{
|
2022-04-22 15:26:18 +00:00
|
|
|
if (currentConversation != nullptr) {
|
2020-04-11 20:00:15 +00:00
|
|
|
currentConversation->deleteLater();
|
2022-04-03 20:53:46 +00:00
|
|
|
currentConversation = nullptr;
|
2020-04-11 20:00:15 +00:00
|
|
|
m_ui->filler->show();
|
|
|
|
}
|
2019-05-29 15:05:54 +00:00
|
|
|
}
|
2019-06-12 17:18:18 +00:00
|
|
|
|
|
|
|
void Squawk::onRosterContextMenu(const QPoint& point)
|
|
|
|
{
|
|
|
|
QModelIndex index = m_ui->roster->indexAt(point);
|
|
|
|
if (index.isValid()) {
|
|
|
|
Models::Item* item = static_cast<Models::Item*>(index.internalPointer());
|
2020-04-17 23:17:47 +00:00
|
|
|
if (item->type == Models::Item::reference) {
|
|
|
|
item = static_cast<Models::Reference*>(item)->dereference();
|
|
|
|
}
|
2019-06-12 17:18:18 +00:00
|
|
|
contextMenu->clear();
|
|
|
|
bool hasMenu = false;
|
2020-04-03 22:28:15 +00:00
|
|
|
bool active = item->getAccountConnectionState() == Shared::ConnectionState::connected;
|
2019-06-12 17:18:18 +00:00
|
|
|
switch (item->type) {
|
|
|
|
case Models::Item::account: {
|
|
|
|
Models::Account* acc = static_cast<Models::Account*>(item);
|
|
|
|
hasMenu = true;
|
|
|
|
QString name = acc->getName();
|
|
|
|
|
2022-04-12 20:33:10 +00:00
|
|
|
if (acc->getActive()) {
|
|
|
|
QAction* con = contextMenu->addAction(Shared::icon("network-disconnect"), tr("Deactivate"));
|
|
|
|
connect(con, &QAction::triggered, std::bind(&Squawk::disconnectAccount, this, name));
|
2019-06-12 17:18:18 +00:00
|
|
|
} else {
|
2022-04-12 20:33:10 +00:00
|
|
|
QAction* con = contextMenu->addAction(Shared::icon("network-connect"), tr("Activate"));
|
|
|
|
connect(con, &QAction::triggered, std::bind(&Squawk::connectAccount, this, name));
|
2019-06-12 17:18:18 +00:00
|
|
|
}
|
|
|
|
|
2019-10-22 15:13:56 +00:00
|
|
|
QAction* card = contextMenu->addAction(Shared::icon("user-properties"), tr("VCard"));
|
|
|
|
card->setEnabled(active);
|
|
|
|
connect(card, &QAction::triggered, std::bind(&Squawk::onActivateVCard, this, name, acc->getBareJid(), true));
|
|
|
|
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* remove = contextMenu->addAction(Shared::icon("edit-delete"), tr("Remove"));
|
2022-04-13 19:02:48 +00:00
|
|
|
connect(remove, &QAction::triggered, std::bind(&Squawk::removeAccountRequest, this, name));
|
2019-06-12 17:18:18 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Models::Item::contact: {
|
|
|
|
Models::Contact* cnt = static_cast<Models::Contact*>(item);
|
2022-04-22 15:26:18 +00:00
|
|
|
Models::Roster::ElId id(cnt->getAccountName(), cnt->getJid());
|
|
|
|
QString cntName = cnt->getName();
|
2019-06-12 17:18:18 +00:00
|
|
|
hasMenu = true;
|
|
|
|
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* dialog = contextMenu->addAction(Shared::icon("mail-message"), tr("Open dialog"));
|
2019-09-28 14:30:16 +00:00
|
|
|
dialog->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(dialog, &QAction::triggered, std::bind(&Squawk::onRosterItemDoubleClicked, this, index));
|
2019-06-12 17:18:18 +00:00
|
|
|
|
|
|
|
Shared::SubscriptionState state = cnt->getState();
|
|
|
|
switch (state) {
|
2020-04-03 22:28:15 +00:00
|
|
|
case Shared::SubscriptionState::both:
|
|
|
|
case Shared::SubscriptionState::to: {
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* unsub = contextMenu->addAction(Shared::icon("news-unsubscribe"), tr("Unsubscribe"));
|
2019-09-28 14:30:16 +00:00
|
|
|
unsub->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(unsub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, false));
|
2019-06-12 17:18:18 +00:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:28:15 +00:00
|
|
|
case Shared::SubscriptionState::from:
|
|
|
|
case Shared::SubscriptionState::unknown:
|
|
|
|
case Shared::SubscriptionState::none: {
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* sub = contextMenu->addAction(Shared::icon("news-subscribe"), tr("Subscribe"));
|
2019-09-28 14:30:16 +00:00
|
|
|
sub->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(sub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, true));
|
2019-06-12 17:18:18 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-01 08:47:40 +00:00
|
|
|
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* rename = contextMenu->addAction(Shared::icon("edit-rename"), tr("Rename"));
|
2019-10-01 08:47:40 +00:00
|
|
|
rename->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(rename, &QAction::triggered, [this, cntName, id]() {
|
2019-10-01 08:47:40 +00:00
|
|
|
QInputDialog* dialog = new QInputDialog(this);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(dialog, &QDialog::accepted, [this, dialog, cntName, id]() {
|
2019-10-01 08:47:40 +00:00
|
|
|
QString newName = dialog->textValue();
|
|
|
|
if (newName != cntName) {
|
2022-04-22 15:26:18 +00:00
|
|
|
emit renameContactRequest(id.account, id.name, newName);
|
2019-10-01 08:47:40 +00:00
|
|
|
}
|
|
|
|
dialog->deleteLater();
|
|
|
|
});
|
|
|
|
connect(dialog, &QDialog::rejected, dialog, &QObject::deleteLater);
|
|
|
|
dialog->setInputMode(QInputDialog::TextInput);
|
2022-04-22 15:26:18 +00:00
|
|
|
dialog->setLabelText(tr("Input new name for %1\nor leave it empty for the contact \nto be displayed as %1").arg(id.name));
|
|
|
|
dialog->setWindowTitle(tr("Renaming %1").arg(id.name));
|
2019-10-01 08:47:40 +00:00
|
|
|
dialog->setTextValue(cntName);
|
|
|
|
dialog->exec();
|
|
|
|
});
|
2019-06-12 17:18:18 +00:00
|
|
|
|
2019-10-01 08:47:40 +00:00
|
|
|
|
2019-10-05 11:27:39 +00:00
|
|
|
QMenu* groupsMenu = contextMenu->addMenu(Shared::icon("group"), tr("Groups"));
|
2022-04-22 15:26:18 +00:00
|
|
|
std::deque<QString> groupList = rosterModel.groupList(id.account);
|
2019-09-28 14:30:16 +00:00
|
|
|
for (QString groupName : groupList) {
|
|
|
|
QAction* gr = groupsMenu->addAction(groupName);
|
|
|
|
gr->setCheckable(true);
|
2022-04-22 15:26:18 +00:00
|
|
|
gr->setChecked(rosterModel.groupHasContact(id.account, groupName, id.name));
|
2019-09-28 14:30:16 +00:00
|
|
|
gr->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(gr, &QAction::toggled, [this, groupName, id](bool checked) {
|
2019-09-28 14:30:16 +00:00
|
|
|
if (checked) {
|
2022-04-22 15:26:18 +00:00
|
|
|
emit addContactToGroupRequest(id.account, id.name, groupName);
|
2019-09-28 14:30:16 +00:00
|
|
|
} else {
|
2022-04-22 15:26:18 +00:00
|
|
|
emit removeContactFromGroupRequest(id.account, id.name, groupName);
|
2019-09-28 14:30:16 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-10-25 13:38:48 +00:00
|
|
|
QAction* newGroup = groupsMenu->addAction(Shared::icon("group-new"), tr("New group"));
|
2019-09-28 14:30:16 +00:00
|
|
|
newGroup->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(newGroup, &QAction::triggered, [this, id]() {
|
2019-09-28 14:30:16 +00:00
|
|
|
QInputDialog* dialog = new QInputDialog(this);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(dialog, &QDialog::accepted, [this, dialog, id]() {
|
|
|
|
emit addContactToGroupRequest(id.account, id.name, dialog->textValue());
|
2019-09-28 14:30:16 +00:00
|
|
|
dialog->deleteLater();
|
|
|
|
});
|
|
|
|
connect(dialog, &QDialog::rejected, dialog, &QObject::deleteLater);
|
|
|
|
dialog->setInputMode(QInputDialog::TextInput);
|
2019-10-05 11:27:39 +00:00
|
|
|
dialog->setLabelText(tr("New group name"));
|
2022-04-22 15:26:18 +00:00
|
|
|
dialog->setWindowTitle(tr("Add %1 to a new group").arg(id.name));
|
2019-09-28 14:30:16 +00:00
|
|
|
dialog->exec();
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2019-10-22 15:13:56 +00:00
|
|
|
QAction* card = contextMenu->addAction(Shared::icon("user-properties"), tr("VCard"));
|
|
|
|
card->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(card, &QAction::triggered, std::bind(&Squawk::onActivateVCard, this, id.account, id.name, false));
|
2019-10-22 15:13:56 +00:00
|
|
|
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* remove = contextMenu->addAction(Shared::icon("edit-delete"), tr("Remove"));
|
2019-09-28 14:30:16 +00:00
|
|
|
remove->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(remove, &QAction::triggered, std::bind(&Squawk::removeContactRequest, this, id.account, id.name));
|
2019-06-14 16:36:04 +00:00
|
|
|
|
2019-09-03 20:28:58 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Models::Item::room: {
|
|
|
|
Models::Room* room = static_cast<Models::Room*>(item);
|
|
|
|
hasMenu = true;
|
|
|
|
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* dialog = contextMenu->addAction(Shared::icon("mail-message"), tr("Open conversation"));
|
2019-09-28 14:30:16 +00:00
|
|
|
dialog->setEnabled(active);
|
2019-09-03 20:28:58 +00:00
|
|
|
connect(dialog, &QAction::triggered, [this, index]() {
|
|
|
|
onRosterItemDoubleClicked(index);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
Models::Roster::ElId id(room->getAccountName(), room->getJid());
|
|
|
|
if (room->getAutoJoin()) {
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* unsub = contextMenu->addAction(Shared::icon("news-unsubscribe"), tr("Unsubscribe"));
|
2019-09-28 14:30:16 +00:00
|
|
|
unsub->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(unsub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, false));
|
2019-09-03 20:28:58 +00:00
|
|
|
} else {
|
2022-04-22 15:26:18 +00:00
|
|
|
QAction* sub = contextMenu->addAction(Shared::icon("news-subscribe"), tr("Subscribe"));
|
|
|
|
sub->setEnabled(active);
|
|
|
|
connect(sub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, true));
|
2019-09-03 20:28:58 +00:00
|
|
|
}
|
|
|
|
|
2019-10-05 11:27:39 +00:00
|
|
|
QAction* remove = contextMenu->addAction(Shared::icon("edit-delete"), tr("Remove"));
|
2019-09-28 14:30:16 +00:00
|
|
|
remove->setEnabled(active);
|
2022-04-22 15:26:18 +00:00
|
|
|
connect(remove, &QAction::triggered, std::bind(&Squawk::removeRoomRequest, this, id.account, id.name));
|
2019-06-12 17:18:18 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (hasMenu) {
|
|
|
|
contextMenu->popup(m_ui->roster->viewport()->mapToGlobal(point));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-11 08:51:52 +00:00
|
|
|
|
2019-10-22 15:13:56 +00:00
|
|
|
void Squawk::responseVCard(const QString& jid, const Shared::VCard& card)
|
|
|
|
{
|
|
|
|
std::map<QString, VCard*>::const_iterator itr = vCards.find(jid);
|
|
|
|
if (itr != vCards.end()) {
|
|
|
|
itr->second->setVCard(card);
|
2019-10-31 14:01:48 +00:00
|
|
|
itr->second->hideProgress();
|
2019-10-22 15:13:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Squawk::onVCardClosed()
|
|
|
|
{
|
|
|
|
VCard* vCard = static_cast<VCard*>(sender());
|
|
|
|
|
|
|
|
std::map<QString, VCard*>::const_iterator itr = vCards.find(vCard->getJid());
|
|
|
|
if (itr == vCards.end()) {
|
|
|
|
qDebug() << "VCard has been closed but can not be found among other opened vCards, application is most probably going to crash";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
vCards.erase(itr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Squawk::onActivateVCard(const QString& account, const QString& jid, bool edition)
|
|
|
|
{
|
|
|
|
std::map<QString, VCard*>::const_iterator itr = vCards.find(jid);
|
|
|
|
VCard* card;
|
|
|
|
if (itr != vCards.end()) {
|
|
|
|
card = itr->second;
|
|
|
|
} else {
|
|
|
|
card = new VCard(jid, edition);
|
2019-10-23 14:49:56 +00:00
|
|
|
if (edition) {
|
|
|
|
card->setWindowTitle(tr("%1 account card").arg(account));
|
|
|
|
} else {
|
|
|
|
card->setWindowTitle(tr("%1 contact card").arg(jid));
|
|
|
|
}
|
2019-10-22 15:13:56 +00:00
|
|
|
card->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
vCards.insert(std::make_pair(jid, card));
|
|
|
|
|
|
|
|
connect(card, &VCard::destroyed, this, &Squawk::onVCardClosed);
|
2019-10-23 14:49:56 +00:00
|
|
|
connect(card, &VCard::saveVCard, std::bind( &Squawk::onVCardSave, this, std::placeholders::_1, account));
|
2019-10-22 15:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
card->show();
|
|
|
|
card->raise();
|
|
|
|
card->activateWindow();
|
2019-10-31 14:01:48 +00:00
|
|
|
card->showProgress(tr("Downloading vCard"));
|
2019-10-22 15:13:56 +00:00
|
|
|
|
|
|
|
emit requestVCard(account, jid);
|
|
|
|
}
|
2019-10-23 14:49:56 +00:00
|
|
|
|
|
|
|
void Squawk::onVCardSave(const Shared::VCard& card, const QString& account)
|
|
|
|
{
|
|
|
|
VCard* widget = static_cast<VCard*>(sender());
|
|
|
|
emit uploadVCard(account, card);
|
|
|
|
|
|
|
|
widget->deleteLater();
|
|
|
|
}
|
2019-12-25 10:24:20 +00:00
|
|
|
|
|
|
|
void Squawk::writeSettings()
|
|
|
|
{
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup("ui");
|
2022-04-22 15:26:18 +00:00
|
|
|
settings.beginGroup("window");
|
|
|
|
settings.setValue("geometry", saveGeometry());
|
|
|
|
settings.setValue("state", saveState());
|
|
|
|
settings.endGroup();
|
2019-12-25 10:24:20 +00:00
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
settings.setValue("splitter", m_ui->splitter->saveState());
|
|
|
|
settings.remove("roster");
|
|
|
|
settings.beginGroup("roster");
|
|
|
|
int size = rosterModel.accountsModel->rowCount(QModelIndex());
|
|
|
|
for (int i = 0; i < size; ++i) {
|
|
|
|
QModelIndex acc = rosterModel.index(i, 0, QModelIndex());
|
|
|
|
Models::Account* account = rosterModel.accountsModel->getAccount(i);
|
|
|
|
QString accName = account->getName();
|
|
|
|
settings.beginGroup(accName);
|
|
|
|
|
|
|
|
settings.setValue("expanded", m_ui->roster->isExpanded(acc));
|
|
|
|
std::deque<QString> groups = rosterModel.groupList(accName);
|
|
|
|
for (const QString& groupName : groups) {
|
|
|
|
settings.beginGroup(groupName);
|
|
|
|
QModelIndex gIndex = rosterModel.getGroupIndex(accName, groupName);
|
|
|
|
settings.setValue("expanded", m_ui->roster->isExpanded(gIndex));
|
|
|
|
settings.endGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
settings.endGroup();
|
|
|
|
}
|
2019-12-25 10:24:20 +00:00
|
|
|
settings.endGroup();
|
|
|
|
settings.endGroup();
|
2022-01-25 20:35:55 +00:00
|
|
|
|
|
|
|
settings.sync();
|
2019-12-25 10:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Squawk::onItemCollepsed(const QModelIndex& index)
|
|
|
|
{
|
|
|
|
QSettings settings;
|
|
|
|
Models::Item* item = static_cast<Models::Item*>(index.internalPointer());
|
|
|
|
switch (item->type) {
|
|
|
|
case Models::Item::account:
|
|
|
|
settings.setValue("ui/roster/" + item->getName() + "/expanded", false);
|
|
|
|
break;
|
|
|
|
case Models::Item::group: {
|
|
|
|
QModelIndex accInd = rosterModel.parent(index);
|
|
|
|
Models::Account* account = rosterModel.accountsModel->getAccount(accInd.row());
|
|
|
|
settings.setValue("ui/roster/" + account->getName() + "/" + item->getName() + "/expanded", false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-04-07 20:33:03 +00:00
|
|
|
|
2020-04-11 20:00:15 +00:00
|
|
|
void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIndex& previous)
|
2020-04-12 15:55:05 +00:00
|
|
|
{
|
|
|
|
if (restoreSelection.isValid() && restoreSelection == current) {
|
|
|
|
restoreSelection = QModelIndex();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-11 20:00:15 +00:00
|
|
|
if (current.isValid()) {
|
|
|
|
Models::Item* node = static_cast<Models::Item*>(current.internalPointer());
|
2020-04-17 23:17:47 +00:00
|
|
|
if (node->type == Models::Item::reference) {
|
|
|
|
node = static_cast<Models::Reference*>(node)->dereference();
|
|
|
|
}
|
2022-04-03 20:53:46 +00:00
|
|
|
Models::Contact* contact = nullptr;
|
|
|
|
Models::Room* room = nullptr;
|
2020-04-11 20:00:15 +00:00
|
|
|
QString res;
|
2022-04-03 20:53:46 +00:00
|
|
|
Models::Roster::ElId* id = nullptr;
|
2020-04-12 15:55:05 +00:00
|
|
|
bool hasContext = true;
|
2020-04-11 20:00:15 +00:00
|
|
|
switch (node->type) {
|
|
|
|
case Models::Item::contact:
|
|
|
|
contact = static_cast<Models::Contact*>(node);
|
|
|
|
id = new Models::Roster::ElId(contact->getAccountName(), contact->getJid());
|
|
|
|
break;
|
|
|
|
case Models::Item::presence:
|
|
|
|
contact = static_cast<Models::Contact*>(node->parentItem());
|
|
|
|
id = new Models::Roster::ElId(contact->getAccountName(), contact->getJid());
|
|
|
|
res = node->getName();
|
2020-04-12 15:55:05 +00:00
|
|
|
hasContext = false;
|
2020-04-11 20:00:15 +00:00
|
|
|
break;
|
|
|
|
case Models::Item::room:
|
|
|
|
room = static_cast<Models::Room*>(node);
|
|
|
|
id = new Models::Roster::ElId(room->getAccountName(), room->getJid());
|
|
|
|
break;
|
2020-04-12 15:55:05 +00:00
|
|
|
case Models::Item::participant:
|
|
|
|
room = static_cast<Models::Room*>(node->parentItem());
|
|
|
|
id = new Models::Roster::ElId(room->getAccountName(), room->getJid());
|
|
|
|
hasContext = false;
|
|
|
|
break;
|
|
|
|
case Models::Item::group:
|
|
|
|
hasContext = false;
|
2020-04-11 20:00:15 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-12 15:55:05 +00:00
|
|
|
if (hasContext && QGuiApplication::mouseButtons() & Qt::RightButton) {
|
2022-04-03 20:53:46 +00:00
|
|
|
if (id != nullptr) {
|
2020-04-12 15:55:05 +00:00
|
|
|
delete id;
|
|
|
|
}
|
2020-04-14 16:30:33 +00:00
|
|
|
needToRestore = true;
|
2020-04-12 15:55:05 +00:00
|
|
|
restoreSelection = previous;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-03 20:53:46 +00:00
|
|
|
if (id != nullptr) {
|
|
|
|
if (currentConversation != nullptr) {
|
2020-04-12 15:55:05 +00:00
|
|
|
if (currentConversation->getId() == *id) {
|
2022-04-03 20:53:46 +00:00
|
|
|
if (contact != nullptr) {
|
2020-04-11 20:00:15 +00:00
|
|
|
currentConversation->setPalResource(res);
|
|
|
|
}
|
2020-04-12 15:55:05 +00:00
|
|
|
return;
|
2020-04-11 20:00:15 +00:00
|
|
|
} else {
|
|
|
|
currentConversation->deleteLater();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m_ui->filler->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
Models::Account* acc = rosterModel.getAccount(id->account);
|
2022-04-03 20:53:46 +00:00
|
|
|
if (contact != nullptr) {
|
2020-04-11 20:00:15 +00:00
|
|
|
currentConversation = new Chat(acc, contact);
|
2022-04-03 20:53:46 +00:00
|
|
|
} else if (room != nullptr) {
|
2020-04-11 20:00:15 +00:00
|
|
|
currentConversation = new Room(acc, room);
|
|
|
|
}
|
|
|
|
if (!testAttribute(Qt::WA_TranslucentBackground)) {
|
|
|
|
currentConversation->setFeedFrames(true, false, true, true);
|
|
|
|
}
|
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
emit openedConversation();
|
2020-04-11 20:00:15 +00:00
|
|
|
|
|
|
|
if (res.size() > 0) {
|
|
|
|
currentConversation->setPalResource(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ui->splitter->insertWidget(1, currentConversation);
|
|
|
|
|
|
|
|
delete id;
|
|
|
|
} else {
|
2022-04-22 15:26:18 +00:00
|
|
|
closeCurrentConversation();
|
2020-04-11 20:00:15 +00:00
|
|
|
}
|
2020-04-12 15:55:05 +00:00
|
|
|
} else {
|
2022-04-22 15:26:18 +00:00
|
|
|
closeCurrentConversation();
|
2020-04-11 20:00:15 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-12 15:55:05 +00:00
|
|
|
|
|
|
|
void Squawk::onContextAboutToHide()
|
|
|
|
{
|
2020-04-14 16:30:33 +00:00
|
|
|
if (needToRestore) {
|
|
|
|
needToRestore = false;
|
|
|
|
m_ui->roster->selectionModel()->setCurrentIndex(restoreSelection, QItemSelectionModel::ClearAndSelect);
|
|
|
|
}
|
2020-04-12 15:55:05 +00:00
|
|
|
}
|
2022-04-03 20:53:46 +00:00
|
|
|
|
|
|
|
void Squawk::onAboutSquawkCalled()
|
|
|
|
{
|
|
|
|
if (about == nullptr) {
|
|
|
|
about = new About();
|
|
|
|
about->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
connect(about, &Settings::destroyed, this, &Squawk::onAboutSquawkClosed);
|
|
|
|
} else {
|
|
|
|
about->raise();
|
|
|
|
about->activateWindow();
|
|
|
|
}
|
2022-04-05 19:00:56 +00:00
|
|
|
about->show();
|
2022-04-03 20:53:46 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 15:26:18 +00:00
|
|
|
Models::Roster::ElId Squawk::currentConversationId() const
|
2022-04-03 20:53:46 +00:00
|
|
|
{
|
2022-04-22 15:26:18 +00:00
|
|
|
if (currentConversation == nullptr) {
|
|
|
|
return Models::Roster::ElId();
|
|
|
|
} else {
|
|
|
|
return Models::Roster::ElId(currentConversation->getAccount(), currentConversation->getJid());
|
|
|
|
}
|
2022-04-03 20:53:46 +00:00
|
|
|
}
|
2022-04-22 15:26:18 +00:00
|
|
|
|
2022-04-24 15:52:29 +00:00
|
|
|
void Squawk::select(QModelIndex index)
|
|
|
|
{
|
|
|
|
m_ui->roster->scrollTo(index, QAbstractItemView::EnsureVisible);
|
|
|
|
m_ui->roster->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
|
|
|
|
}
|