Compare commits
81 Commits
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (c) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ICommand/ICommandPriv.h" |
||||
#include "IRCClient/DCC.h" |
||||
#include <fmt/format.h> |
||||
|
||||
void ICommandPriv::cmd_dcc(const std::string& command, const std::string& target, const std::string& message) |
||||
{ |
||||
auto& mdi = MdiManager::instance(); |
||||
|
||||
if (command == "CHAT") { |
||||
auto result = connection.initiateDCC(); |
||||
if (result.second != IRCError::NoError) { |
||||
const auto code = static_cast<int>(result.second); |
||||
const auto errorStr = QString::fromStdString(IRCErrorToString(result.second)); |
||||
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, QObject::tr("/DCC: Unable to initiate DCC Chat to %1 [%2 (%3)]") |
||||
.arg( QString::fromStdString(target), errorStr, QString::number(code)) ); |
||||
} |
||||
else { |
||||
auto dcc = result.first; |
||||
const auto portno = dcc->isReversed() ? 0 |
||||
: dcc->port(); |
||||
|
||||
auto* window = mdi.createDCCSubwindow(mdi.currentStatus(), IWin::Type::DCCChat, result.first, IRCPrefix(target)); |
||||
|
||||
if (dcc->isReversed()) |
||||
window->print(PrintType::ProgramInfo, QObject::tr("Initiating CHAT with %1, please wait...") |
||||
.arg( QString::fromStdString(target) )); |
||||
else |
||||
window->print(PrintType::ProgramInfo, QObject::tr("Initiating CHAT with %1 on port %2, please wait...") |
||||
.arg( QString::fromStdString(target) ) |
||||
.arg(portno)); |
||||
|
||||
const auto myIp = findOwnIpAddress(); |
||||
const auto msg = fmt::format( "CHAT chat {} {}", |
||||
normalIpToLong(myIp), |
||||
portno |
||||
); |
||||
|
||||
cmd_ctcp(target, "DCC", msg); |
||||
} |
||||
} |
||||
else { |
||||
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, QObject::tr("/DCC: Unknown DCC method: %1") |
||||
.arg( QString::fromStdString(command) )); |
||||
} |
||||
} |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "AddServer.h" |
||||
#include "ui_AddServer.h" |
||||
#include <QFile> |
||||
#include <QJsonDocument> |
||||
#include <QJsonObject> |
||||
#include <QJsonArray> |
||||
|
||||
AddServer::AddServer(const QStringList& networkList, QWidget *parent) : |
||||
QDialog(parent), |
||||
ui(new Ui::AddServer) |
||||
{ |
||||
ui->setupUi(this); |
||||
setAttribute(Qt::WA_DeleteOnClose); |
||||
|
||||
auto EnableOrDisableSave = [this](const QString&) { |
||||
auto isDisabled = ui->edName->text().isEmpty() || ui->edAddress->text().isEmpty(); |
||||
ui->btnSave->setEnabled(!isDisabled); |
||||
}; |
||||
|
||||
connect(ui->edName, &QLineEdit::textChanged, EnableOrDisableSave); |
||||
connect(ui->edAddress, &QLineEdit::textChanged, EnableOrDisableSave); |
||||
|
||||
for (const auto& networkName : networkList) |
||||
ui->edNetwork->addItem(networkName); |
||||
} |
||||
|
||||
AddServer::~AddServer() |
||||
{ |
||||
delete ui; |
||||
} |
||||
|
||||
QString AddServer::name() const |
||||
{ |
||||
return ui->edName->text(); |
||||
} |
||||
|
||||
QString AddServer::address() const |
||||
{ |
||||
return ui->edAddress->text(); |
||||
} |
||||
|
||||
QString AddServer::password() const |
||||
{ |
||||
return ui->edPassword->text(); |
||||
} |
||||
|
||||
QString AddServer::sasl() const |
||||
{ |
||||
return ui->edSASL->text(); |
||||
} |
||||
|
||||
bool AddServer::ssl() const |
||||
{ |
||||
return ui->chkSSL->isChecked(); |
||||
} |
||||
|
||||
bool AddServer::isServer() const |
||||
{ |
||||
return ui->rdServer->isChecked(); |
||||
} |
||||
|
||||
int AddServer::networkIndex() const |
||||
{ |
||||
// 0th index is the "No network" selection, make that into a "-1" index instead... and the rest must also follow.
|
||||
return ui->edNetwork->currentIndex() - 1; |
||||
} |
||||
|
||||
void AddServer::on_btnCancel_clicked() |
||||
{ |
||||
close(); |
||||
} |
||||
|
||||
void AddServer::on_btnSave_clicked() |
||||
{ |
||||
emit saved(); |
||||
close(); |
||||
} |
||||
|
||||
void AddServer::on_rdNetwork_toggled(bool checked) |
||||
{ |
||||
ui->edNetwork->setEnabled(!checked); |
||||
|
||||
// Network servers (child servers) uses their parent server's SASL.
|
||||
// The individual child servers will not have own SASL credentials.
|
||||
ui->edSASL->setEnabled(!checked && ui->edNetwork->currentIndex() == 0 || checked); |
||||
} |
||||
|
||||
void AddServer::on_edNetwork_currentIndexChanged(int index) |
||||
{ |
||||
ui->edSASL->setEnabled(index == 0); |
||||
} |
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef ADDSERVER_H |
||||
#define ADDSERVER_H |
||||
|
||||
#include <QDialog> |
||||
|
||||
namespace Ui { |
||||
class AddServer; |
||||
} |
||||
|
||||
class AddServer : public QDialog |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
explicit AddServer(const QStringList& networkList, QWidget *parent = nullptr); |
||||
~AddServer(); |
||||
|
||||
QString name() const; |
||||
QString address() const; |
||||
QString password() const; |
||||
QString sasl() const; |
||||
bool ssl() const; |
||||
bool isServer() const; |
||||
int networkIndex() const; |
||||
|
||||
signals: |
||||
void saved(); |
||||
|
||||
private slots: |
||||
void on_btnCancel_clicked(); |
||||
void on_btnSave_clicked(); |
||||
void on_rdNetwork_toggled(bool checked); |
||||
void on_edNetwork_currentIndexChanged(int index); |
||||
|
||||
private: |
||||
Ui::AddServer *ui; |
||||
}; |
||||
|
||||
#endif // ADDSERVER_H
|
@ -0,0 +1,183 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<ui version="4.0"> |
||||
<class>AddServer</class> |
||||
<widget class="QDialog" name="AddServer"> |
||||
<property name="geometry"> |
||||
<rect> |
||||
<x>0</x> |
||||
<y>0</y> |
||||
<width>400</width> |
||||
<height>200</height> |
||||
</rect> |
||||
</property> |
||||
<property name="windowTitle"> |
||||
<string>Add server</string> |
||||
</property> |
||||
<property name="windowIcon"> |
||||
<iconset resource="../Resources/resources.qrc"> |
||||
<normaloff>:/Icons/options.png</normaloff>:/Icons/options.png</iconset> |
||||
</property> |
||||
<layout class="QVBoxLayout" name="verticalLayout"> |
||||
<item> |
||||
<layout class="QHBoxLayout" name="horizontalLayout"> |
||||
<item> |
||||
<widget class="QRadioButton" name="rdNetwork"> |
||||
<property name="text"> |
||||
<string>Network</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QRadioButton" name="rdServer"> |
||||
<property name="text"> |
||||
<string>Server</string> |
||||
</property> |
||||
<property name="checked"> |
||||
<bool>true</bool> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QComboBox" name="edNetwork"> |
||||
<property name="sizePolicy"> |
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> |
||||
<horstretch>0</horstretch> |
||||
<verstretch>0</verstretch> |
||||
</sizepolicy> |
||||
</property> |
||||
<property name="placeholderText"> |
||||
<string/> |
||||
</property> |
||||
<item> |
||||
<property name="text"> |
||||
<string><No network></string> |
||||
</property> |
||||
</item> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
<item> |
||||
<layout class="QHBoxLayout" name="horizontalLayout_2"> |
||||
<item> |
||||
<widget class="QLabel" name="label"> |
||||
<property name="text"> |
||||
<string>Name</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QLineEdit" name="edName"/> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
<item> |
||||
<layout class="QHBoxLayout" name="horizontalLayout_3"> |
||||
<item> |
||||
<widget class="QLabel" name="label_2"> |
||||
<property name="text"> |
||||
<string>Address</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QLineEdit" name="edAddress"/> |
||||
</item> |
||||
<item> |
||||
<widget class="QCheckBox" name="chkSSL"> |
||||
<property name="text"> |
||||
<string>SSL</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
<item> |
||||
<layout class="QHBoxLayout" name="horizontalLayout_4"> |
||||
<item> |
||||
<widget class="QLabel" name="label_3"> |
||||
<property name="text"> |
||||
<string>Password</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QLineEdit" name="edPassword"> |
||||
<property name="echoMode"> |
||||
<enum>QLineEdit::Password</enum> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
<item> |
||||
<layout class="QHBoxLayout" name="horizontalLayout_6"> |
||||
<item> |
||||
<widget class="QLabel" name="label_4"> |
||||
<property name="text"> |
||||
<string>SASL credential</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QLineEdit" name="edSASL"> |
||||
<property name="echoMode"> |
||||
<enum>QLineEdit::Password</enum> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
<item> |
||||
<layout class="QHBoxLayout" name="horizontalLayout_5"> |
||||
<item> |
||||
<spacer name="horizontalSpacer"> |
||||
<property name="orientation"> |
||||
<enum>Qt::Horizontal</enum> |
||||
</property> |
||||
<property name="sizeHint" stdset="0"> |
||||
<size> |
||||
<width>40</width> |
||||
<height>20</height> |
||||
</size> |
||||
</property> |
||||
</spacer> |
||||
</item> |
||||
<item> |
||||
<widget class="QPushButton" name="btnCancel"> |
||||
<property name="text"> |
||||
<string>Cancel</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QPushButton" name="btnSave"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
<property name="text"> |
||||
<string>Save</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
</layout> |
||||
</widget> |
||||
<tabstops> |
||||
<tabstop>rdNetwork</tabstop> |
||||
<tabstop>rdServer</tabstop> |
||||
<tabstop>edNetwork</tabstop> |
||||
<tabstop>edName</tabstop> |
||||
<tabstop>edAddress</tabstop> |
||||
<tabstop>chkSSL</tabstop> |
||||
<tabstop>edPassword</tabstop> |
||||
<tabstop>edSASL</tabstop> |
||||
<tabstop>btnCancel</tabstop> |
||||
<tabstop>btnSave</tabstop> |
||||
</tabstops> |
||||
<resources> |
||||
<include location="../Resources/resources.qrc"/> |
||||
</resources> |
||||
<connections/> |
||||
</ui> |
@ -1,313 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ServerEditor.h" |
||||
#include "ui_ServerEditor.h" |
||||
#include <QDebug> |
||||
#include <QMessageBox> |
||||
#include <QInputDialog> |
||||
|
||||
ServerEditor::ServerEditor(ServerModel& model, QWidget* parent) |
||||
: QDialog(parent) |
||||
, ui(new Ui::ServerEditor) |
||||
, smodel(model) |
||||
{ |
||||
ui->setupUi(this); |
||||
addMenu = new QMenu(this); |
||||
addServerAction = addMenu->addAction(tr("Server"), this, &ServerEditor::on_addServerAction_triggered); |
||||
addNetworkAction = addMenu->addAction(tr("Network"), this, &ServerEditor::on_addNetworkAction_triggered); |
||||
ui->btnAdd->setMenu(addMenu); |
||||
ui->serverView->setModel(&smodel); |
||||
ui->serverView->header()->setSectionResizeMode(QHeaderView::Interactive); |
||||
|
||||
QStringList networks = smodel.networkList(); |
||||
ui->edNetwork->addItem(""); |
||||
for (const QString& network : networks) { |
||||
if (network == "NONE") |
||||
continue; |
||||
ui->edNetwork->addItem(network); |
||||
} |
||||
} |
||||
|
||||
ServerEditor::~ServerEditor() |
||||
{ |
||||
delete ui; |
||||
} |
||||
|
||||
void ServerEditor::on_addServerAction_triggered() |
||||
{ |
||||
QString network = "NONE"; |
||||
if (editMode == EditMode::Network) { |
||||
QModelIndex current = ui->serverView->currentIndex(); |
||||
auto spair = smodel.fromIndex(current); |
||||
network = spair.first; |
||||
} |
||||
else if (editMode == EditMode::Server) { |
||||
QModelIndex current = ui->serverView->currentIndex(); |
||||
if (current.parent().isValid()) { |
||||
auto spair = smodel.fromIndex(current.parent()); |
||||
network = spair.first; |
||||
} |
||||
} |
||||
|
||||
QString name; |
||||
QString host; |
||||
for (int i = 1 ;; ++i) { |
||||
name = QStringLiteral("New server %1").arg(i); |
||||
host = QStringLiteral("host%1.name:6667").arg(i); |
||||
QString det = smodel.details(name); |
||||
if (det.isEmpty()) |
||||
break; |
||||
} |
||||
QModelIndex idx = smodel.addServer(name, host, network); |
||||
selectItem(idx); |
||||
} |
||||
|
||||
void ServerEditor::on_addNetworkAction_triggered() |
||||
{ |
||||
QString name; |
||||
QString host; |
||||
for (int i = 1 ;; ++i) { |
||||
name = QStringLiteral("New network %1").arg(i); |
||||
host = QStringLiteral("irc%1.host.name:6667").arg(i); |
||||
QString det = smodel.details("DEFAULT", name); |
||||
if (det.isEmpty()) |
||||
break; |
||||
} |
||||
QModelIndex idx = smodel.addNetwork(name, host); |
||||
ui->edNetwork->addItem(name); |
||||
selectItem(idx); |
||||
} |
||||
|
||||
void ServerEditor::on_btnDel_clicked() |
||||
{ |
||||
if (editMode == EditMode::Off) |
||||
return; |
||||
|
||||
QModelIndex current = ui->serverView->currentIndex(); |
||||
auto spair = smodel.fromIndex(current); |
||||
QString network = spair.first; |
||||
QString name = spair.second; |
||||
|
||||
if (editMode == EditMode::Server) { |
||||
if (QMessageBox::question(this, tr("Delete server"), tr("Do you want to delete the server '%1'?").arg(name)) == QMessageBox::No) |
||||
return; |
||||
smodel.delServer(name, network); |
||||
} |
||||
|
||||
if (editMode == EditMode::Network) { |
||||
name = spair.first; |
||||
auto answer = QMessageBox::question(this, tr("Delete network"), tr("Do you want to delete the network '%1'?\nHitting 'Yes' will keep the servers as orphans.").arg(name), QMessageBox::Yes | QMessageBox::YesAll | QMessageBox::No); |
||||
if (answer == QMessageBox::No) |
||||
return; |
||||
bool keepServers = answer != QMessageBox::YesAll; |
||||
smodel.delNetwork(name, keepServers); |
||||
} |
||||
|
||||
ui->serverView->clearSelection(); |
||||
disableAll(); |
||||
} |
||||
|
||||
void ServerEditor::on_btnShowPassword_toggled(bool checked) |
||||
{ |
||||
ui->edPassword->setEchoMode(checked ? QLineEdit::Normal : QLineEdit::Password); |
||||
} |
||||
|
||||
void ServerEditor::on_btnSave_clicked() |
||||
{ |
||||
if (editMode == EditMode::Off) |
||||
return; |
||||
|
||||
if (ui->edName->text().isEmpty()) { |
||||
QMessageBox::information(this, tr("Field missing"), tr("No name is specified.")); |
||||
return; |
||||
} |
||||
|
||||
if (ui->edHostname->text().isEmpty()) { |
||||
QMessageBox::information(this, tr("Field missing"), tr("No hostname is specified.")); |
||||
return; |
||||
} |
||||
|
||||
if (editMode == EditMode::Server) |
||||
saveServerEdit(); |
||||
|
||||
else if (editMode == EditMode::Network) |
||||
saveNetworkEdit(); |
||||
} |
||||
|
||||
void ServerEditor::enableForServer() |
||||
{ |
||||
enableAll(); |
||||
ui->lbNetwork->show(); |
||||
ui->edNetwork->show(); |
||||
editMode = EditMode::Server; |
||||
} |
||||
|
||||
void ServerEditor::enableForNetwork() |
||||
{ |
||||
enableAll(); |
||||
ui->lbNetwork->hide(); |
||||
ui->edNetwork->hide(); |
||||
editMode = EditMode::Network; |
||||
} |
||||
|
||||
void ServerEditor::enableAll() |
||||
{ |
||||
ui->edName->setEnabled(true); |
||||
ui->edHostname->setEnabled(true); |
||||
ui->edPort->setEnabled(true); |
||||
ui->edPassword->setEnabled(true); |
||||
ui->btnShowPassword->setEnabled(true); |
||||
ui->btnShowPassword->setChecked(false); |
||||
ui->edNetwork->setEnabled(true); |
||||
ui->btnSave->setEnabled(true); |
||||
} |
||||
|
||||
void ServerEditor::disableAll() |
||||
{ |
||||
ui->edName->clear(); |
||||
ui->edHostname->clear(); |
||||
ui->edPort->setValue(6667); |
||||
ui->edPassword->clear(); |
||||
ui->btnShowPassword->setChecked(false); |
||||
ui->edNetwork->clearEditText(); |
||||
|
||||
ui->edName->setEnabled(false); |
||||
ui->edHostname->setEnabled(false); |
||||
ui->edPort->setEnabled(false); |
||||
ui->edPassword->setEnabled(false); |
||||
ui->btnShowPassword->setEnabled(false); |
||||
ui->edNetwork->setEnabled(false); |
||||
ui->btnSave->setEnabled(false); |
||||
ui->lbNetwork->show(); |
||||
ui->edNetwork->show(); |
||||
|
||||
editMode = EditMode::Off; |
||||
} |
||||
|
||||
void ServerEditor::saveNetworkEdit() |
||||
{ |
||||
qDebug() << "Save network"; |
||||
|
||||
QModelIndex current = ui->serverView->currentIndex(); |
||||
auto spair = smodel.fromIndex(current); |
||||
QString network = spair.first; |
||||
|
||||
/* Network name changed */ |
||||
if (network != ui->edName->text()) { |
||||
QString newNetwork = ui->edName->text(); |
||||
if (ui->edNetwork->findText(newNetwork) > -1) { |
||||
QMessageBox::information(this, tr("Duplicate network name"), tr("The specified network name already exist.")); |
||||
return; |
||||
} |
||||
smodel.renameNetwork(network, newNetwork); |
||||
int networkIdx = ui->edNetwork->findText(network); |
||||
ui->edNetwork->setItemText(networkIdx, newNetwork); |
||||
network = newNetwork; |
||||
} |
||||
|
||||
QString details = ui->edHostname->text() + ":" + QString::number(ui->edPort->value()); |
||||
QString password = ui->edPassword->text(); |
||||
if (!password.isEmpty()) |
||||
details += "|" + password; |
||||
smodel.setNetworkServer(network, details); |
||||
} |
||||
|
||||
void ServerEditor::saveServerEdit() |
||||
{ |
||||
qDebug() << "Save server"; |
||||
QModelIndex current = ui->serverView->currentIndex(); |
||||
auto spair = smodel.fromIndex(current); |
||||
|
||||
QString name = ui->edName->text(); |
||||
QString host = ui->edHostname->text(); |
||||
QString port = QString::number(ui->edPort->value()); |
||||
QString password = ui->edPassword->text(); |
||||
QString network = ui->edNetwork->currentText(); |
||||
if (ui->edNetwork->currentIndex() == 0) |
||||
network = "NONE"; |
||||
if (spair.first != network) { |
||||
/* New network */ |
||||
if (network != "NONE" && ui->edNetwork->findText(network) == -1) { |
||||
bool ok = false; |
||||
QString hostname = QInputDialog::getText(this, tr("New network"), tr("Set hostname:port for the new network %1").arg(network), QLineEdit::Normal, "", &ok); |
||||
if (!ok || hostname.isEmpty()) |
||||
return; |
||||
|
||||
smodel.addNetwork(network, hostname); |
||||
ui->edNetwork->addItem(network); |
||||
} |
||||
|
||||
QString details = smodel.details(spair.second, spair.first); |
||||
smodel.delServer(spair.second, spair.first); |
||||
QModelIndex idx = smodel.addServer(spair.second, details, network); |
||||
selectItem(idx); |
||||
} |
||||
|
||||
smodel.setServer(spair.second, host + ":" + port, password, network); |
||||
if (spair.second != name) { |
||||
QString details = smodel.details(spair.second, network); |
||||
smodel.delServer(spair.second, network); |
||||
smodel.resetModel(); |
||||
QModelIndex idx = smodel.addServer(name, details, network); |
||||
selectItem(idx); |
||||
} |
||||
} |
||||
|
||||
void ServerEditor::selectItem(const QModelIndex& index) |
||||
{ |
||||
ui->serverView->clearSelection(); |
||||
ui->serverView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); |
||||
on_serverView_clicked(index); |
||||
} |
||||
|
||||
void ServerEditor::on_serverView_clicked(const QModelIndex &index) |
||||
{ |
||||
if (!index.isValid()) { |
||||
disableAll(); |
||||
return; |
||||
} |
||||
|
||||
auto spair = smodel.fromIndex(index); |
||||
if (spair.first.isEmpty()) { |
||||
disableAll(); |
||||
return; |
||||
} |
||||
|
||||
QString name; |
||||
if (spair.second == "DEFAULT") { |
||||
name = spair.first; |
||||
enableForNetwork(); |
||||
} |
||||
else { |
||||
name = spair.second; |
||||
enableForServer(); |
||||
} |
||||
|
||||
QString details = smodel.details(spair.second, spair.first); |
||||
QString host, port, password; |
||||
// Value format: host:port|password
|
||||
if (details.contains('|')) { |
||||
password = details.split('|')[1]; |
||||
details = details.remove("|"+password); |
||||
} |
||||
if (details.contains(':')) { |
||||
port = details.split(':')[1]; |
||||
details = details.remove(":"+port); |
||||
} |
||||
host = details; |
||||
|
||||
|
||||
ui->edName->setText(name); |
||||
ui->edHostname->setText(host); |
||||
ui->edPort->setValue(port.toInt()); |
||||
ui->edPassword->setText(password); |
||||
int networkUiIndex = ui->edNetwork->findText(spair.first); |
||||
if (networkUiIndex == -1) |
||||
networkUiIndex = 0; |
||||
ui->edNetwork->setCurrentIndex(networkUiIndex); |
||||
} |
@ -1,59 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef SERVEREDITOR_H |
||||
#define SERVEREDITOR_H |
||||
|
||||
#include "ServerModel.h" |
||||
#include <QDialog> |
||||
#include <QMenu> |
||||
|
||||
namespace Ui { |
||||
class ServerEditor; |
||||
} |
||||
|
||||
class ServerEditor : public QDialog |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
explicit ServerEditor(ServerModel& model, QWidget *parent = nullptr); |
||||
~ServerEditor(); |
||||
|
||||
private slots: |
||||
void on_addServerAction_triggered(); |
||||
void on_addNetworkAction_triggered(); |
||||
void on_btnDel_clicked(); |
||||
void on_btnShowPassword_toggled(bool checked); |
||||
void on_btnSave_clicked(); |
||||
void on_serverView_clicked(const QModelIndex &index); |
||||
|
||||
private: |
||||
enum class EditMode { |
||||
Off, |
||||
Server, |
||||
Network |
||||
} editMode = EditMode::Off; |
||||
|
||||
void enableForServer(); |
||||
void enableForNetwork(); |
||||
void enableAll(); |
||||
void disableAll(); |
||||
|
||||
void saveNetworkEdit(); |
||||
void saveServerEdit(); |
||||
|
||||
void selectItem(const QModelIndex& index); |
||||
|
||||
Ui::ServerEditor* ui; |
||||
QMenu* addMenu; |
||||
QAction* addServerAction; |
||||
QAction* addNetworkAction; |
||||
ServerModel& smodel; |
||||
}; |
||||
|
||||
#endif // SERVEREDITOR_H
|
@ -1,251 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<ui version="4.0"> |
||||
<class>ServerEditor</class> |
||||
<widget class="QDialog" name="ServerEditor"> |
||||
<property name="windowModality"> |
||||
<enum>Qt::WindowModal</enum> |
||||
</property> |
||||
<property name="geometry"> |
||||
<rect> |
||||
<x>0</x> |
||||
<y>0</y> |
||||
<width>370</width> |
||||
<height>450</height> |
||||
</rect> |
||||
</property> |
||||
<property name="windowTitle"> |
||||
<string>Server editor</string> |
||||
</property> |
||||
<layout class="QGridLayout" name="gridLayout_2"> |
||||
<item row="0" column="0" rowspan="3" colspan="2"> |
||||
<widget class="QTreeView" name="serverView"> |
||||
<property name="editTriggers"> |
||||
<set>QAbstractItemView::NoEditTriggers</set> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="0" column="2"> |
||||
<widget class="QToolButton" name="btnAdd"> |
||||
<property name="text"> |
||||
<string>+</string> |
||||
</property> |
||||
<property name="popupMode"> |
||||
<enum>QToolButton::InstantPopup</enum> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="1" column="2"> |
||||
<widget class="QToolButton" name="btnDel"> |
||||
<property name="text"> |
||||
<string>-</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="2" column="2"> |
||||
<spacer name="verticalSpacer"> |
||||
<property name="orientation"> |
||||
<enum>Qt::Vertical</enum> |
||||
</property> |
||||
<property name="sizeHint" stdset="0"> |
||||
<size> |
||||
<width>20</width> |
||||
<height>178</height> |
||||
</size> |
||||
</property> |
||||
</spacer> |
||||
</item> |
||||
<item row="3" column="0" colspan="2"> |
||||
<widget class="QFrame" name="frame"> |
||||
<property name="frameShape"> |
||||
<enum>QFrame::StyledPanel</enum> |
||||
</property> |
||||
<property name="frameShadow"> |
||||
<enum>QFrame::Raised</enum> |
||||
</property> |
||||
<layout class="QGridLayout" name="gridLayout"> |
||||
<item row="0" column="0"> |
||||
<widget class="QLabel" name="label_4"> |
||||
<property name="text"> |
||||
<string>Name</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="1" column="0"> |
||||
<widget class="QLabel" name="label"> |
||||
<property name="text"> |
||||
<string>Hostname</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="2" column="0"> |
||||
<widget class="QLabel" name="label_2"> |
||||
<property name="text"> |
||||
<string>Port</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="3" column="0"> |
||||
<widget class="QLabel" name="label_3"> |
||||
<property name="text"> |
||||
<string>Password</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="3" column="1" colspan="2"> |
||||
<layout class="QHBoxLayout" name="horizontalLayout"> |
||||
<item> |
||||
<widget class="QLineEdit" name="edPassword"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
<property name="echoMode"> |
||||
<enum>QLineEdit::Password</enum> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QToolButton" name="btnShowPassword"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
<property name="text"> |
||||
<string>Show</string> |
||||
</property> |
||||
<property name="checkable"> |
||||
<bool>true</bool> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
<item row="4" column="0"> |
||||
<widget class="QLabel" name="lbNetwork"> |
||||
<property name="text"> |
||||
<string>Network</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="5" column="1"> |
||||
<spacer name="horizontalSpacer"> |
||||
<property name="orientation"> |
||||
<enum>Qt::Horizontal</enum> |
||||
</property> |
||||
<property name="sizeHint" stdset="0"> |
||||
<size> |
||||
<width>40</width> |
||||
<height>20</height> |
||||
</size> |
||||
</property> |
||||
</spacer> |
||||
</item> |
||||
<item row="5" column="2"> |
||||
<widget class="QPushButton" name="btnSave"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
<property name="text"> |
||||
<string>Save</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="2" column="1" colspan="2"> |
||||
<widget class="QSpinBox" name="edPort"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
<property name="minimum"> |
||||
<number>1</number> |
||||
</property> |
||||
<property name="maximum"> |
||||
<number>65535</number> |
||||
</property> |
||||
<property name="value"> |
||||
<number>6667</number> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="1" column="1" colspan="2"> |
||||
<widget class="QLineEdit" name="edHostname"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="0" column="1" colspan="2"> |
||||
<widget class="QLineEdit" name="edName"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="4" column="1" colspan="2"> |
||||
<widget class="QComboBox" name="edNetwork"> |
||||
<property name="enabled"> |
||||
<bool>false</bool> |
||||
</property> |
||||
<property name="editable"> |
||||
<bool>true</bool> |
||||
</property> |
||||
<property name="insertPolicy"> |
||||
<enum>QComboBox::InsertAlphabetically</enum> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</widget> |
||||
</item> |
||||
<item row="4" column="0"> |
||||
<spacer name="horizontalSpacer_2"> |
||||
<property name="orientation"> |
||||
<enum>Qt::Horizontal</enum> |
||||
</property> |
||||
<property name="sizeHint" stdset="0"> |
||||
<size> |
||||
<width>230</width> |
||||
<height>20</height> |
||||
</size> |
||||
</property> |
||||
</spacer> |
||||
</item> |
||||
<item row="4" column="1"> |
||||
<widget class="QPushButton" name="btnClose"> |
||||
<property name="text"> |
||||
<string>Close</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</widget> |
||||
<tabstops> |
||||
<tabstop>serverView</tabstop> |
||||
<tabstop>btnAdd</tabstop> |
||||
<tabstop>btnDel</tabstop> |
||||
<tabstop>edName</tabstop> |
||||
<tabstop>edHostname</tabstop> |
||||
<tabstop>edPort</tabstop> |
||||
<tabstop>edPassword</tabstop> |
||||
<tabstop>edNetwork</tabstop> |
||||
<tabstop>btnSave</tabstop> |
||||
<tabstop>btnClose</tabstop> |
||||
<tabstop>btnShowPassword</tabstop> |
||||
</tabstops> |
||||
<resources/> |
||||
<connections> |
||||
<connection> |
||||
<sender>btnClose</sender> |
||||
<signal>clicked()</signal> |
||||
<receiver>ServerEditor</receiver> |
||||
<slot>close()</slot> |
||||
<hints> |
||||
<hint type="sourcelabel"> |
||||
<x>272</x> |
||||
<y>327</y> |
||||
</hint> |
||||
<hint type="destinationlabel"> |
||||
<x>358</x> |
||||
<y>288</y> |
||||
</hint> |
||||
</hints> |
||||
</connection> |
||||
</connections> |
||||
</ui> |
@ -0,0 +1,51 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ServerItem.h" |
||||
|
||||
namespace Key = ServerJsonKey; |
||||
|
||||
ServerItem::ServerItem(const QJsonObject& data, int row, ServerItem* parentItem, bool isNetwork) |
||||
: m_data(data) |
||||
, m_row(row) |
||||
, m_parent(parentItem) |
||||
, m_isNetwork{ isNetwork } |
||||
{} |
||||
|
||||
QString ServerItem::name() const |
||||
{ |
||||
return m_data[Key::Name].toString(); |
||||
} |
||||
|
||||
QString ServerItem::address() const |
||||
{ |
||||
auto host{ m_data[Key::Host].toString() }; |
||||
auto port{ m_data[Key::Port].toInt() }; |
||||
|
||||
if (host.isEmpty()) |
||||
host = "no.host"; |
||||
|
||||
if (port == 0) |
||||
port = ssl() ? 6697 : 6667; |
||||
|
||||
return QStringLiteral("%1:%2").arg(host).arg(port); |
||||
} |
||||
|
||||
QString ServerItem::password() const |
||||
{ |
||||
return m_data[Key::Password].toString(); |
||||
} |
||||
|
||||
QString ServerItem::sasl() const |
||||
{ |
||||
return m_data[Key::SASL].toString(); |
||||
} |
||||
|
||||
bool ServerItem::ssl() const |
||||
{ |
||||
return m_data[Key::SSL].toBool(); |
||||
} |
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef SERVERITEM_H |
||||
#define SERVERITEM_H |
||||
|
||||
#include <QList> |
||||
#include <QString> |
||||
#include <QJsonObject> |
||||
|
||||
namespace ServerJsonKey |
||||
{ |
||||
constexpr auto Servers = "Servers"; |
||||
constexpr auto Networks = "Networks"; |
||||
constexpr auto Name = "Name"; |
||||
constexpr auto Host = "Host"; |
||||
constexpr auto Port = "Port"; |
||||
constexpr auto Password = "Password"; |
||||
constexpr auto SASL = "SASL"; |
||||
constexpr auto SSL = "SSL"; |
||||
} |
||||
|
||||
class ServerItem |
||||
{ |
||||
public: |
||||
ServerItem(const QJsonObject& data, int row, ServerItem* parentItem, bool isNetwork); |
||||
|
||||
QString name() const; |
||||
void setName(const QString& name) { m_data[ServerJsonKey::Name] = name; } |
||||
|
||||
QString address() const; |
||||
void setAddress(const QString& address) |
||||
{ |
||||
auto hostport = address.split(':'); |
||||
|
||||
if (hostport.size() == 1) |
||||
hostport << (ssl() ? "6697" : "6667"); |
||||
|
||||
if (hostport[0].isEmpty()) |
||||
hostport[0] = "server.name"; |
||||
|
||||
m_data[ServerJsonKey::Host] = hostport[0]; |
||||
m_data[ServerJsonKey::Port] = hostport[1].toUShort(); |
||||
} |
||||
|
||||
QString password() const; |
||||
void setPassword(const QString& password) { m_data[ServerJsonKey::Password] = password; } |
||||
|
||||
QString sasl() const; |
||||
void setSasl(const QString& credentials) { m_data[ServerJsonKey::SASL] = credentials; } |
||||
|
||||
bool ssl() const; |
||||
void setSsl(bool enable) { m_data[ServerJsonKey::SSL] = enable; } |
||||
|
||||
ServerItem* parent() const { return m_parent; } |
||||
int row() const { return m_row; } |
||||
void incRow() { ++m_row; } |
||||
void decRow() { --m_row; } |
||||
|
||||
QList<ServerItem>& children() { return m_children; } |
||||
|
||||
bool isNetwork() const { return m_isNetwork; } |
||||
|
||||
private: |
||||
QJsonObject m_data; |
||||
QList<ServerItem> m_children; |
||||
int m_row; |
||||
ServerItem* m_parent; |
||||
bool m_isNetwork; |
||||
}; |
||||
|
||||
#endif // SERVERITEM_H
|
@ -1,133 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ServerMgr.h" |
||||
#include "config.h" |
||||
#include <fmt/format.h> |
||||
|
||||
ServerMgr::ServerMgr(QObject *parent) : |
||||
QObject(parent), |
||||
ini( QString(LOCAL_PATH+"/servers.ini").toStdString() ) |
||||
{ |
||||
} |
||||
|
||||
QStringList ServerMgr::networkList() |
||||
{ |
||||
int count = ini.count(); |
||||
QStringList r; |
||||
|
||||
for (int i = 0; i < count; i++) { |
||||
const auto name = QString::fromStdString( ini.section(i) ); |
||||
r.push_back(name); |
||||
} |
||||
|
||||
return r; |
||||
} |
||||
|
||||
QHash<QString,QString> ServerMgr::serverList(const QString& network) |
||||
{ |
||||
const auto networkStr = network.toStdString(); |
||||
|
||||
int count = ini.count(networkStr); |
||||
QHash<QString,QString> r; |
||||
|
||||
for (int i = 0; i < count; i++) { |
||||
const auto servername = QString::fromStdString( ini.item(networkStr, i) ); |
||||
const auto serverdetails = QString::fromStdString( ini.read(networkStr, i) ); |
||||
r.insert(servername, serverdetails); |
||||
} |
||||
|
||||
return r; |
||||
} |
||||
|
||||
QString ServerMgr::defaultServer(const QString& network) |
||||
{ |
||||
return QString::fromStdString( ini.read(network.toStdString(), "DEFAULT") ); |
||||
} |
||||
|
||||
bool ServerMgr::addNetwork(const QString& name) |
||||
{ |
||||
const auto nameStr = name.toStdString(); |
||||
|
||||
if (nameStr == "NONE" || ini.exist(nameStr)) |
||||
return false; |
||||
|
||||
ini.write(nameStr, "DEFAULT", "server.name"); |
||||
return true; |
||||
} |
||||
|
||||
bool ServerMgr::renameNetwork(const QString& o_name, const QString& n_name) |
||||
{ |
||||
if ((o_name == "NONE") || (n_name == "NONE")) |
||||
return false; |
||||
|
||||
auto err = ini.rename(o_name.toStdString(), n_name.toStdString()); |
||||
return err == IniFile::Error::NoError; |
||||
} |
||||
|
||||
void ServerMgr::delNetwork(const QString& name, bool keep_servers) |
||||
{ |
||||
// If servers=true, we will keep the servers by moving them to the NONE section.
|
||||
|
||||
const auto nameStr = name.toStdString(); |
||||
if (! ini.exist(nameStr)) |
||||
return; |
||||
|
||||
if (keep_servers) { |
||||
int max = ini.count(nameStr); |
||||
for (int i = 0; i < max; i++) { |
||||
auto item = fmt::format("{}_{}", name.toStdString(), ini.item(nameStr, i)); |
||||
auto value = ini.read(nameStr, i); |
||||
|
||||
ini.write("NONE", item, value); |
||||
} |
||||
} |
||||
|
||||
ini.remove(nameStr); |
||||
} |
||||
|
||||
bool ServerMgr::addServer(const QString& name, const QString& host, const QString& pw, const QString& network) |
||||
{ |
||||
QString details; |
||||
|
||||
if (pw.isEmpty()) { |
||||
details = host; |
||||
} |
||||
else { |
||||
details = QString("%1|%2") |
||||
.arg(host) |
||||
.arg(pw); |
||||
} |
||||
|
||||
const auto networkStr = network.toStdString(); |
||||
|
||||
if (!ini.exist(networkStr) && networkStr != "NONE") |
||||
return false; |
||||
|
||||
ini.write(networkStr, name.toStdString(), details.toStdString()); |
||||
return true; |
||||
} |
||||
|
||||
void ServerMgr::delServer(const QString& name, const QString& network) |
||||
{ |
||||
ini.remove(network.toStdString(), name.toStdString()); |
||||
} |
||||
|
||||
bool ServerMgr::hasNetwork(const QString& name) |
||||
{ |
||||
return ini.exist(name.toStdString()); |
||||
} |
||||
|
||||
bool ServerMgr::hasServer(const QString& name, const QString& network) |
||||
{ |
||||
return ini.exist(network.toStdString(), name.toStdString()); |
||||
} |
||||
|
||||
QString ServerMgr::getServerDetails(const QString& name, const QString& network) |
||||
{ |
||||
return QString::fromStdString( ini.read(network.toStdString(), name.toStdString()) ); |
||||
} |
@ -1,66 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef SERVERMGR_H |
||||
#define SERVERMGR_H |
||||
|
||||
#include <QObject> |
||||
#include <QStringList> |
||||
#include <QHash> |
||||
|
||||
#include "IniFile.h" |
||||
|
||||
/**
|
||||
* @brief Manages servers.ini |
||||
* @details |
||||
* This class is from IdealIRC 0.x series and is going to be removed/replaced at any time. |
||||
*/ |
||||
class ServerMgr : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
explicit ServerMgr(QObject *parent = nullptr); |
||||
|
||||
// All networks in a string list (Also counts in the NONE network)
|
||||
QStringList networkList(); |
||||
|
||||
// All servers from a network in a hash map <"name","server:port|passwd">
|
||||
QHash<QString,QString> serverList(const QString& network = "NONE"); |
||||
|
||||
// Return default server of given network (The "NONE" network have no default!) - returns empty if no default server is set.
|
||||
QString defaultServer(const QString& network); |
||||
|
||||
// Add new network to servers.ini - returns false if network exist
|
||||
bool addNetwork(const QString& name); |
||||
|
||||
// Rename a network - returns false if new network name already exist
|
||||
bool renameNetwork(const QString& o_name, const QString& n_name); |
||||
|
||||
// Delete network
|
||||
void delNetwork(const QString& name, bool keep_servers = false); |
||||
|
||||
// Add (or update) a server to network - returns false if network doesn't exsist
|
||||
bool addServer(const QString& name, const QString& host /*host:port*/, const QString& pw = "", const QString& network = "NONE"); |
||||
|
||||
// Delete a server from network
|
||||
void delServer(const QString& name, const QString& network = "NONE"); |
||||
|
||||
// Check of we have the given network name
|
||||
bool hasNetwork(const QString& name); |
||||
|
||||
// Check if we have the given server name inside the network
|
||||
bool hasServer(const QString& name, const QString& network = "NONE"); |
||||
|
||||
// Get server details
|
||||
QString getServerDetails(const QString& name, const QString& network = "NONE"); |
||||
|
||||
private: |
||||
IniFile ini;
|
||||
}; |
||||
|
||||
#endif // SERVERMGR_H
|
@ -1,358 +1,430 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* Copyright (C) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ServerModel.h" |
||||
#include <QHashIterator> |
||||
#include "config.h" |
||||
#include <QJsonArray> |
||||
#include <QFile> |
||||
#include <QDebug> |
||||
#include <QTimer> |
||||
#include <QIcon> |
||||
#include <QFile> |
||||
|
||||
ServerModel::ServerModel(QObject *parent) : |
||||
QStandardItemModel(parent) |
||||
namespace { |
||||
QJsonObject createJsonObject(const QString& name, const QString& address, const QString& password, const QString& sasl, bool isSsl) |
||||
{ |
||||
resetModel(); |
||||
} |
||||
|
||||
QModelIndex ServerModel::indexFromHost(QString hostname) |
||||
{ |
||||
return hostmap.value(hostname, QModelIndex()); |
||||
} |
||||
|
||||
QPair<QString, QString> ServerModel::fromIndex(const QModelIndex& index) |
||||
{ |
||||
/* Locate netmap */ |
||||
{ |
||||
QHashIterator<QString,QModelIndex> it(netmap); |
||||
while (it.hasNext()) { |
||||
const QString& network = it.next().key(); |
||||
const QModelIndex& iidx = it.value(); |
||||
if (index == iidx || index == iidx.siblingAtColumn(1)) |
||||
return { network, "DEFAULT" }; |
||||
|
||||
for (int i = 0 ;; ++i) { |
||||
QModelIndex cidx = iidx.child(i, 0); |
||||
if (!cidx.isValid()) |
||||
break; |
||||
QString name = cidx.data().toString(); |
||||
if (index == cidx || index == cidx.siblingAtColumn(1)) |
||||
return { network, name }; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Locate nonemap */ |
||||
{ |
||||
QHashIterator<QString,QModelIndex> it(hostmap); |
||||
while (it.hasNext()) { |
||||
it.next(); |
||||
const QModelIndex& iidx = it.value(); |
||||
if (index == iidx || index == iidx.siblingAtColumn(1)) |
||||
return { "NONE", iidx.data().toString() }; |
||||
} |
||||
} |
||||
|
||||
return {}; |
||||
} |
||||
namespace Key = ServerJsonKey; |
||||
|
||||
QModelIndex ServerModel::addNetwork(QString name, QString server) |
||||
{ |
||||
QStandardItem *root = invisibleRootItem(); |
||||
auto hostport{ address.split(':') }; |
||||
if (hostport.size() == 1) { |
||||
hostport[0] = "no.host"; |
||||
hostport << (isSsl ? "6697" : "6667"); |
||||
} |
||||
|
||||
QStandardItem *pname = new QStandardItem(QIcon(":/options/gfx/network.png"), name); |
||||
QStandardItem *phost = new QStandardItem(server); |
||||
QList<QStandardItem*> list; |
||||
list << pname << phost; |
||||
const auto host{ hostport[0] }; |
||||
const auto port{ hostport.count() > 1 ? hostport[1].toShort() |
||||
: (isSsl ? 6697 : 6667) }; |
||||
QJsonObject obj; |
||||
|
||||
root->appendRow(list); |
||||
hostmap.insert(server, pname->index()); |
||||
netmap.insert(name, pname->index()); |
||||
obj[Key::Name] = name; |
||||
obj[Key::Host] = host; |
||||
obj[Key::Port] = port; |
||||
obj[Key::SSL] = isSsl; |
||||
obj[Key::Password] = password; |
||||
|
||||
if (smgr.addNetwork(name)) |
||||
smgr.addServer("DEFAULT", server, "", name); |
||||
if (!sasl.isEmpty()) |
||||
obj[Key::SASL] = sasl; |
||||
|
||||
return pname->index(); |
||||
return obj; |
||||
} |
||||
} |
||||
|
||||
void ServerModel::setNetworkServer(QString name, QString server) |
||||
ServerModel::ServerModel(QObject* parent) : |
||||
QAbstractItemModel(parent) |
||||
{ |
||||
QModelIndex current = netmap.value(name); |
||||
int row = current.row(); |
||||
QModelIndex serverIndex = index(row, 1, current.parent()); |
||||
|
||||
QStandardItem *item = itemFromIndex(serverIndex); |
||||
item->setText(server); |
||||
smgr.addServer("DEFAULT", server, "", name); |
||||
loadFromFile(); |
||||
} |
||||
|
||||
void ServerModel::renameNetwork(QString name, QString newname) |
||||
bool ServerModel::saveToFile() |
||||
{ |
||||
QModelIndex current = netmap.value(name); |
||||
int row = current.row(); |
||||
QModelIndex nameIndex = index(row, 0, current.parent()); |
||||
namespace Key = ServerJsonKey; |
||||
|
||||
QJsonArray servers, networks; |
||||
for (auto& item : m_items) { |
||||
if (item.isNetwork()) { |
||||
QJsonArray networkServers; |
||||
for (auto& child : item.children()) { |
||||
QJsonObject server{ createJsonObject(child.name(), child.address(), child.password(), "", child.ssl()) }; |
||||
networkServers << server; |
||||
} |
||||
|
||||
QJsonObject network{ createJsonObject(item.name(), item.address(), item.password(), item.sasl(), item.ssl()) }; |
||||
network[Key::Servers] = networkServers; |
||||
networks << network; |
||||
} |
||||
else { |
||||
QJsonObject server{ createJsonObject(item.name(), item.address(), item.password(), item.sasl(), item.ssl()) }; |
||||
servers << server; |
||||
} |
||||
} |
||||
|
||||
QJsonObject root; |
||||
root[Key::Servers] = servers; |
||||
root[Key::Networks] = networks; |
||||
|
||||
QJsonDocument doc(root); |
||||
|
||||
QStandardItem *item = itemFromIndex(nameIndex); |
||||
item->setText(newname); |
||||
const auto path{ QStringLiteral("%1/servers.json").arg(LOCAL_PATH) }; |
||||
QFile f{ path }; |
||||
if (!f.open(QIODevice::WriteOnly)) |
||||
return false; |
||||
|
||||
netmap.remove(name); |
||||
netmap.insert(newname, current); |
||||
smgr.renameNetwork(name, newname); |
||||
f.write(doc.toJson(QJsonDocument::Indented)); |
||||
f.flush(); |
||||
f.close(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void ServerModel::delNetwork(QString name, bool keepServers) |
||||
void ServerModel::reloadModel() |
||||
{ |
||||
smgr.delNetwork(name, keepServers); |
||||
resetModel(); |
||||
beginResetModel(); |
||||
m_items.clear(); |
||||
loadFromFile(); |
||||
endResetModel(); |
||||
} |
||||
|
||||
QModelIndex ServerModel::addServer(QString name, QString server, QString network) |
||||
Qt::ItemFlags ServerModel::flags(const QModelIndex& index) const |
||||
{ |
||||
QStandardItem *parent; |
||||
|
||||
if (network.length() == 0) |
||||
network = "NONE"; |
||||
/* Don't care about invalid indexes */ |
||||
if (!index.isValid()) |
||||
return Qt::NoItemFlags; |
||||
|
||||
if (network == "NONE") |
||||
parent = invisibleRootItem(); |
||||
else |
||||
parent = itemFromIndex( netmap.value(network) ); |
||||
/* Columns containing widgets for editing */ |
||||
if (index.column() > 1) |
||||
return Qt::ItemIsEnabled | Qt::ItemIsEditable; |
||||
|
||||
QStandardItem *sname = new QStandardItem(QIcon(":/options/gfx/server.png"), name); |
||||
QStandardItem *shost = new QStandardItem(server); |
||||
QList<QStandardItem*> list; |
||||
list << sname << shost; |
||||
/* Directly editable columns */ |
||||
Qt::ItemFlags flags{ Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled }; |
||||
|
||||
parent->appendRow(list); |
||||
hostmap.insert(server, indexFromItem(sname)); |
||||
if (network == "NONE") |
||||
nonemap.insert(name, indexFromItem(sname)); |
||||
const auto* item = static_cast<const ServerItem*>(index.internalPointer()); |
||||
if (!item->isNetwork()) |
||||
flags |= Qt::ItemNeverHasChildren; |
||||
|
||||
smgr.addServer(name, server, "", network); |
||||
|
||||
return indexFromItem(sname); |
||||
return flags; |
||||
} |
||||
|
||||
void ServerModel::setServer(QString name, QString server, QString password, QString network) |
||||
QVariant ServerModel::data(const QModelIndex& index, int role) const |
||||
{ |
||||
QStandardItem *parent; |
||||
if (!index.isValid()) |
||||
return {}; |
||||
|
||||
if (network.length() == 0) |
||||
network = "NONE"; |
||||
if (role == Qt::DisplayRole || role == Qt::EditRole) { |
||||
const auto* item = static_cast<const ServerItem*>(index.internalPointer()); |
||||
|
||||
if (network == "NONE") |
||||
parent = invisibleRootItem(); |
||||
else |
||||
parent = itemFromIndex( netmap.value(network) ); |
||||
if (index.column() == 0) |
||||
return item->name(); |
||||
|
||||
QModelIndex parentIdx = indexFromItem(parent); // Parent index
|
||||
QModelIndex current; // Item's index
|
||||
else if (index.column() == 1) |
||||
return item->address(); |
||||
|
||||
if (network != "NONE") { |
||||
else |
||||
return {}; |
||||
} |
||||
|
||||
for (int r = 0 ;; r++) { |
||||
QModelIndex idx = parentIdx.child(r, 0); |
||||
if (role == Qt::DecorationRole && index.column() == 0) { |
||||
const auto* item = static_cast<const ServerItem*>(index.internalPointer()); |
||||
if (item->isNetwork()) |
||||
return QIcon(":/Icons/network.png"); |
||||
else |
||||
return QIcon(":/Icons/serverwindow.png"); |
||||
} |
||||
|
||||
if (! idx.isValid()) |
||||
return; // No relevant child found, stop.
|
||||
return {}; |
||||
} |
||||
|
||||
if (idx.data().toString() == name) { |
||||
current = idx; |
||||
break; |
||||
} |
||||
} |
||||
QVariant ServerModel::headerData(int section, Qt::Orientation orientation, int role) const |
||||
{ |
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { |
||||
QStringList labels { |
||||
tr("Name"), |
||||
tr("Address"), |
||||
"", |
||||
"", |
||||
"" |
||||
}; |
||||
|
||||
return labels[section]; |
||||
} |
||||
else { |
||||
current = nonemap.value(name); |
||||
return {}; |
||||
} |
||||
} |
||||
|
||||
bool ServerModel::setData(const QModelIndex& index, const QVariant& value, int role) |
||||
{ |
||||
if (!index.isValid() || role != Qt::EditRole) |
||||
return false; |
||||
|
||||
auto* item = static_cast<ServerItem*>(index.internalPointer()); |
||||
|
||||
bool ret{ true }; |
||||
switch (index.column()) { |
||||
case 0: |
||||
if (value.toString().isEmpty()) |
||||
ret = false; |
||||
else |
||||
item->setName(value.toString()); |
||||
break; |
||||
|
||||
case 1: |
||||
if (value.toString().isEmpty()) |
||||
ret = false; |
||||
else |
||||
item->setAddress(value.toString()); |
||||
break; |
||||
|
||||
default: |
||||
ret = false; |
||||
} |
||||
|
||||
int row = current.row(); |
||||
QModelIndex nameIndex = index(row, 0, current.parent()); |
||||
QModelIndex serverIndex = index(row, 1, current.parent()); |
||||
QStandardItem *serverItem = itemFromIndex(serverIndex); |
||||
serverItem->setText(server); |
||||
return ret; |
||||
} |
||||
|
||||
hostmap.insert(server, nameIndex); |
||||
smgr.addServer(name, server, password, network); |
||||
int ServerModel::rowCount(const QModelIndex& parent) const |
||||
{ |
||||
if (!parent.isValid()) |
||||
return m_items.count(); |
||||
else { |
||||
auto* parentItem = static_cast<ServerItem*>(parent.internalPointer()); |
||||
return parentItem->children().count(); |
||||
} |
||||
} |
||||
|
||||
void ServerModel::renameServer(QString name, QString newname, QString network) |
||||
QModelIndex ServerModel::index(int row, int column, const QModelIndex& parent) const |
||||
{ |
||||
QStandardItem *parent; |
||||
if (!hasIndex(row, column, parent)) |
||||
return {}; |
||||
|
||||
if (network.length() == 0) |
||||
network = "NONE"; |
||||
ServerItem* item{}; |
||||
|
||||
if (network == "NONE") |
||||
parent = invisibleRootItem(); |
||||
else |
||||
parent = itemFromIndex( netmap.value(network) ); |
||||
if (!parent.isValid()) |
||||
item = &m_items[row]; |
||||
else { |
||||
auto* parentItem = static_cast<ServerItem*>(parent.internalPointer()); |
||||
item = &parentItem->children()[row]; |
||||
} |
||||
|
||||
QModelIndex parentIdx = indexFromItem(parent); // Parent index
|
||||
QModelIndex current; // Item's index
|
||||
return createIndex(row, column, item); |
||||
} |
||||
|
||||
if (network != "NONE") { |
||||
QModelIndex ServerModel::parent(const QModelIndex& index) const |
||||
{ |
||||
if (!index.isValid()) |
||||
return {}; |
||||
|
||||
for (int r = 0 ;; r++) { |
||||
QModelIndex idx = parentIdx.child(r, 0); |
||||
auto* parentItem = static_cast<ServerItem*>(index.internalPointer())->parent(); |
||||
if (!parentItem) |
||||
return {}; |
||||
|
||||
if (! idx.isValid()) |
||||
return; // No relevant child found, stop.
|
||||
return createIndex(parentItem->row(), 0, parentItem); |
||||
} |
||||
|
||||
if (idx.data().toString() == name) { |
||||
current = idx; |
||||
break; |
||||
} |
||||
} |
||||
void ServerModel::addServer(const QString& name, const QString& address, const QString& password, const QString& sasl, bool isSsl, int networkIdx) |
||||
{ |
||||
QList<ServerItem>* items{}; |
||||
ServerItem* parentNetworkItem{}; |
||||
int pos{}; |
||||
|
||||
QModelIndex modelIdx; |
||||
|
||||
/* Network server */ |
||||
if (networkIdx > -1) { |
||||
modelIdx = networkIndex(networkIdx); |
||||
parentNetworkItem = static_cast<ServerItem*>(modelIdx.internalPointer()); |
||||
items = &(parentNetworkItem->children()); |
||||
pos = items->count(); |
||||
} |
||||
|
||||
/* Non-network server */ |
||||
else { |
||||
current = nonemap.value(name); |
||||
nonemap.remove(name); |
||||
nonemap.insert(newname, current); |
||||
} |
||||
items = &m_items; |
||||
|
||||
int row = current.row(); |
||||
QModelIndex serverIndex = index(row, 0, current.parent()); |
||||
QStandardItem *item = itemFromIndex(serverIndex); |
||||
item->setText(newname); |
||||
for (auto& item : m_items) { |
||||
if (item.isNetwork()) |
||||
item.incRow(); // Increment row number for each network, since any non-network server is inserted before these.
|
||||
else |
||||
++pos; // Finds the end position of non-network servers. Add server there (bottom of non-networks; before networks are listed.)
|
||||
} |
||||
} |
||||
|
||||
QString details = smgr.getServerDetails(name, network); |
||||
smgr.delServer(name, network); |
||||
smgr.addServer(name, details, "", network); |
||||
const auto obj{ createJsonObject(name, address, password, sasl, isSsl) }; |
||||
beginInsertRows(modelIdx, pos, pos); |
||||
items->insert(pos, ServerItem(obj, pos, parentNetworkItem, false)); |
||||
endInsertRows(); |
||||
|
||||
emit newEntry( |
||||
createIndex(pos, 2, &((*items)[pos])), // SSL
|
||||
createIndex(pos, 3, &((*items)[pos])), // Password
|
||||
createIndex(pos, 4, &((*items)[pos])) // SASL
|
||||
); |
||||
|
||||
/*
|
||||
* A hack to make new child items appear if parent's expanded. |
||||
* This also "solves" when a new/empty network gets its first entry, the network item (parent) won't get the "expand/collapse" decoration. |
||||
* Doing this should not be necessary, so there is an issue with this ServerModel, somewhere... |
||||
*/ |
||||
QTimer::singleShot(1, [this] { |
||||
auto pos = m_items.size(); |
||||
beginInsertRows(QModelIndex{}, pos, pos); |
||||
m_items << ServerItem({}, pos, nullptr, false); |
||||
endInsertRows(); |
||||
|
||||
QTimer::singleShot(1, [this] { |
||||
auto pos = m_items.size() - 1; |
||||
beginRemoveRows(QModelIndex{}, pos, pos); |
||||
m_items.removeLast(); |
||||
endRemoveRows(); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
void ServerModel::delServer(QString name, QString network) |
||||
void ServerModel::addNetwork(const QString& name, const QString& address, const QString& password, const QString& sasl, bool isSsl) |
||||
{ |
||||
QStandardItem *parent; |
||||
const auto obj{ createJsonObject(name, address, password, sasl, isSsl) }; |
||||
|
||||
const auto idx{ m_items.count() }; |
||||
beginInsertRows(QModelIndex{}, idx, idx); |
||||
m_items << ServerItem(obj, idx, nullptr, true); |
||||
endInsertRows(); |
||||
|
||||
emit newEntry( |
||||
createIndex(idx, 2, &(m_items.back())), // SSL
|
||||
createIndex(idx, 3, &(m_items.back())), // Password
|
||||
createIndex(idx, 4, &(m_items.back())) // SASL
|
||||
); |
||||
} |
||||
|
||||
if (network.length() == 0) |
||||
network = "NONE"; |
||||
void ServerModel::deleteEntry(const QModelIndex& index) |
||||
{ |
||||
auto* item = static_cast<ServerItem*>(index.internalPointer()); |
||||
auto* parent = item->parent(); |
||||
QList<ServerItem>* items{}; |
||||
|
||||
if (network == "NONE") |
||||
parent = invisibleRootItem(); |
||||
if (parent == nullptr) |
||||
items = &m_items; |
||||
else |
||||
parent = itemFromIndex( netmap.value(network) ); |
||||
items = &(parent->children()); |
||||
|
||||
QModelIndex parentIdx = indexFromItem(parent); // Parent index
|
||||
QModelIndex current; // Item's index
|
||||
beginRemoveRows(index.parent(), index.row(), index.row()); |
||||
|
||||
if (network != "NONE") { |
||||
items->removeAt(item->row()); |
||||
for (int i = item->row(); i < items->count(); ++i) |
||||
(*items)[i].decRow(); |
||||
|
||||
for (int r = 0 ;; r++) { |
||||
QModelIndex idx = parentIdx.child(r, 0); |
||||
endRemoveRows(); |
||||
} |
||||
|
||||
if (! idx.isValid()) |
||||
return; // No relevant child found, stop.
|
||||
QStringList ServerModel::getNetworks() const |
||||
{ |
||||
QStringList networks; |
||||
|
||||
for (const auto& item : m_items) { |
||||
if (item.isNetwork()) |
||||
networks << item.name(); |
||||
} |
||||
|
||||
if (idx.data().toString() == name) { |
||||
current = idx; |
||||
break; |
||||
return networks; |
||||
} |
||||
|
||||
QList<QModelIndex> ServerModel::getEditorColumns() |
||||
{ |
||||
QList<QModelIndex> indexList; |
||||
|
||||
for (auto& topItem : m_items) { |
||||
indexList << createIndex(topItem.row(), 2, &topItem); |
||||
indexList << createIndex(topItem.row(), 3, &topItem); |
||||
indexList << createIndex(topItem.row(), 4, &topItem); |
||||
|
||||
if (topItem.isNetwork()) { |
||||
auto& items = topItem.children(); |
||||
for (auto& item : items) { |
||||
indexList << createIndex(item.row(), 2, &item); |
||||
indexList << createIndex(item.row(), 3, &item); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
current = nonemap.value(name); |
||||
nonemap.remove(name); |
||||
} |
||||
|
||||
|
||||
int row = current.row(); |
||||
removeRow(row, current.parent()); |
||||
smgr.delServer(name, network); |
||||
return indexList; |
||||
} |
||||
|
||||
void ServerModel::resetModel() |
||||
QModelIndex ServerModel::networkIndex(int row, int col) |
||||
{ |
||||
clear(); |
||||
|
||||
QStandardItem *root = invisibleRootItem(); |
||||
|
||||
QStandardItem *i = new QStandardItem(); |
||||
QStringList l; |
||||
l << tr("Name") << tr("Host"); |
||||
setColumnCount(2); |
||||
setHorizontalHeaderItem(0, i); |
||||
setHorizontalHeaderLabels(l); |
||||
|
||||
hostmap.clear(); |
||||
netmap.clear(); |
||||
nonemap.clear(); |
||||
|
||||
QStringList netlist = smgr.networkList(); |
||||
|
||||
if (netlist.contains("NONE")) { // "None" network is a section with servers not assigned to a network.
|
||||
QHash<QString,QString> sl = smgr.serverList("NONE"); |
||||
QHashIterator<QString,QString> i(sl); |
||||
while (i.hasNext()) { |
||||
i.next(); |
||||
// Key: Server name
|
||||
// Value: host:port|pass
|
||||
QString name = i.key(); |
||||
QString detail = i.value(); |
||||
|
||||
QString host; // hostname with port, e.g. irc.network.org:6667
|
||||
host = detail.split('|')[0]; |
||||
|
||||
QStandardItem *itemname = new QStandardItem(QIcon(":/options/gfx/server.png"), name); |
||||
QStandardItem *itemhost = new QStandardItem(host); |
||||
QList<QStandardItem*> list; |
||||
list << itemname << itemhost; |
||||
|
||||
root->appendRow(list); |
||||
hostmap.insert(host, indexFromItem(itemname)); |
||||
nonemap.insert(name, indexFromItem(itemname)); |
||||
|
||||
} |
||||
} |
||||
|
||||
for (int i = 0; i <= netlist.count()-1; ++i) { |
||||
|
||||
if (netlist[i] == "NONE") |
||||
continue; // The "None" network already taken care of - ignore.
|
||||
|
||||
QString data = smgr.defaultServer(netlist[i]); |
||||
QString host = data.split('|')[0]; |
||||
|
||||
QStandardItem *pname = new QStandardItem(QIcon(":/options/gfx/network.png"), netlist[i]); // parent name
|
||||
QStandardItem *phost = new QStandardItem(host); // parent host
|
||||
QList<QStandardItem*> list; |
||||
list << pname << phost; |
||||
|
||||
root->appendRow(list); |
||||
hostmap.insert(host, pname->index()); |
||||
netmap.insert(netlist[i], pname->index()); |
||||
|
||||
QHash<QString,QString> sl = smgr.serverList(netlist[i]); |
||||
QHashIterator<QString,QString> sli(sl); |
||||
while (sli.hasNext()) { |
||||
sli.next(); |
||||
// Key: Server name
|
||||
// Value: host:port|pass
|
||||
QString name = sli.key(); |
||||
if (name == "DEFAULT") |
||||
continue; // The default value already taken care of, it's the address of parent item.
|
||||
QString detail = sli.value(); |
||||
QString host; // hostname with port, e.g. irc.network.org:6667
|
||||
host = detail.split('|')[0]; |
||||
|
||||
QStandardItem *itemname = new QStandardItem(QIcon(":/options/gfx/server.png"), name); // parent name
|
||||
QStandardItem *itemhost = new QStandardItem(host); // parent host
|
||||
QList<QStandardItem*> list; |
||||
list << itemname << itemhost; |
||||
|
||||
pname->appendRow(list); |
||||
hostmap.insert(host, indexFromItem(itemname)); |
||||
} |
||||
} |
||||
int rc{ 0 }; |
||||
for (auto& item : m_items) { |
||||
if (!item.isNetwork()) |
||||
continue; |
||||
|
||||
if (rc == row) |
||||
return createIndex(row, col, &item); |
||||
else |
||||
++rc; |
||||
} |
||||
|
||||
return {}; |
||||
} |
||||
|
||||
QStringList ServerModel::networkList() |
||||
void ServerModel::createItems(const QJsonObject& json) |
||||
{ |
||||
return smgr.networkList(); |
||||
namespace Key = ServerJsonKey; |
||||
|
||||
const auto servers = json[Key::Servers].toArray(); |
||||
const auto networks = json[Key::Networks].toArray(); |
||||
|
||||
int rootRow{ 0 }; |
||||
|
||||
for (const auto& server : servers) { |
||||
m_items << ServerItem(server.toObject(), rootRow++, nullptr, false); |
||||
} |
||||
|
||||
for (const auto& network : networks) { |
||||
const auto networkObj = network.toObject(); |
||||
const auto childServers = networkObj[Key::Servers].toArray(); |
||||
|
||||
m_items << ServerItem(networkObj, rootRow++, nullptr, true); |
||||
auto& networkItem = m_items.back(); |
||||
|
||||
int childRow{ 0 }; |
||||
for (const auto& cs : childServers) { |
||||
auto& networkServers = networkItem.children(); |
||||
networkServers << ServerItem(cs.toObject(), childRow++, &networkItem, false); |
||||
} |
||||
} |
||||
} |
||||
|
||||
QString ServerModel::details(QString name, QString network) |
||||
void ServerModel::loadFromFile() |
||||
{ |
||||
return smgr.getServerDetails(name, network); |
||||
QJsonDocument jsondoc; |
||||
|
||||
const auto path{ QStringLiteral("%1/servers.json").arg(LOCAL_PATH) }; |
||||
QFile f{ path }; |
||||
if (f.open(QIODevice::ReadOnly)) { |
||||
const auto jsonData{ f.readAll() }; |
||||
qDebug() << "Read" << jsonData.size() << "bytes from" << path; |
||||
jsondoc = QJsonDocument::fromJson(jsonData); |
||||
|
||||
f.close(); |
||||
|
||||
if (!jsondoc.isObject()) |
||||
qWarning() << "Parse error for servers.json"; |
||||
else |
||||
createItems(jsondoc.object()); |
||||
} |
||||
else |
||||
qWarning() << "Unable to open servers.json:" << path; |
||||
} |
||||
|
||||
|
@ -0,0 +1,105 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ServerOptionsDelegate.h" |
||||
#include "ServerItem.h" |
||||
#include <QInputDialog> |
||||
#include <QPushButton> |
||||
#include <QDebug> |
||||
|
||||
ServerOptionsDelegate::ServerOptionsDelegate(QObject* parent) |
||||
: QStyledItemDelegate(parent) |
||||
{} |
||||
|
||||
QWidget* ServerOptionsDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const |
||||
{ |
||||
if (!index.isValid()) |
||||
return nullptr; |
||||
|
||||
if (index.column() == 2) { |
||||
auto* btn = new QPushButton(tr("SSL"), parent); |
||||
btn->setCheckable(true); |
||||
return btn; |
||||
} |
||||
|
||||
else if (index.column() == 3) { |
||||
auto* item = static_cast<ServerItem*>(index.internalPointer()); |
||||
auto* btn = new QPushButton(tr("Password"), parent); |
||||
connect(btn, &QPushButton::pressed, |
||||
[item, parent] { |
||||
auto password = QInputDialog::getText( |
||||
parent, |
||||
tr("Enter password"), |
||||
tr("Password for %1:").arg(item->name()), |
||||
QLineEdit::Password, |
||||
item->password() |
||||
); |
||||
|
||||
item->setPassword(password); |
||||
}); |
||||
|
||||
return btn; |
||||
} |
||||
|
||||
else if (index.column() == 4) { |
||||
auto* item = static_cast<ServerItem*>(index.internalPointer()); |
||||
if (item->parent()) // Only items with a parent are network servers / child servers. No SASL for them.
|
||||
return nullptr; |
||||
|
||||
auto* btn = new QPushButton(tr("SASL"), parent); |
||||
connect(btn, &QPushButton::pressed, |
||||
[item, parent] { |
||||
auto password = QInputDialog::getText( |
||||
parent, |
||||
tr("SASL credentials"), |
||||
tr("SASL credentials for %1:").arg(item->name()), |
||||
QLineEdit::Password, |
||||
item->sasl() |
||||
); |
||||
|
||||
item->setSasl(password); |
||||
}); |
||||
|
||||
return btn; |
||||
} |
||||
|
||||
else { |
||||
return nullptr; |
||||
} |
||||
} |
||||
|
||||
void ServerOptionsDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const |
||||
{ |
||||
const auto* item = static_cast<const ServerItem*>(index.internalPointer()); |
||||
|
||||
if (index.column() == 2) { |
||||
auto* btn = qobject_cast<QPushButton*>(editor); |
||||
if (btn) |
||||
btn->setChecked(item->ssl()); |
||||
else |
||||
qCritical() << "SSL button is not a QPushButton?!"; |
||||
} |
||||
|
||||
} |
||||
|
||||
void ServerOptionsDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const |
||||
{ |
||||
auto* item = static_cast<ServerItem*>(index.internalPointer()); |
||||
|
||||
if (index.column() == 2) { |
||||
auto* btn = qobject_cast<QPushButton*>(editor); |
||||
if (btn) |
||||
item->setSsl(btn->isChecked()); |
||||
else |
||||
qCritical() << "SSL button is not a QPushButton?!"; |
||||
} |
||||
} |
||||
|
||||
void ServerOptionsDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& /*index*/) const |
||||
{ |
||||
editor->setGeometry(option.rect); |
||||
} |
@ -0,0 +1,26 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef SERVEROPTIONSDELEGATE_H |
||||
#define SERVEROPTIONSDELEGATE_H |
||||
|
||||
#include <QStyledItemDelegate> |
||||
|
||||
class ServerOptionsDelegate : public QStyledItemDelegate |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
explicit ServerOptionsDelegate(QObject* parent = nullptr); |
||||
|
||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; |
||||
void setEditorData(QWidget* editor, const QModelIndex& index) const override; |
||||
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; |
||||
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override; |
||||
}; |
||||
|
||||
#endif // SERVEROPTIONSDELEGATE_H
|
@ -1,125 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ServerItem.h" |
||||
#include <QDebug> |
||||
|
||||
ServerItem::ServerItem() |
||||
: m_type(Type::Root) |
||||
{} |
||||
|
||||
ServerItem::ServerItem(ServerItem* parentItem, const QString& serverName, const QString& host, const quint16 port, const QString& password) |
||||
: m_type(Type::Server) |
||||
, m_serverName(serverName) |
||||
, m_host(host) |
||||
, m_port(port) |
||||
, m_password(password) |
||||
, m_parent(parentItem) |
||||
{} |
||||
|
||||
ServerItem::ServerItem(const QString& networkName, const QString& host, const quint16 port, const QString& password) |
||||
: m_type(Type::Network) |
||||
, m_networkName(networkName) |
||||
, m_host(host) |
||||
, m_port(port) |
||||
, m_password(password) |
||||
{} |
||||
|
||||
ServerItem::~ServerItem() |
||||
{ |
||||
qDeleteAll(m_children); |
||||
} |
||||
|
||||
ServerItem::Type ServerItem::getType() const |
||||
{ |
||||
return m_type; |
||||
} |
||||
|
||||
const QString& ServerItem::getNetworkName() const |
||||
{ |
||||
return m_networkName; |
||||
} |
||||
|
||||
const QString& ServerItem::getServerName() const |
||||
{ |
||||
return m_serverName; |
||||
} |
||||
|
||||
const QString& ServerItem::getHost() const |
||||
{ |
||||
return m_host; |
||||
} |
||||
|
||||
quint16 ServerItem::getPort() const |
||||
{ |
||||
return m_port; |
||||
} |
||||
|
||||
const QString& ServerItem::getPassword() const |
||||
{ |
||||
return m_password; |
||||
} |
||||
|
||||
ServerItem*ServerItem::getParentItem() const |
||||
{ |
||||
return m_parent; |
||||
} |
||||
|
||||
bool ServerItem::isOrphan() const |
||||
{ |
||||
return m_parent == nullptr; |
||||
} |
||||
|
||||
bool ServerItem::addChild(ServerItem* child) |
||||
{ |
||||
if (m_type == Type::Server) { |
||||
qWarning() << "Tried to add a child item on a server entry!"; |
||||
return false; |
||||
} |
||||
m_children.push_back(child); |
||||
return true; |
||||
} |
||||
|
||||
bool ServerItem::delChild(ServerItem* child) |
||||
{ |
||||
if (m_type == Type::Server) { |
||||
qWarning() << "Tried to delete a child item on a server entry!"; |
||||
return false; |
||||
} |
||||
m_children.removeOne(child); |
||||
return true; |
||||
} |
||||
|
||||
ServerItem* ServerItem::getChild(int row) const |
||||
{ |
||||
if (m_type == Type::Server) { |
||||
qWarning() << "Tried to get a child item on a server entry!"; |
||||
return nullptr; |
||||
} |
||||
|
||||
if (row >= m_children.count()) { |
||||
qWarning() << "Tried to get child from row" << row << "- but it's out of index. Network:" << m_networkName; |
||||
return nullptr; |
||||
} |
||||
|
||||
return m_children[row]; |
||||
} |
||||
|
||||
int ServerItem::childCount() const |
||||
{ |
||||
return m_children.count(); |
||||
} |
||||
|
||||
int ServerItem::childRow(ServerItem* child) const |
||||
{ |
||||
return m_children.indexOf(child); |
||||
} |
||||
|
||||
ServerItem*ServerItem::getParent() const |
||||
{ |
||||
return m_parent; |
||||
} |
@ -1,67 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef SERVERITEM_H |
||||
#define SERVERITEM_H |
||||
|
||||
#include <QString> |
||||
#include <QList> |
||||
|
||||
class ServerItem |
||||
{ |
||||
public: |
||||
enum class Type { |
||||
Root, |
||||
Server, |
||||
Network |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Construct a root item. Should only be constructed once as the "invisible" root item in the tree. |
||||
*/ |
||||
explicit ServerItem(); |
||||
|
||||
/**
|
||||
* @brief Construct a server item. Set parentItem=nullptr for an orphaned server. |
||||
*/ |
||||
ServerItem(ServerItem* parentItem, const QString& serverName, const QString& host, const quint16 port, const QString& password); |
||||
|
||||
/**
|
||||
* @brief Construct a network item. |
||||
*/ |
||||
ServerItem(const QString& networkName, const QString& host, const quint16 port, const QString& password); |
||||
|
||||
~ServerItem(); |
||||
|
||||
Type getType() const; |
||||
const QString& getNetworkName() const; |
||||
const QString& getServerName() const; |
||||
const QString& getHost() const; |
||||
quint16 getPort() const; |
||||
const QString& getPassword() const; |
||||
ServerItem* getParentItem() const; |
||||
bool isOrphan() const; |
||||
|
||||
bool addChild(ServerItem* child); |
||||
bool delChild(ServerItem* child); |
||||
ServerItem* getChild(int row) const; |
||||
int childCount() const; |
||||
int childRow(ServerItem* child) const; |
||||
ServerItem* getParent() const; |
||||
|
||||
private: |
||||
Type m_type; |
||||
QString m_networkName; |
||||
QString m_serverName; |
||||
QString m_host; |
||||
quint16 m_port; |
||||
QString m_password; |
||||
ServerItem* m_parent{ nullptr }; |
||||
QList<ServerItem*> m_children; |
||||
}; |
||||
|
||||
#endif // SERVERITEM_H
|
@ -1,172 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ServerModel.h" |
||||
#include "config.h" |
||||
#include <QDebug> |
||||
|
||||
ServerModel::ServerModel(QObject *parent) |
||||
: QAbstractItemModel(parent) |
||||
{ |
||||
IniFile ini(LOCAL_PATH+"/servers.ini"); |
||||
buildToplevelItem(ini, "NONE"); // Orphaned servers. Always build first.
|
||||
const int sectionCount = ini.countSections(); |
||||
for (int i = 0; i < sectionCount; ++i) { |
||||
QString section = ini.section(i); |
||||
if (section == "NONE") |
||||
continue; |
||||
|
||||
buildToplevelItem(ini, section); |
||||
} |
||||
|
||||
qDebug() << "Built server tree model."; |
||||
} |
||||
|
||||
ServerModel::~ServerModel() |
||||
{ |
||||
qDeleteAll(toplevelItems); |
||||
} |
||||
|
||||
ServerModel::ItemIniValue::ItemIniValue(QString value) |
||||
{ |
||||
if (value.isEmpty()) |
||||
return; |
||||
|
||||
// Value format: host:port|password
|
||||
if (value.contains('|')) { |
||||
password = value.split('|')[1]; |
||||
value = value.remove("|"+password); |
||||
} |
||||
if (value.contains(':')) { |
||||
port = value.split(':')[1]; |
||||
value = value.remove(":"+port); |
||||
} |
||||
host = value; |
||||
} |
||||
|
||||
QModelIndex ServerModel::index(int row, int column, const QModelIndex &parent) const |
||||
{ |
||||
// TEST
|
||||
//if (!hasIndex(row, column, parent))
|
||||
// return QModelIndex();
|
||||
|
||||
ServerItem* item{ nullptr }; |
||||
if (!parent.isValid()) { |
||||
if (row < toplevelItems.count()) |
||||
item = toplevelItems[row]; |
||||
} |
||||
else |
||||
item = static_cast<ServerItem*>(parent.internalPointer()); |
||||
|
||||
if (item) |
||||
return createIndex(row, column, item); |
||||
else |
||||
return QModelIndex(); |
||||
} |
||||
|
||||
QModelIndex ServerModel::parent(const QModelIndex &index) const |
||||
{ |
||||
// FIXME: Implement me!
|
||||
if (!index.isValid()) |
||||
return QModelIndex(); |
||||
|
||||
ServerItem* childItem = static_cast<ServerItem*>(index.internalPointer()); |
||||
if (!childItem->isOrphan()) { |
||||
ServerItem* parentItem = childItem->getParentItem(); |
||||
return createIndex(parentItem->childRow(childItem), 0, parentItem); |
||||
} |
||||
else { |
||||
return QModelIndex(); |
||||
} |
||||
} |
||||
|
||||
int ServerModel::rowCount(const QModelIndex &parent) const |
||||
{ |
||||
if (!parent.isValid()) |
||||
return toplevelItems.count(); |
||||
|
||||
ServerItem* item = static_cast<ServerItem*>(parent.internalPointer()); |
||||
if (!item) |
||||
return 0; |
||||
else |
||||
return item->childCount(); |
||||
} |
||||
|
||||
int ServerModel::columnCount(const QModelIndex&) const |
||||
{ |
||||
return 1; |
||||
} |
||||
|
||||
QVariant ServerModel::data(const QModelIndex &index, int role) const |
||||
{ |
||||
if (!index.isValid()) |
||||
return QVariant(); |
||||
|
||||
// FIXME: Implement me!
|
||||
return "neger"; |
||||
} |
||||
|
||||
bool ServerModel::setData(const QModelIndex &index, const QVariant &value, int role) |
||||
{ |
||||
if (data(index, role) != value) { |
||||
// FIXME: Implement me!
|
||||
emit dataChanged(index, index, QVector<int>() << role); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
Qt::ItemFlags ServerModel::flags(const QModelIndex &index) const |
||||
{ |
||||
if (!index.isValid()) |
||||
return Qt::NoItemFlags; |
||||
|
||||
return Qt::ItemIsEditable; // FIXME: Implement me!
|
||||
} |
||||
|
||||
bool ServerModel::insertRows(int row, int count, const QModelIndex &parent) |
||||
{ |
||||
beginInsertRows(parent, row, row + count - 1); |
||||
// FIXME: Implement me!
|
||||
endInsertRows(); |
||||
} |
||||
|
||||
bool ServerModel::removeRows(int row, int count, const QModelIndex &parent) |
||||
{ |
||||
beginRemoveRows(parent, row, row + count - 1); |
||||
// FIXME: Implement me!
|
||||
endRemoveRows(); |
||||
} |
||||
|
||||
void ServerModel::buildToplevelItem(IniFile& ini, const QString& section) |
||||
{ |
||||
if (!ini.sectionExists(section)) |
||||
return; |
||||
|
||||
ServerItem* parent{ nullptr }; |
||||
if (section != "NONE") { |
||||
ItemIniValue networkDefault(ini.value(section, "DEFAULT")); |
||||
parent = new ServerItem(section, networkDefault.host, |
||||
networkDefault.port.toUShort(), |
||||
networkDefault.password); |
||||
toplevelItems.push_back(parent); |
||||
} |
||||
|
||||
const int itemCount = ini.countItems(section); |
||||
for (int i = 0; i < itemCount; ++i) { |
||||
QString key = ini.key(section, i); |
||||
if (key == "DEFAULT") |
||||
continue; |
||||
|
||||
ItemIniValue val(ini.value(section, key)); |
||||
ServerItem* item = new ServerItem(parent, key, val.host, val.port.toUShort(), val.password); |
||||
if (parent) |
||||
parent->addChild(item); |
||||
else |
||||
toplevelItems.push_back(item); |
||||
} |
||||
} |
@ -1,54 +0,0 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef SERVERMODEL_H |
||||
#define SERVERMODEL_H |
||||
|
||||
#include "ServerItem.h" |
||||
#include "IniFile.h" |
||||
#include <QAbstractItemModel> |
||||
#include <QList> |
||||
|
||||
class ServerModel : public QAbstractItemModel |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
explicit ServerModel(QObject *parent = nullptr); |
||||
~ServerModel() override; |
||||
|
||||
// Basic functionality:
|
||||
QModelIndex index(int row, int column, |
||||
const QModelIndex &parent = QModelIndex()) const override; |
||||
QModelIndex parent(const QModelIndex &index) const override; |
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override; |
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; |
||||
|
||||
// Editable:
|
||||
bool setData(const QModelIndex &index, const QVariant &value, |
||||
int role = Qt::EditRole) override; |
||||
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override; |
||||
|
||||
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; |
||||
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; |
||||
|
||||
private: |
||||
struct ItemIniValue { |
||||
ItemIniValue(QString value); |
||||
QString host; |
||||
QString port; |
||||
QString password; |
||||
}; |
||||
void buildToplevelItem(IniFile& ini, const QString& section); |
||||
QList<ServerItem*> toplevelItems; |
||||
}; |
||||
|
||||
#endif // SERVERMODEL_H
|
@ -0,0 +1,14 @@ |
||||
/*
|
||||
* IdealIRC Core - Internet Relay Chat API |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "../IRCBase.h" |
||||
#include "../IRCBasePriv.h" |
||||
|
||||
void IRCBasePriv::handleUnhandled(const IRCMessage& ircmessage) |
||||
{ |
||||
super.onMsgUnhandled(ircmessage.getSender(), ircmessage.getCommand(), ircmessage.getArgs(), ircmessage.getMessage()); |
||||
} |
@ -0,0 +1,14 @@ |
||||
/*
|
||||
* IdealIRC Core - Internet Relay Chat API |
||||
* Copyright (C) 2021 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "../IRCBase.h" |
||||
#include "../IRCBasePriv.h" |
||||
|
||||
void IRCBasePriv::cmdError(const IRCMessage& ircmessage) |
||||
{ |
||||
super.onMsgError(ircmessage.getMessage()); |
||||
} |
@ -0,0 +1,14 @@ |
||||
/*
|