first
This commit is contained in:
commit
6649fd406e
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
QT += core gui network
|
||||||
|
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
TARGET = FileTrans
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
main.cpp \
|
||||||
|
mainwindow.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
mainwindow.h
|
||||||
|
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
mainwindow.ui
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
res.qrc
|
|
@ -0,0 +1,9 @@
|
||||||
|
# File Trans
|
||||||
|
基于 Qt Socket 的文件传输软件。
|
||||||
|
|
||||||
|
## 界面
|
||||||
|

|
||||||
|
|
||||||
|
## 参考
|
||||||
|
[Qt文服务器](https://github.com/sonichy/HTYServer)
|
||||||
|
[Android手机间使用socket进行文件互传实例](https://www.cnblogs.com/zhujiabin/p/7139644.html)
|
|
@ -0,0 +1,40 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>LOGO</title>
|
||||||
|
<style>
|
||||||
|
canvas { border:1px solid gray; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas" width="512" height="512"></canvas>
|
||||||
|
<script>
|
||||||
|
var canvas = document.getElementById("canvas");
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.lineTo(70, 30);
|
||||||
|
ctx.lineTo(350, 30);
|
||||||
|
ctx.lineTo(440, 130);
|
||||||
|
ctx.lineTo(440, 480);
|
||||||
|
ctx.lineTo(70, 480);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fillStyle = '#05a8ec';
|
||||||
|
ctx.fill();
|
||||||
|
ctx.lineWidth = 5;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.lineTo(350, 30);
|
||||||
|
ctx.lineTo(350, 130);
|
||||||
|
ctx.lineTo(440, 130);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.fillStyle = "black";
|
||||||
|
ctx.font = "500px 方正粗圆简体";
|
||||||
|
var text = "⇅";
|
||||||
|
var x = (canvas.width - ctx.measureText(text).width)/2;
|
||||||
|
ctx.fillText(text, x, 400);
|
||||||
|
</script>
|
||||||
|
<body>
|
||||||
|
</html>
|
|
@ -0,0 +1,4 @@
|
||||||
|
filename=FileTrans
|
||||||
|
s="[Desktop Entry]\nName=文件传输\nComment=A file transfer base on Qt.\nExec=`pwd`/$filename\nIcon=`pwd`/$filename.png\nPath=`pwd`\nTerminal=false\nType=Application\nCategories=Net;"
|
||||||
|
echo -e $s > $filename.desktop
|
||||||
|
cp `pwd`/$filename.desktop ~/.local/share/applications/$filename.desktop
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
qSetMessagePattern("[ %{file}: %{line} ] %{message}");
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
a.setOrganizationName("HTY");
|
||||||
|
a.setApplicationName("FileTrans");
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
return a.exec();
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QMetaEnum>
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
QMainWindow(parent),
|
||||||
|
ui(new Ui::MainWindow),
|
||||||
|
settings(QApplication::organizationName(), QApplication::applicationName())
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
setFixedSize(400, 500);
|
||||||
|
ui->lineEdit_port->setValidator(new QIntValidator(1024, 65535, this));
|
||||||
|
ui->lineEdit_root_dir->setText(settings.value("Directory", QApplication::applicationDirPath()).toString());
|
||||||
|
QAction *action_browser = new QAction;
|
||||||
|
action_browser->setIcon(QIcon::fromTheme("folder"));
|
||||||
|
ui->lineEdit_root_dir->addAction(action_browser, QLineEdit::TrailingPosition);
|
||||||
|
connect(action_browser, &QAction::triggered, [=](){
|
||||||
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Root Directory"),
|
||||||
|
settings.value("Directory", QApplication::applicationDirPath()).toString(),
|
||||||
|
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||||
|
if (dir != "") {
|
||||||
|
ui->lineEdit_root_dir->setText(dir);
|
||||||
|
settings.setValue("Directory", ui->lineEdit_root_dir->text());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
|
||||||
|
foreach (QNetworkInterface interface, list) {
|
||||||
|
QList<QNetworkAddressEntry> entryList = interface.addressEntries();
|
||||||
|
foreach (QNetworkAddressEntry entry, entryList) {
|
||||||
|
if (!entry.ip().toString().contains("::") && entry.ip().toString() != "127.0.0.1") {
|
||||||
|
IP = entry.ip().toString();
|
||||||
|
ui->lineEdit_ip->setText(IP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(ui->pushButton_start, &QPushButton::toggled, [=](bool b){
|
||||||
|
if (b) {
|
||||||
|
state = 0;
|
||||||
|
qint64 port = 9999;
|
||||||
|
while (!tcpServer->listen(QHostAddress::Any, port)) {
|
||||||
|
port--;
|
||||||
|
}
|
||||||
|
ui->label_local->setText(IP + ":" + QString::number(port));
|
||||||
|
ui->lineEdit_port->setText(QString::number(port));
|
||||||
|
ui->textBrowser->clear();
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] 监听:" + IP + ":" + QString::number(port));
|
||||||
|
ui->pushButton_start->setText("Stop");
|
||||||
|
} else {
|
||||||
|
tcpServer->close();
|
||||||
|
ui->pushButton_start->setText("Start");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->pushButton_add, &QPushButton::clicked, [=]{
|
||||||
|
if (path == "")
|
||||||
|
path = ".";
|
||||||
|
QStringList SL_path = QFileDialog::getOpenFileNames(this, "上传文件", path);
|
||||||
|
//qDebug() << SL_path;
|
||||||
|
for (int i=0; i<SL_path.length(); i++) {
|
||||||
|
QString filepath = SL_path.at(i);
|
||||||
|
path = filepath;
|
||||||
|
//qDebug() << filepath;
|
||||||
|
upload(filepath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->pushButton_clear, &QPushButton::clicked, [=]{
|
||||||
|
ui->textBrowser->clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
tcpServer = new QTcpServer(this);
|
||||||
|
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnect()));
|
||||||
|
ui->pushButton_start->toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newConnect()
|
||||||
|
{
|
||||||
|
tcpSocket = tcpServer->nextPendingConnection();
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] " + tcpSocket->peerAddress().toString().replace("::ffff:","") + ":" + QString::number(tcpSocket->peerPort()));
|
||||||
|
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||||
|
|
||||||
|
connect(tcpSocket, &QTcpSocket::disconnected, [=](){
|
||||||
|
qDebug() << state;
|
||||||
|
if (state == 0) {
|
||||||
|
state = 1;
|
||||||
|
} else {
|
||||||
|
file.close();
|
||||||
|
state = 0;
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(tcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), [=](QAbstractSocket::SocketError socketError){
|
||||||
|
qDebug() << socketError;
|
||||||
|
QMetaEnum metaEnum = QMetaEnum::fromType<QAbstractSocket::SocketError>();
|
||||||
|
QString errorString = metaEnum.valueToKey(socketError);
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] " + errorString);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::readyRead()
|
||||||
|
{
|
||||||
|
QByteArray BA = tcpSocket->readAll();
|
||||||
|
//qDebug() << BA ;
|
||||||
|
if (state == 0) {
|
||||||
|
QString filename = BA;
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] " + "接收:" + filename);
|
||||||
|
QString filepath = ui->lineEdit_root_dir->text() + "/" + filename;
|
||||||
|
file.setFileName(filepath);
|
||||||
|
file.open(QIODevice::WriteOnly);
|
||||||
|
} else {
|
||||||
|
file.write(BA);
|
||||||
|
length += BA.length();
|
||||||
|
ui->statusBar->showMessage("接收:" + BS(length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MainWindow::BS(long b)
|
||||||
|
{
|
||||||
|
QString s = "";
|
||||||
|
if (b > 999999999) {
|
||||||
|
s = QString::number(b/(1024*1024*1024.0), 'f', 2) + " GB";
|
||||||
|
} else {
|
||||||
|
if (b > 999999) {
|
||||||
|
s = QString::number(b/(1024*1024.0), 'f', 2) + " MB";
|
||||||
|
} else {
|
||||||
|
if (b > 999) {
|
||||||
|
s = QString::number(b/(1024.0), 'f', 2) + " KB";
|
||||||
|
} else {
|
||||||
|
s = QString::number(b) + " B";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::upload(QString filepath)
|
||||||
|
{
|
||||||
|
qint64 port = ui->lineEdit_port->text().toInt();
|
||||||
|
QTcpSocket *tcpSocket1 = new QTcpSocket(this);
|
||||||
|
connect(tcpSocket1, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), [=](QAbstractSocket::SocketError socketError){
|
||||||
|
qDebug() << socketError;
|
||||||
|
QMetaEnum metaEnum = QMetaEnum::fromType<QAbstractSocket::SocketError>();
|
||||||
|
QString errorString = metaEnum.valueToKey(socketError);
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] " + errorString);
|
||||||
|
});
|
||||||
|
|
||||||
|
tcpSocket1->connectToHost(QHostAddress(ui->lineEdit_ip->text()), port);
|
||||||
|
connect(tcpSocket1, &QTcpSocket::connected, [=](){
|
||||||
|
QString filename = QFileInfo(filepath).fileName();
|
||||||
|
tcpSocket1->write(filename.toUtf8());
|
||||||
|
tcpSocket1->close();
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] 上传:" + filename);
|
||||||
|
});
|
||||||
|
|
||||||
|
QTcpSocket *tcpSocket2 = new QTcpSocket(this);
|
||||||
|
connect(tcpSocket2, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), [=](QAbstractSocket::SocketError socketError){
|
||||||
|
qDebug() << socketError;
|
||||||
|
QMetaEnum metaEnum = QMetaEnum::fromType<QAbstractSocket::SocketError>();
|
||||||
|
QString errorString = metaEnum.valueToKey(socketError);
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] " + errorString);
|
||||||
|
});
|
||||||
|
tcpSocket2->connectToHost(QHostAddress(ui->lineEdit_ip->text()), port);
|
||||||
|
connect(tcpSocket2, &QTcpSocket::connected, [=](){
|
||||||
|
qint64 length1 = 0;
|
||||||
|
QFile file(filepath);
|
||||||
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
|
while (!file.atEnd()) {
|
||||||
|
QByteArray BA = file.read(10240); //每次读取10k数据
|
||||||
|
tcpSocket2->write(BA);
|
||||||
|
//qDebug() << "\b" << file.pos();
|
||||||
|
length1 += 10240;
|
||||||
|
ui->statusBar->showMessage("上传:" + BS(length1) + "/" + BS(file.size()));
|
||||||
|
}
|
||||||
|
ui->textBrowser->append("[" + QDateTime::currentDateTime().toString("HH:mm:ss") + "] " + "上传完成");
|
||||||
|
tcpSocket2->close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
QSettings settings;
|
||||||
|
QString IP, path;
|
||||||
|
QTcpServer *tcpServer;
|
||||||
|
QTcpSocket *tcpSocket;
|
||||||
|
int state;
|
||||||
|
QFile file;
|
||||||
|
qint64 length;
|
||||||
|
QString BS(long b);
|
||||||
|
void upload(QString filepath);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void newConnect();
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,177 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>500</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>文件传输</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/FileTrans.png</normaloff>:/FileTrans.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>IP</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Port</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>根目录</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>本机</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_local">
|
||||||
|
<property name="text">
|
||||||
|
<string>ip:port</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1" colspan="2">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_port">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1" colspan="2">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_root_dir"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_ip"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<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="pushButton_start">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_add">
|
||||||
|
<property name="text">
|
||||||
|
<string>+</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_clear">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="textBrowser"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>27</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>lineEdit_ip</tabstop>
|
||||||
|
<tabstop>lineEdit_port</tabstop>
|
||||||
|
<tabstop>lineEdit_root_dir</tabstop>
|
||||||
|
<tabstop>pushButton_start</tabstop>
|
||||||
|
<tabstop>pushButton_add</tabstop>
|
||||||
|
<tabstop>pushButton_clear</tabstop>
|
||||||
|
<tabstop>textBrowser</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources>
|
||||||
|
<include location="res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
Loading…
Reference in New Issue