diff --git a/tool/0snap/base64helper.jpg b/tool/0snap/base64helper.jpg new file mode 100644 index 0000000..f830a21 Binary files /dev/null and b/tool/0snap/base64helper.jpg differ diff --git a/tool/0snap/comtool.jpg b/tool/0snap/comtool.jpg new file mode 100644 index 0000000..9ae8ca3 Binary files /dev/null and b/tool/0snap/comtool.jpg differ diff --git a/tool/0snap/countcode.jpg b/tool/0snap/countcode.jpg new file mode 100644 index 0000000..a0a188e Binary files /dev/null and b/tool/0snap/countcode.jpg differ diff --git a/tool/0snap/emailtool.jpg b/tool/0snap/emailtool.jpg new file mode 100644 index 0000000..3f3b873 Binary files /dev/null and b/tool/0snap/emailtool.jpg differ diff --git a/tool/0snap/keydemo.jpg b/tool/0snap/keydemo.jpg new file mode 100644 index 0000000..2bba60f Binary files /dev/null and b/tool/0snap/keydemo.jpg differ diff --git a/tool/0snap/keytool.jpg b/tool/0snap/keytool.jpg new file mode 100644 index 0000000..a8cd3c2 Binary files /dev/null and b/tool/0snap/keytool.jpg differ diff --git a/tool/0snap/livedemo.jpg b/tool/0snap/livedemo.jpg new file mode 100644 index 0000000..a4bb1a2 Binary files /dev/null and b/tool/0snap/livedemo.jpg differ diff --git a/tool/0snap/livetool.jpg b/tool/0snap/livetool.jpg new file mode 100644 index 0000000..012cfb2 Binary files /dev/null and b/tool/0snap/livetool.jpg differ diff --git a/tool/0snap/moneytool.jpg b/tool/0snap/moneytool.jpg new file mode 100644 index 0000000..9116703 Binary files /dev/null and b/tool/0snap/moneytool.jpg differ diff --git a/tool/0snap/netserver.jpg b/tool/0snap/netserver.jpg new file mode 100644 index 0000000..55a2ebe Binary files /dev/null and b/tool/0snap/netserver.jpg differ diff --git a/tool/0snap/netserver2.jpg b/tool/0snap/netserver2.jpg new file mode 100644 index 0000000..711ebbc Binary files /dev/null and b/tool/0snap/netserver2.jpg differ diff --git a/tool/0snap/nettool.jpg b/tool/0snap/nettool.jpg new file mode 100644 index 0000000..3cce979 Binary files /dev/null and b/tool/0snap/nettool.jpg differ diff --git a/tool/0snap/pngtool.jpg b/tool/0snap/pngtool.jpg new file mode 100644 index 0000000..af23e53 Binary files /dev/null and b/tool/0snap/pngtool.jpg differ diff --git a/tool/3rd_qextserialport/3rd_qextserialport.pri b/tool/3rd_qextserialport/3rd_qextserialport.pri new file mode 100644 index 0000000..12e8a78 --- /dev/null +++ b/tool/3rd_qextserialport/3rd_qextserialport.pri @@ -0,0 +1,9 @@ +HEADERS += \ + $$PWD/qextserialport.h \ + $$PWD/qextserialport_global.h \ + $$PWD/qextserialport_p.h + +SOURCES += $$PWD/qextserialport.cpp + +win32:SOURCES += $$PWD/qextserialport_win.cpp +unix:SOURCES += $$PWD/qextserialport_unix.cpp diff --git a/tool/3rd_qextserialport/qextserialport.cpp b/tool/3rd_qextserialport/qextserialport.cpp new file mode 100644 index 0000000..66e987c --- /dev/null +++ b/tool/3rd_qextserialport/qextserialport.cpp @@ -0,0 +1,1095 @@ +/**************************************************************************** +** Copyright (c) 2000-2003 Wayne Roth +** Copyright (c) 2004-2007 Stefan Sander +** Copyright (c) 2007 Michal Policht +** Copyright (c) 2008 Brandon Fosdick +** Copyright (c) 2009-2010 Liam Staskawicz +** Copyright (c) 2011 Debao Zhang +** All right reserved. +** Web: http://code.google.com/p/qextserialport/ +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "qextserialport.h" +#include "qextserialport_p.h" +#include +#include +#include +#include + +/*! + \class PortSettings + + \brief The PortSettings class contain port settings + + Structure to contain port settings. + + \code + BaudRateType BaudRate; + DataBitsType DataBits; + ParityType Parity; + StopBitsType StopBits; + FlowType FlowControl; + long Timeout_Millisec; + \endcode +*/ + +QextSerialPortPrivate::QextSerialPortPrivate(QextSerialPort *q) + : lock(QReadWriteLock::Recursive), q_ptr(q) +{ + lastErr = E_NO_ERROR; + settings.BaudRate = BAUD9600; + settings.Parity = PAR_NONE; + settings.FlowControl = FLOW_OFF; + settings.DataBits = DATA_8; + settings.StopBits = STOP_1; + settings.Timeout_Millisec = 10; + settingsDirtyFlags = DFE_ALL; + + platformSpecificInit(); +} + +QextSerialPortPrivate::~QextSerialPortPrivate() +{ + platformSpecificDestruct(); +} + +void QextSerialPortPrivate::setBaudRate(BaudRateType baudRate, bool update) +{ + switch (baudRate) { +#ifdef Q_OS_WIN + + //Windows Special + case BAUD14400: + case BAUD56000: + case BAUD128000: + case BAUD256000: + QESP_PORTABILITY_WARNING() << "QextSerialPort Portability Warning: POSIX does not support baudRate:" << baudRate; +#elif defined(Q_OS_UNIX) + + //Unix Special + case BAUD50: + case BAUD75: + case BAUD134: + case BAUD150: + case BAUD200: + case BAUD1800: +# ifdef B76800 + case BAUD76800: +# endif +# if defined(B230400) && defined(B4000000) + case BAUD230400: + case BAUD460800: + case BAUD500000: + case BAUD576000: + case BAUD921600: + case BAUD1000000: + case BAUD1152000: + case BAUD1500000: + case BAUD2000000: + case BAUD2500000: + case BAUD3000000: + case BAUD3500000: + case BAUD4000000: +# endif + QESP_PORTABILITY_WARNING() << "QextSerialPort Portability Warning: Windows does not support baudRate:" << baudRate; +#endif + + case BAUD110: + case BAUD300: + case BAUD600: + case BAUD1200: + case BAUD2400: + case BAUD4800: + case BAUD9600: + case BAUD19200: + case BAUD38400: + case BAUD57600: + case BAUD115200: +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) + default: +#endif + settings.BaudRate = baudRate; + settingsDirtyFlags |= DFE_BaudRate; + + if (update && q_func()->isOpen()) { + updatePortSettings(); + } + + break; +#if !(defined(Q_OS_WIN) || defined(Q_OS_MAC)) + + default: + QESP_WARNING() << "QextSerialPort does not support baudRate:" << baudRate; +#endif + } +} + +void QextSerialPortPrivate::setParity(ParityType parity, bool update) +{ + switch (parity) { + case PAR_SPACE: + if (settings.DataBits == DATA_8) { +#ifdef Q_OS_WIN + QESP_PORTABILITY_WARNING("QextSerialPort Portability Warning: Space parity with 8 data bits is not supported by POSIX systems."); +#else + QESP_WARNING("Space parity with 8 data bits is not supported by POSIX systems."); +#endif + } + + break; + +#ifdef Q_OS_WIN + + /*mark parity - WINDOWS ONLY*/ + case PAR_MARK: + QESP_PORTABILITY_WARNING("QextSerialPort Portability Warning: Mark parity is not supported by POSIX systems"); + break; +#endif + + case PAR_NONE: + case PAR_EVEN: + case PAR_ODD: + break; + + default: + QESP_WARNING() << "QextSerialPort does not support Parity:" << parity; + } + + settings.Parity = parity; + settingsDirtyFlags |= DFE_Parity; + + if (update && q_func()->isOpen()) { + updatePortSettings(); + } +} + +void QextSerialPortPrivate::setDataBits(DataBitsType dataBits, bool update) +{ + switch (dataBits) { + + case DATA_5: + if (settings.StopBits == STOP_2) { + QESP_WARNING("QextSerialPort: 5 Data bits cannot be used with 2 stop bits."); + } else { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + + break; + + case DATA_6: +#ifdef Q_OS_WIN + if (settings.StopBits == STOP_1_5) { + QESP_WARNING("QextSerialPort: 6 Data bits cannot be used with 1.5 stop bits."); + } else +#endif + { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + + break; + + case DATA_7: +#ifdef Q_OS_WIN + if (settings.StopBits == STOP_1_5) { + QESP_WARNING("QextSerialPort: 7 Data bits cannot be used with 1.5 stop bits."); + } else +#endif + { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + + break; + + case DATA_8: +#ifdef Q_OS_WIN + if (settings.StopBits == STOP_1_5) { + QESP_WARNING("QextSerialPort: 8 Data bits cannot be used with 1.5 stop bits."); + } else +#endif + { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + + break; + + default: + QESP_WARNING() << "QextSerialPort does not support Data bits:" << dataBits; + } + + if (update && q_func()->isOpen()) { + updatePortSettings(); + } +} + +void QextSerialPortPrivate::setStopBits(StopBitsType stopBits, bool update) +{ + switch (stopBits) { + + /*one stop bit*/ + case STOP_1: + settings.StopBits = stopBits; + settingsDirtyFlags |= DFE_StopBits; + break; + +#ifdef Q_OS_WIN + + /*1.5 stop bits*/ + case STOP_1_5: + QESP_PORTABILITY_WARNING("QextSerialPort Portability Warning: 1.5 stop bit operation is not supported by POSIX."); + + if (settings.DataBits != DATA_5) { + QESP_WARNING("QextSerialPort: 1.5 stop bits can only be used with 5 data bits"); + } else { + settings.StopBits = stopBits; + settingsDirtyFlags |= DFE_StopBits; + } + + break; +#endif + + /*two stop bits*/ + case STOP_2: + if (settings.DataBits == DATA_5) { + QESP_WARNING("QextSerialPort: 2 stop bits cannot be used with 5 data bits"); + } else { + settings.StopBits = stopBits; + settingsDirtyFlags |= DFE_StopBits; + } + + break; + + default: + QESP_WARNING() << "QextSerialPort does not support stop bits: " << stopBits; + } + + if (update && q_func()->isOpen()) { + updatePortSettings(); + } +} + +void QextSerialPortPrivate::setFlowControl(FlowType flow, bool update) +{ + settings.FlowControl = flow; + settingsDirtyFlags |= DFE_Flow; + + if (update && q_func()->isOpen()) { + updatePortSettings(); + } +} + +void QextSerialPortPrivate::setTimeout(long millisec, bool update) +{ + settings.Timeout_Millisec = millisec; + settingsDirtyFlags |= DFE_TimeOut; + + if (update && q_func()->isOpen()) { + updatePortSettings(); + } +} + +void QextSerialPortPrivate::setPortSettings(const PortSettings &settings, bool update) +{ + setBaudRate(settings.BaudRate, false); + setDataBits(settings.DataBits, false); + setStopBits(settings.StopBits, false); + setParity(settings.Parity, false); + setFlowControl(settings.FlowControl, false); + setTimeout(settings.Timeout_Millisec, false); + settingsDirtyFlags = DFE_ALL; + + if (update && q_func()->isOpen()) { + updatePortSettings(); + } +} + + +void QextSerialPortPrivate::_q_canRead() +{ + qint64 maxSize = bytesAvailable_sys(); + + if (maxSize > 0) { + char *writePtr = readBuffer.reserve(size_t(maxSize)); + qint64 bytesRead = readData_sys(writePtr, maxSize); + + if (bytesRead < maxSize) { + readBuffer.chop(maxSize - bytesRead); + } + + Q_Q(QextSerialPort); + Q_EMIT q->readyRead(); + } +} + +/*! \class QextSerialPort + + \brief The QextSerialPort class encapsulates a serial port on both POSIX and Windows systems. + + \section1 Usage + QextSerialPort offers both a polling and event driven API. Event driven + is typically easier to use, since you never have to worry about checking + for new data. + + \bold Example + \code + QextSerialPort *port = new QextSerialPort("COM1"); + connect(port, SIGNAL(readyRead()), myClass, SLOT(onDataAvailable())); + port->open(); + + void MyClass::onDataAvailable() + { + QByteArray data = port->readAll(); + processNewData(usbdata); + } + \endcode + + \section1 Compatibility + The user will be notified of errors and possible portability conflicts at run-time + by default. + + For example, if a application has used BAUD1800, when it is runing under unix, you + will get following message. + + \code + QextSerialPort Portability Warning: Windows does not support baudRate:1800 + \endcode + + This behavior can be turned off by defining macro QESP_NO_WARN (to turn off all warnings) + or QESP_NO_PORTABILITY_WARN (to turn off portability warnings) in the project. + + + \bold Author: Stefan Sander, Michal Policht, Brandon Fosdick, Liam Staskawicz, Debao Zhang +*/ + +/*! + \enum QextSerialPort::QueryMode + + This enum type specifies query mode used in a serial port: + + \value Polling + asynchronously read and write + \value EventDriven + synchronously read and write +*/ + +/*! + \fn void QextSerialPort::dsrChanged(bool status) + This signal is emitted whenever dsr line has changed its state. You may + use this signal to check if device is connected. + + \a status true when DSR signal is on, false otherwise. + */ + + +/*! + \fn QueryMode QextSerialPort::queryMode() const + Get query mode. + */ + +/*! + Default constructor. Note that the name of the device used by a QextSerialPort is dependent on + your OS. Possible naming conventions and their associated OS are: + + \code + + OS Constant Used By Naming Convention + ------------- ------------- ------------------------ + Q_OS_WIN Windows COM1, COM2 + Q_OS_IRIX SGI/IRIX /dev/ttyf1, /dev/ttyf2 + Q_OS_HPUX HP-UX /dev/tty1p0, /dev/tty2p0 + Q_OS_SOLARIS SunOS/Slaris /dev/ttya, /dev/ttyb + Q_OS_OSF Digital UNIX /dev/tty01, /dev/tty02 + Q_OS_FREEBSD FreeBSD /dev/ttyd0, /dev/ttyd1 + Q_OS_OPENBSD OpenBSD /dev/tty00, /dev/tty01 + Q_OS_LINUX Linux /dev/ttyS0, /dev/ttyS1 + /dev/ttyS0, /dev/ttyS1 + \endcode + + This constructor assigns the device name to the name of the first port on the specified system. + See the other constructors if you need to open a different port. Default \a mode is EventDriven. + As a subclass of QObject, \a parent can be specified. +*/ + +QextSerialPort::QextSerialPort(QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ +#ifdef Q_OS_WIN + setPortName(QLatin1String("COM1")); + +#elif defined(Q_OS_IRIX) + setPortName(QLatin1String("/dev/ttyf1")); + +#elif defined(Q_OS_HPUX) + setPortName(QLatin1String("/dev/tty1p0")); + +#elif defined(Q_OS_SOLARIS) + setPortName(QLatin1String("/dev/ttya")); + +#elif defined(Q_OS_OSF) //formally DIGITAL UNIX + setPortName(QLatin1String("/dev/tty01")); + +#elif defined(Q_OS_FREEBSD) + setPortName(QLatin1String("/dev/ttyd1")); + +#elif defined(Q_OS_OPENBSD) + setPortName(QLatin1String("/dev/tty00")); + +#else + setPortName(QLatin1String("/dev/ttyS0")); +#endif + setQueryMode(mode); +} + +/*! + Constructs a serial port attached to the port specified by name. + \a name is the name of the device, which is windowsystem-specific, + e.g."COM1" or "/dev/ttyS0". \a mode +*/ +QextSerialPort::QextSerialPort(const QString &name, QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ + setQueryMode(mode); + setPortName(name); +} + +/*! + Constructs a port with default name and specified \a settings. +*/ +QextSerialPort::QextSerialPort(const PortSettings &settings, QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ + Q_D(QextSerialPort); + setQueryMode(mode); + d->setPortSettings(settings); +} + +/*! + Constructs a port with specified \a name , \a mode and \a settings. +*/ +QextSerialPort::QextSerialPort(const QString &name, const PortSettings &settings, QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ + Q_D(QextSerialPort); + setPortName(name); + setQueryMode(mode); + d->setPortSettings(settings); +} + +/*! + Opens a serial port and sets its OpenMode to \a mode. + Note that this function does not specify which device to open. + Returns true if successful; otherwise returns false.This function has no effect + if the port associated with the class is already open. The port is also + configured to the current settings, as stored in the settings structure. +*/ +bool QextSerialPort::open(OpenMode mode) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (mode != QIODevice::NotOpen && !isOpen()) { + d->open_sys(mode); + } + + return isOpen(); +} + + +/*! \reimp + Closes a serial port. This function has no effect if the serial port associated with the class + is not currently open. +*/ +void QextSerialPort::close() +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (isOpen()) { + // Be a good QIODevice and call QIODevice::close() before really close() + // so the aboutToClose() signal is emitted at the proper time + QIODevice::close(); // mark ourselves as closed + d->close_sys(); + d->readBuffer.clear(); + } +} + +/*! + Flushes all pending I/O to the serial port. This function has no effect if the serial port + associated with the class is not currently open. +*/ +void QextSerialPort::flush() +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (isOpen()) { + d->flush_sys(); + } +} + +/*! \reimp + Returns the number of bytes waiting in the port's receive queue. This function will return 0 if + the port is not currently open, or -1 on error. +*/ +qint64 QextSerialPort::bytesAvailable() const +{ + QWriteLocker locker(&d_func()->lock); + + if (isOpen()) { + qint64 bytes = d_func()->bytesAvailable_sys(); + + if (bytes != -1) { + return bytes + d_func()->readBuffer.size() + + QIODevice::bytesAvailable(); + } else { + return -1; + } + } + + return 0; +} + +/*! \reimp + +*/ +bool QextSerialPort::canReadLine() const +{ + QReadLocker locker(&d_func()->lock); + return QIODevice::canReadLine() || d_func()->readBuffer.canReadLine(); +} + +/*! + * Set desired serial communication handling style. You may choose from polling + * or event driven approach. This function does nothing when port is open; to + * apply changes port must be reopened. + * + * In event driven approach read() and write() functions are acting + * asynchronously. They return immediately and the operation is performed in + * the background, so they doesn't freeze the calling thread. + * To determine when operation is finished, QextSerialPort runs separate thread + * and monitors serial port events. Whenever the event occurs, adequate signal + * is emitted. + * + * When polling is set, read() and write() are acting synchronously. Signals are + * not working in this mode and some functions may not be available. The advantage + * of polling is that it generates less overhead due to lack of signals emissions + * and it doesn't start separate thread to monitor events. + * + * Generally event driven approach is more capable and friendly, although some + * applications may need as low overhead as possible and then polling comes. + * + * \a mode query mode. + */ +void QextSerialPort::setQueryMode(QueryMode mode) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (mode != d->queryMode) { + d->queryMode = mode; + } +} + +/*! + Sets the \a name of the device associated with the object, e.g. "COM1", or "/dev/ttyS0". +*/ +void QextSerialPort::setPortName(const QString &name) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + d->port = name; +} + +/*! + Returns the name set by setPortName(). +*/ +QString QextSerialPort::portName() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->port; +} + +QextSerialPort::QueryMode QextSerialPort::queryMode() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->queryMode; +} + +/*! + Reads all available data from the device, and returns it as a QByteArray. + This function has no way of reporting errors; returning an empty QByteArray() + can mean either that no data was currently available for reading, or that an error occurred. +*/ +QByteArray QextSerialPort::readAll() +{ + int avail = this->bytesAvailable(); + return (avail > 0) ? this->read(avail) : QByteArray(); +} + +/*! + Returns the baud rate of the serial port. For a list of possible return values see + the definition of the enum BaudRateType. +*/ +BaudRateType QextSerialPort::baudRate() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.BaudRate; +} + +/*! + Returns the number of data bits used by the port. For a list of possible values returned by + this function, see the definition of the enum DataBitsType. +*/ +DataBitsType QextSerialPort::dataBits() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.DataBits; +} + +/*! + Returns the type of parity used by the port. For a list of possible values returned by + this function, see the definition of the enum ParityType. +*/ +ParityType QextSerialPort::parity() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.Parity; +} + +/*! + Returns the number of stop bits used by the port. For a list of possible return values, see + the definition of the enum StopBitsType. +*/ +StopBitsType QextSerialPort::stopBits() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.StopBits; +} + +/*! + Returns the type of flow control used by the port. For a list of possible values returned + by this function, see the definition of the enum FlowType. +*/ +FlowType QextSerialPort::flowControl() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.FlowControl; +} + +/*! + \reimp + Returns true if device is sequential, otherwise returns false. Serial port is sequential device + so this function always returns true. Check QIODevice::isSequential() documentation for more + information. +*/ +bool QextSerialPort::isSequential() const +{ + return true; +} + +/*! + Return the error number, or 0 if no error occurred. +*/ +ulong QextSerialPort::lastError() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->lastErr; +} + +/*! + Returns the line status as stored by the port function. This function will retrieve the states + of the following lines: DCD, CTS, DSR, and RI. On POSIX systems, the following additional lines + can be monitored: DTR, RTS, Secondary TXD, and Secondary RXD. The value returned is an unsigned + long with specific bits indicating which lines are high. The following constants should be used + to examine the states of individual lines: + + \code + Mask Line + ------ ---- + LS_CTS CTS + LS_DSR DSR + LS_DCD DCD + LS_RI RI + LS_RTS RTS (POSIX only) + LS_DTR DTR (POSIX only) + LS_ST Secondary TXD (POSIX only) + LS_SR Secondary RXD (POSIX only) + \endcode + + This function will return 0 if the port associated with the class is not currently open. +*/ +unsigned long QextSerialPort::lineStatus() +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (isOpen()) { + return d->lineStatus_sys(); + } + + return 0; +} + +/*! + Returns a human-readable description of the last device error that occurred. +*/ +QString QextSerialPort::errorString() +{ + Q_D(QextSerialPort); + QReadLocker locker(&d->lock); + + switch (d->lastErr) { + case E_NO_ERROR: + return tr("No Error has occurred"); + + case E_INVALID_FD: + return tr("Invalid file descriptor (port was not opened correctly)"); + + case E_NO_MEMORY: + return tr("Unable to allocate memory tables (POSIX)"); + + case E_CAUGHT_NON_BLOCKED_SIGNAL: + return tr("Caught a non-blocked signal (POSIX)"); + + case E_PORT_TIMEOUT: + return tr("Operation timed out (POSIX)"); + + case E_INVALID_DEVICE: + return tr("The file opened by the port is not a valid device"); + + case E_BREAK_CONDITION: + return tr("The port detected a break condition"); + + case E_FRAMING_ERROR: + return tr("The port detected a framing error (usually caused by incorrect baud rate settings)"); + + case E_IO_ERROR: + return tr("There was an I/O error while communicating with the port"); + + case E_BUFFER_OVERRUN: + return tr("Character buffer overrun"); + + case E_RECEIVE_OVERFLOW: + return tr("Receive buffer overflow"); + + case E_RECEIVE_PARITY_ERROR: + return tr("The port detected a parity error in the received data"); + + case E_TRANSMIT_OVERFLOW: + return tr("Transmit buffer overflow"); + + case E_READ_FAILED: + return tr("General read operation failure"); + + case E_WRITE_FAILED: + return tr("General write operation failure"); + + case E_FILE_NOT_FOUND: + return tr("The %1 file doesn't exists").arg(this->portName()); + + case E_PERMISSION_DENIED: + return tr("Permission denied"); + + case E_AGAIN: + return tr("Device is already locked"); + + default: + return tr("Unknown error: %1").arg(d->lastErr); + } +} + +/*! + Destructs the QextSerialPort object. +*/ +QextSerialPort::~QextSerialPort() +{ + if (isOpen()) { + close(); + } + + delete d_ptr; +} + +/*! + Sets the flow control used by the port to \a flow. Possible values of flow are: + \code + FLOW_OFF No flow control + FLOW_HARDWARE Hardware (RTS/CTS) flow control + FLOW_XONXOFF Software (XON/XOFF) flow control + \endcode +*/ +void QextSerialPort::setFlowControl(FlowType flow) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (d->settings.FlowControl != flow) { + d->setFlowControl(flow, true); + } +} + +/*! + Sets the parity associated with the serial port to \a parity. The possible values of parity are: + \code + PAR_SPACE Space Parity + PAR_MARK Mark Parity + PAR_NONE No Parity + PAR_EVEN Even Parity + PAR_ODD Odd Parity + \endcode +*/ +void QextSerialPort::setParity(ParityType parity) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (d->settings.Parity != parity) { + d->setParity(parity, true); + } +} + +/*! + Sets the number of data bits used by the serial port to \a dataBits. Possible values of dataBits are: + \code + DATA_5 5 data bits + DATA_6 6 data bits + DATA_7 7 data bits + DATA_8 8 data bits + \endcode + + \bold note: + This function is subject to the following restrictions: + \list + \o 5 data bits cannot be used with 2 stop bits. + \o 1.5 stop bits can only be used with 5 data bits. + \o 8 data bits cannot be used with space parity on POSIX systems. + \endlist + */ +void QextSerialPort::setDataBits(DataBitsType dataBits) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (d->settings.DataBits != dataBits) { + d->setDataBits(dataBits, true); + } +} + +/*! + Sets the number of stop bits used by the serial port to \a stopBits. Possible values of stopBits are: + \code + STOP_1 1 stop bit + STOP_1_5 1.5 stop bits + STOP_2 2 stop bits + \endcode + + \bold note: + This function is subject to the following restrictions: + \list + \o 2 stop bits cannot be used with 5 data bits. + \o 1.5 stop bits cannot be used with 6 or more data bits. + \o POSIX does not support 1.5 stop bits. + \endlist +*/ +void QextSerialPort::setStopBits(StopBitsType stopBits) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (d->settings.StopBits != stopBits) { + d->setStopBits(stopBits, true); + } +} + +/*! + Sets the baud rate of the serial port to \a baudRate. Note that not all rates are applicable on + all platforms. The following table shows translations of the various baud rate + constants on Windows(including NT/2000) and POSIX platforms. Speeds marked with an * + are speeds that are usable on both Windows and POSIX. + \code + + RATE Windows Speed POSIX Speed + ----------- ------------- ----------- + BAUD50 X 50 + BAUD75 X 75 + *BAUD110 110 110 + BAUD134 X 134.5 + BAUD150 X 150 + BAUD200 X 200 + *BAUD300 300 300 + *BAUD600 600 600 + *BAUD1200 1200 1200 + BAUD1800 X 1800 + *BAUD2400 2400 2400 + *BAUD4800 4800 4800 + *BAUD9600 9600 9600 + BAUD14400 14400 X + *BAUD19200 19200 19200 + *BAUD38400 38400 38400 + BAUD56000 56000 X + *BAUD57600 57600 57600 + BAUD76800 X 76800 + *BAUD115200 115200 115200 + BAUD128000 128000 X + BAUD230400 X 230400 + BAUD256000 256000 X + BAUD460800 X 460800 + BAUD500000 X 500000 + BAUD576000 X 576000 + BAUD921600 X 921600 + BAUD1000000 X 1000000 + BAUD1152000 X 1152000 + BAUD1500000 X 1500000 + BAUD2000000 X 2000000 + BAUD2500000 X 2500000 + BAUD3000000 X 3000000 + BAUD3500000 X 3500000 + BAUD4000000 X 4000000 + \endcode +*/ + +void QextSerialPort::setBaudRate(BaudRateType baudRate) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (d->settings.BaudRate != baudRate) { + d->setBaudRate(baudRate, true); + } +} + +/*! + For Unix: + + Sets the read and write timeouts for the port to \a millisec milliseconds. + Note that this is a per-character timeout, i.e. the port will wait this long for each + individual character, not for the whole read operation. This timeout also applies to the + bytesWaiting() function. + + \bold note: + POSIX does not support millisecond-level control for I/O timeout values. Any + timeout set using this function will be set to the next lowest tenth of a second for + the purposes of detecting read or write timeouts. For example a timeout of 550 milliseconds + will be seen by the class as a timeout of 500 milliseconds for the purposes of reading and + writing the port. However millisecond-level control is allowed by the select() system call, + so for example a 550-millisecond timeout will be seen as 550 milliseconds on POSIX systems for + the purpose of detecting available bytes in the read buffer. + + For Windows: + + Sets the read and write timeouts for the port to \a millisec milliseconds. + Setting 0 indicates that timeouts are not used for read nor write operations; + however read() and write() functions will still block. Set -1 to provide + non-blocking behaviour (read() and write() will return immediately). + + \bold note: this function does nothing in event driven mode. +*/ +void QextSerialPort::setTimeout(long millisec) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (d->settings.Timeout_Millisec != millisec) { + d->setTimeout(millisec, true); + } +} + +/*! + Sets DTR line to the requested state (\a set default to high). This function will have no effect if + the port associated with the class is not currently open. +*/ +void QextSerialPort::setDtr(bool set) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (isOpen()) { + d->setDtr_sys(set); + } +} + +/*! + Sets RTS line to the requested state \a set (high by default). + This function will have no effect if + the port associated with the class is not currently open. +*/ +void QextSerialPort::setRts(bool set) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + + if (isOpen()) { + d->setRts_sys(set); + } +} + +/*! \reimp + Reads a block of data from the serial port. This function will read at most maxlen bytes from + the serial port and place them in the buffer pointed to by data. Return value is the number of + bytes actually read, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPort::readData(char *data, qint64 maxSize) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + qint64 bytesFromBuffer = 0; + + if (!d->readBuffer.isEmpty()) { + bytesFromBuffer = d->readBuffer.read(data, maxSize); + + if (bytesFromBuffer == maxSize) { + return bytesFromBuffer; + } + } + + qint64 bytesFromDevice = d->readData_sys(data + bytesFromBuffer, maxSize - bytesFromBuffer); + + if (bytesFromDevice < 0) { + return -1; + } + + return bytesFromBuffer + bytesFromDevice; +} + +/*! \reimp + Writes a block of data to the serial port. This function will write len bytes + from the buffer pointed to by data to the serial port. Return value is the number + of bytes actually written, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPort::writeData(const char *data, qint64 maxSize) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + return d->writeData_sys(data, maxSize); +} + +#include "moc_qextserialport.cpp" diff --git a/tool/3rd_qextserialport/qextserialport.h b/tool/3rd_qextserialport/qextserialport.h new file mode 100644 index 0000000..f60e14a --- /dev/null +++ b/tool/3rd_qextserialport/qextserialport.h @@ -0,0 +1,234 @@ +/**************************************************************************** +** Copyright (c) 2000-2003 Wayne Roth +** Copyright (c) 2004-2007 Stefan Sander +** Copyright (c) 2007 Michal Policht +** Copyright (c) 2008 Brandon Fosdick +** Copyright (c) 2009-2010 Liam Staskawicz +** Copyright (c) 2011 Debao Zhang +** All right reserved. +** Web: http://code.google.com/p/qextserialport/ +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef _QEXTSERIALPORT_H_ +#define _QEXTSERIALPORT_H_ + +#include +#include "qextserialport_global.h" +#ifdef Q_OS_UNIX +#include +#endif +/*line status constants*/ +// ### QESP2.0 move to enum +#define LS_CTS 0x01 +#define LS_DSR 0x02 +#define LS_DCD 0x04 +#define LS_RI 0x08 +#define LS_RTS 0x10 +#define LS_DTR 0x20 +#define LS_ST 0x40 +#define LS_SR 0x80 + +/*error constants*/ +// ### QESP2.0 move to enum +#define E_NO_ERROR 0 +#define E_INVALID_FD 1 +#define E_NO_MEMORY 2 +#define E_CAUGHT_NON_BLOCKED_SIGNAL 3 +#define E_PORT_TIMEOUT 4 +#define E_INVALID_DEVICE 5 +#define E_BREAK_CONDITION 6 +#define E_FRAMING_ERROR 7 +#define E_IO_ERROR 8 +#define E_BUFFER_OVERRUN 9 +#define E_RECEIVE_OVERFLOW 10 +#define E_RECEIVE_PARITY_ERROR 11 +#define E_TRANSMIT_OVERFLOW 12 +#define E_READ_FAILED 13 +#define E_WRITE_FAILED 14 +#define E_FILE_NOT_FOUND 15 +#define E_PERMISSION_DENIED 16 +#define E_AGAIN 17 + +enum BaudRateType { +#if defined(Q_OS_UNIX) || defined(qdoc) + BAUD50 = 50, //POSIX ONLY + BAUD75 = 75, //POSIX ONLY + BAUD134 = 134, //POSIX ONLY + BAUD150 = 150, //POSIX ONLY + BAUD200 = 200, //POSIX ONLY + BAUD1800 = 1800, //POSIX ONLY +# if defined(B76800) || defined(qdoc) + BAUD76800 = 76800, //POSIX ONLY +# endif +# if (defined(B230400) && defined(B4000000)) || defined(qdoc) + BAUD230400 = 230400, //POSIX ONLY + BAUD460800 = 460800, //POSIX ONLY + BAUD500000 = 500000, //POSIX ONLY + BAUD576000 = 576000, //POSIX ONLY + BAUD921600 = 921600, //POSIX ONLY + BAUD1000000 = 1000000, //POSIX ONLY + BAUD1152000 = 1152000, //POSIX ONLY + BAUD1500000 = 1500000, //POSIX ONLY + BAUD2000000 = 2000000, //POSIX ONLY + BAUD2500000 = 2500000, //POSIX ONLY + BAUD3000000 = 3000000, //POSIX ONLY + BAUD3500000 = 3500000, //POSIX ONLY + BAUD4000000 = 4000000, //POSIX ONLY +# endif +#endif //Q_OS_UNIX +#if defined(Q_OS_WIN) || defined(qdoc) + BAUD14400 = 14400, //WINDOWS ONLY + BAUD56000 = 56000, //WINDOWS ONLY + BAUD128000 = 128000, //WINDOWS ONLY + BAUD256000 = 256000, //WINDOWS ONLY +#endif //Q_OS_WIN + BAUD110 = 110, + BAUD300 = 300, + BAUD600 = 600, + BAUD1200 = 1200, + BAUD2400 = 2400, + BAUD4800 = 4800, + BAUD9600 = 9600, + BAUD19200 = 19200, + BAUD38400 = 38400, + BAUD57600 = 57600, + BAUD115200 = 115200 +}; + +enum DataBitsType { + DATA_5 = 5, + DATA_6 = 6, + DATA_7 = 7, + DATA_8 = 8 +}; + +enum ParityType { + PAR_NONE, + PAR_ODD, + PAR_EVEN, +#if defined(Q_OS_WIN) || defined(qdoc) + PAR_MARK, //WINDOWS ONLY +#endif + PAR_SPACE +}; + +enum StopBitsType { + STOP_1, +#if defined(Q_OS_WIN) || defined(qdoc) + STOP_1_5, //WINDOWS ONLY +#endif + STOP_2 +}; + +enum FlowType { + FLOW_OFF, + FLOW_HARDWARE, + FLOW_XONXOFF +}; + +/** + * structure to contain port settings + */ +struct PortSettings { + BaudRateType BaudRate; + DataBitsType DataBits; + ParityType Parity; + StopBitsType StopBits; + FlowType FlowControl; + long Timeout_Millisec; +}; + +class QextSerialPortPrivate; +class QEXTSERIALPORT_EXPORT QextSerialPort: public QIODevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QextSerialPort) + Q_ENUMS(QueryMode) + Q_PROPERTY(QString portName READ portName WRITE setPortName) + Q_PROPERTY(QueryMode queryMode READ queryMode WRITE setQueryMode) +public: + enum QueryMode { + Polling, + EventDriven + }; + + explicit QextSerialPort(QueryMode mode = EventDriven, QObject *parent = 0); + explicit QextSerialPort(const QString &name, QueryMode mode = EventDriven, QObject *parent = 0); + explicit QextSerialPort(const PortSettings &s, QueryMode mode = EventDriven, QObject *parent = 0); + QextSerialPort(const QString &name, const PortSettings &s, QueryMode mode = EventDriven, QObject *parent = 0); + + ~QextSerialPort(); + + QString portName() const; + QueryMode queryMode() const; + BaudRateType baudRate() const; + DataBitsType dataBits() const; + ParityType parity() const; + StopBitsType stopBits() const; + FlowType flowControl() const; + + bool open(OpenMode mode); + bool isSequential() const; + void close(); + void flush(); + qint64 bytesAvailable() const; + bool canReadLine() const; + QByteArray readAll(); + + ulong lastError() const; + + ulong lineStatus(); + QString errorString(); + +public Q_SLOTS: + void setPortName(const QString &name); + void setQueryMode(QueryMode mode); + void setBaudRate(BaudRateType); + void setDataBits(DataBitsType); + void setParity(ParityType); + void setStopBits(StopBitsType); + void setFlowControl(FlowType); + void setTimeout(long); + + void setDtr(bool set = true); + void setRts(bool set = true); + +Q_SIGNALS: + void dsrChanged(bool status); + +protected: + qint64 readData(char *data, qint64 maxSize); + qint64 writeData(const char *data, qint64 maxSize); + +private: + Q_DISABLE_COPY(QextSerialPort) + +#ifdef Q_OS_WIN + Q_PRIVATE_SLOT(d_func(), void _q_onWinEvent(HANDLE)) +#endif + Q_PRIVATE_SLOT(d_func(), void _q_canRead()) + + QextSerialPortPrivate *const d_ptr; +}; + +#endif diff --git a/tool/3rd_qextserialport/qextserialport_global.h b/tool/3rd_qextserialport/qextserialport_global.h new file mode 100644 index 0000000..da91069 --- /dev/null +++ b/tool/3rd_qextserialport/qextserialport_global.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** Copyright (c) 2000-2003 Wayne Roth +** Copyright (c) 2004-2007 Stefan Sander +** Copyright (c) 2007 Michal Policht +** Copyright (c) 2008 Brandon Fosdick +** Copyright (c) 2009-2010 Liam Staskawicz +** Copyright (c) 2011 Debao Zhang +** All right reserved. +** Web: http://code.google.com/p/qextserialport/ +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QEXTSERIALPORT_GLOBAL_H +#define QEXTSERIALPORT_GLOBAL_H + +#include + +#ifdef QEXTSERIALPORT_BUILD_SHARED +# define QEXTSERIALPORT_EXPORT Q_DECL_EXPORT +#elif defined(QEXTSERIALPORT_USING_SHARED) +# define QEXTSERIALPORT_EXPORT Q_DECL_IMPORT +#else +# define QEXTSERIALPORT_EXPORT +#endif + +// ### for compatible with old version. should be removed in QESP 2.0 +#ifdef _TTY_NOWARN_ +# define QESP_NO_WARN +#endif +#ifdef _TTY_NOWARN_PORT_ +# define QESP_NO_PORTABILITY_WARN +#endif + +/*if all warning messages are turned off, flag portability warnings to be turned off as well*/ +#ifdef QESP_NO_WARN +# define QESP_NO_PORTABILITY_WARN +#endif + +/*macros for warning and debug messages*/ +#ifdef QESP_NO_PORTABILITY_WARN +# define QESP_PORTABILITY_WARNING while (false)qWarning +#else +# define QESP_PORTABILITY_WARNING qWarning +#endif /*QESP_NOWARN_PORT*/ + +#ifdef QESP_NO_WARN +# define QESP_WARNING while (false)qWarning +#else +# define QESP_WARNING qWarning +#endif /*QESP_NOWARN*/ + +#endif // QEXTSERIALPORT_GLOBAL_H + diff --git a/tool/3rd_qextserialport/qextserialport_p.h b/tool/3rd_qextserialport/qextserialport_p.h new file mode 100644 index 0000000..d128c65 --- /dev/null +++ b/tool/3rd_qextserialport/qextserialport_p.h @@ -0,0 +1,277 @@ +/**************************************************************************** +** Copyright (c) 2000-2003 Wayne Roth +** Copyright (c) 2004-2007 Stefan Sander +** Copyright (c) 2007 Michal Policht +** Copyright (c) 2008 Brandon Fosdick +** Copyright (c) 2009-2010 Liam Staskawicz +** Copyright (c) 2011 Debao Zhang +** All right reserved. +** Web: http://code.google.com/p/qextserialport/ +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef _QEXTSERIALPORT_P_H_ +#define _QEXTSERIALPORT_P_H_ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QESP API. It exists for the convenience +// of other QESP classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qextserialport.h" +#include +#ifdef Q_OS_UNIX +# include +#elif (defined Q_OS_WIN) +# include +#endif +#include + +// This is QextSerialPort's read buffer, needed by posix system. +// ref: QRingBuffer & QIODevicePrivateLinearBuffer +class QextReadBuffer +{ +public: + inline QextReadBuffer(size_t growth = 4096) + : len(0), first(0), buf(0), capacity(0), basicBlockSize(growth) + { + } + + ~QextReadBuffer() + { + delete buf; + } + + inline void clear() + { + first = buf; + len = 0; + } + + inline int size() const + { + return len; + } + + inline bool isEmpty() const + { + return len == 0; + } + + inline int read(char *target, int size) + { + int r = qMin(size, len); + + if (r == 1) { + *target = *first; + --len; + ++first; + } else { + memcpy(target, first, r); + len -= r; + first += r; + } + + return r; + } + + inline char *reserve(size_t size) + { + if ((first - buf) + len + size > capacity) { + size_t newCapacity = qMax(capacity, basicBlockSize); + + while (newCapacity < len + size) { + newCapacity *= 2; + } + + if (newCapacity > capacity) { + // allocate more space + char *newBuf = new char[newCapacity]; + memmove(newBuf, first, len); + delete buf; + buf = newBuf; + capacity = newCapacity; + } else { + // shift any existing data to make space + memmove(buf, first, len); + } + + first = buf; + } + + char *writePtr = first + len; + len += (int)size; + return writePtr; + } + + inline void chop(int size) + { + if (size >= len) { + clear(); + } else { + len -= size; + } + } + + inline void squeeze() + { + if (first != buf) { + memmove(buf, first, len); + first = buf; + } + + size_t newCapacity = basicBlockSize; + + while (newCapacity < size_t(len)) { + newCapacity *= 2; + } + + if (newCapacity < capacity) { + char *tmp = static_cast(realloc(buf, newCapacity)); + + if (tmp) { + buf = tmp; + capacity = newCapacity; + } + } + } + + inline QByteArray readAll() + { + char *f = first; + int l = len; + clear(); + return QByteArray(f, l); + } + + inline int readLine(char *target, int size) + { + int r = qMin(size, len); + char *eol = static_cast(memchr(first, '\n', r)); + + if (eol) { + r = 1 + (eol - first); + } + + memcpy(target, first, r); + len -= r; + first += r; + return int(r); + } + + inline bool canReadLine() const + { + return memchr(first, '\n', len); + } + +private: + int len; + char *first; + char *buf; + size_t capacity; + size_t basicBlockSize; +}; + +class QWinEventNotifier; +class QReadWriteLock; +class QSocketNotifier; + +class QextSerialPortPrivate +{ + Q_DECLARE_PUBLIC(QextSerialPort) +public: + QextSerialPortPrivate(QextSerialPort *q); + ~QextSerialPortPrivate(); + enum DirtyFlagEnum { + DFE_BaudRate = 0x0001, + DFE_Parity = 0x0002, + DFE_StopBits = 0x0004, + DFE_DataBits = 0x0008, + DFE_Flow = 0x0010, + DFE_TimeOut = 0x0100, + DFE_ALL = 0x0fff, + DFE_Settings_Mask = 0x00ff //without TimeOut + }; + mutable QReadWriteLock lock; + QString port; + PortSettings settings; + QextReadBuffer readBuffer; + int settingsDirtyFlags; + ulong lastErr; + QextSerialPort::QueryMode queryMode; + + // platform specific members +#ifdef Q_OS_UNIX + int fd; + QSocketNotifier *readNotifier; + struct termios currentTermios; + struct termios oldTermios; +#elif (defined Q_OS_WIN) + HANDLE handle; + OVERLAPPED overlap; + COMMCONFIG commConfig; + COMMTIMEOUTS commTimeouts; + QWinEventNotifier *winEventNotifier; + DWORD eventMask; + QList pendingWrites; + QReadWriteLock *bytesToWriteLock; +#endif + + /*fill PortSettings*/ + void setBaudRate(BaudRateType baudRate, bool update = true); + void setDataBits(DataBitsType dataBits, bool update = true); + void setParity(ParityType parity, bool update = true); + void setStopBits(StopBitsType stopbits, bool update = true); + void setFlowControl(FlowType flow, bool update = true); + void setTimeout(long millisec, bool update = true); + void setPortSettings(const PortSettings &settings, bool update = true); + + void platformSpecificDestruct(); + void platformSpecificInit(); + void translateError(ulong error); + void updatePortSettings(); + + qint64 readData_sys(char *data, qint64 maxSize); + qint64 writeData_sys(const char *data, qint64 maxSize); + void setDtr_sys(bool set = true); + void setRts_sys(bool set = true); + bool open_sys(QIODevice::OpenMode mode); + bool close_sys(); + bool flush_sys(); + ulong lineStatus_sys(); + qint64 bytesAvailable_sys() const; + +#ifdef Q_OS_WIN + void _q_onWinEvent(HANDLE h); +#endif + void _q_canRead(); + + QextSerialPort *q_ptr; +}; + +#endif //_QEXTSERIALPORT_P_H_ diff --git a/tool/3rd_qextserialport/qextserialport_unix.cpp b/tool/3rd_qextserialport/qextserialport_unix.cpp new file mode 100644 index 0000000..5a78148 --- /dev/null +++ b/tool/3rd_qextserialport/qextserialport_unix.cpp @@ -0,0 +1,559 @@ +/**************************************************************************** +** Copyright (c) 2000-2003 Wayne Roth +** Copyright (c) 2004-2007 Stefan Sander +** Copyright (c) 2007 Michal Policht +** Copyright (c) 2008 Brandon Fosdick +** Copyright (c) 2009-2010 Liam Staskawicz +** Copyright (c) 2011 Debao Zhang +** All right reserved. +** Web: http://code.google.com/p/qextserialport/ +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "qextserialport.h" +#include "qextserialport_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void QextSerialPortPrivate::platformSpecificInit() +{ + fd = 0; + readNotifier = 0; +} + +/*! + Standard destructor. +*/ +void QextSerialPortPrivate::platformSpecificDestruct() +{ +} + +static QString fullPortName(const QString &name) +{ + if (name.startsWith(QLatin1Char('/'))) { + return name; + } + + return QLatin1String("/dev/") + name; +} + +bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode) +{ + Q_Q(QextSerialPort); + + //note: linux 2.6.21 seems to ignore O_NDELAY flag + if ((fd = ::open(fullPortName(port).toLatin1() , O_RDWR | O_NOCTTY | O_NDELAY)) != -1) { + + /*In the Private class, We can not call QIODevice::open()*/ + q->setOpenMode(mode); // Flag the port as opened + ::tcgetattr(fd, &oldTermios); // Save the old termios + currentTermios = oldTermios; // Make a working copy + ::cfmakeraw(¤tTermios); // Enable raw access + + /*set up other port settings*/ + currentTermios.c_cflag |= CREAD | CLOCAL; + currentTermios.c_lflag &= (~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG)); + currentTermios.c_iflag &= (~(INPCK | IGNPAR | PARMRK | ISTRIP | ICRNL | IXANY)); + currentTermios.c_oflag &= (~OPOST); + currentTermios.c_cc[VMIN] = 0; +#ifdef _POSIX_VDISABLE // Is a disable character available on this system? + // Some systems allow for per-device disable-characters, so get the + // proper value for the configured device + const long vdisable = ::fpathconf(fd, _PC_VDISABLE); + currentTermios.c_cc[VINTR] = vdisable; + currentTermios.c_cc[VQUIT] = vdisable; + currentTermios.c_cc[VSTART] = vdisable; + currentTermios.c_cc[VSTOP] = vdisable; + currentTermios.c_cc[VSUSP] = vdisable; +#endif //_POSIX_VDISABLE + settingsDirtyFlags = DFE_ALL; + updatePortSettings(); + + if (queryMode == QextSerialPort::EventDriven) { + readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, q); + q->connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_q_canRead())); + } + + return true; + } else { + translateError(errno); + return false; + } +} + +bool QextSerialPortPrivate::close_sys() +{ + // Force a flush and then restore the original termios + flush_sys(); + // Using both TCSAFLUSH and TCSANOW here discards any pending input + ::tcsetattr(fd, TCSAFLUSH | TCSANOW, &oldTermios); // Restore termios + ::close(fd); + + if (readNotifier) { + delete readNotifier; + readNotifier = 0; + } + + return true; +} + +bool QextSerialPortPrivate::flush_sys() +{ + ::tcdrain(fd); + return true; +} + +qint64 QextSerialPortPrivate::bytesAvailable_sys() const +{ + int bytesQueued; + + if (::ioctl(fd, FIONREAD, &bytesQueued) == -1) { + return (qint64) - 1; + } + + return bytesQueued; +} + +/*! + Translates a system-specific error code to a QextSerialPort error code. Used internally. +*/ +void QextSerialPortPrivate::translateError(ulong error) +{ + switch (error) { + case EBADF: + case ENOTTY: + lastErr = E_INVALID_FD; + break; + + case EINTR: + lastErr = E_CAUGHT_NON_BLOCKED_SIGNAL; + break; + + case ENOMEM: + lastErr = E_NO_MEMORY; + break; + + case EACCES: + lastErr = E_PERMISSION_DENIED; + break; + + case EAGAIN: + lastErr = E_AGAIN; + break; + } +} + +void QextSerialPortPrivate::setDtr_sys(bool set) +{ + int status; + ::ioctl(fd, TIOCMGET, &status); + + if (set) { + status |= TIOCM_DTR; + } else { + status &= ~TIOCM_DTR; + } + + ::ioctl(fd, TIOCMSET, &status); +} + +void QextSerialPortPrivate::setRts_sys(bool set) +{ + int status; + ::ioctl(fd, TIOCMGET, &status); + + if (set) { + status |= TIOCM_RTS; + } else { + status &= ~TIOCM_RTS; + } + + ::ioctl(fd, TIOCMSET, &status); +} + +unsigned long QextSerialPortPrivate::lineStatus_sys() +{ + unsigned long Status = 0, Temp = 0; + ::ioctl(fd, TIOCMGET, &Temp); + + if (Temp & TIOCM_CTS) { + Status |= LS_CTS; + } + + if (Temp & TIOCM_DSR) { + Status |= LS_DSR; + } + + if (Temp & TIOCM_RI) { + Status |= LS_RI; + } + + if (Temp & TIOCM_CD) { + Status |= LS_DCD; + } + + if (Temp & TIOCM_DTR) { + Status |= LS_DTR; + } + + if (Temp & TIOCM_RTS) { + Status |= LS_RTS; + } + + if (Temp & TIOCM_ST) { + Status |= LS_ST; + } + + if (Temp & TIOCM_SR) { + Status |= LS_SR; + } + + return Status; +} + +/*! + Reads a block of data from the serial port. This function will read at most maxSize bytes from + the serial port and place them in the buffer pointed to by data. Return value is the number of + bytes actually read, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPortPrivate::readData_sys(char *data, qint64 maxSize) +{ + int retVal = ::read(fd, data, maxSize); + + if (retVal == -1) { + lastErr = E_READ_FAILED; + } + + return retVal; +} + +/*! + Writes a block of data to the serial port. This function will write maxSize bytes + from the buffer pointed to by data to the serial port. Return value is the number + of bytes actually written, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPortPrivate::writeData_sys(const char *data, qint64 maxSize) +{ + int retVal = ::write(fd, data, maxSize); + + if (retVal == -1) { + lastErr = E_WRITE_FAILED; + } + + return (qint64)retVal; +} + +static void setBaudRate2Termios(termios *config, int baudRate) +{ +#ifdef CBAUD + config->c_cflag &= (~CBAUD); + config->c_cflag |= baudRate; +#else + ::cfsetispeed(config, baudRate); + ::cfsetospeed(config, baudRate); +#endif +} + +/* + All the platform settings was performed in this function. +*/ +void QextSerialPortPrivate::updatePortSettings() +{ + if (!q_func()->isOpen() || !settingsDirtyFlags) { + return; + } + + if (settingsDirtyFlags & DFE_BaudRate) { + switch (settings.BaudRate) { + case BAUD50: + setBaudRate2Termios(¤tTermios, B50); + break; + + case BAUD75: + setBaudRate2Termios(¤tTermios, B75); + break; + + case BAUD110: + setBaudRate2Termios(¤tTermios, B110); + break; + + case BAUD134: + setBaudRate2Termios(¤tTermios, B134); + break; + + case BAUD150: + setBaudRate2Termios(¤tTermios, B150); + break; + + case BAUD200: + setBaudRate2Termios(¤tTermios, B200); + break; + + case BAUD300: + setBaudRate2Termios(¤tTermios, B300); + break; + + case BAUD600: + setBaudRate2Termios(¤tTermios, B600); + break; + + case BAUD1200: + setBaudRate2Termios(¤tTermios, B1200); + break; + + case BAUD1800: + setBaudRate2Termios(¤tTermios, B1800); + break; + + case BAUD2400: + setBaudRate2Termios(¤tTermios, B2400); + break; + + case BAUD4800: + setBaudRate2Termios(¤tTermios, B4800); + break; + + case BAUD9600: + setBaudRate2Termios(¤tTermios, B9600); + break; + + case BAUD19200: + setBaudRate2Termios(¤tTermios, B19200); + break; + + case BAUD38400: + setBaudRate2Termios(¤tTermios, B38400); + break; + + case BAUD57600: + setBaudRate2Termios(¤tTermios, B57600); + break; +#ifdef B76800 + + case BAUD76800: + setBaudRate2Termios(¤tTermios, B76800); + break; +#endif + + case BAUD115200: + setBaudRate2Termios(¤tTermios, B115200); + break; +#if defined(B230400) && defined(B4000000) + + case BAUD230400: + setBaudRate2Termios(¤tTermios, B230400); + break; + + case BAUD460800: + setBaudRate2Termios(¤tTermios, B460800); + break; + + case BAUD500000: + setBaudRate2Termios(¤tTermios, B500000); + break; + + case BAUD576000: + setBaudRate2Termios(¤tTermios, B576000); + break; + + case BAUD921600: + setBaudRate2Termios(¤tTermios, B921600); + break; + + case BAUD1000000: + setBaudRate2Termios(¤tTermios, B1000000); + break; + + case BAUD1152000: + setBaudRate2Termios(¤tTermios, B1152000); + break; + + case BAUD1500000: + setBaudRate2Termios(¤tTermios, B1500000); + break; + + case BAUD2000000: + setBaudRate2Termios(¤tTermios, B2000000); + break; + + case BAUD2500000: + setBaudRate2Termios(¤tTermios, B2500000); + break; + + case BAUD3000000: + setBaudRate2Termios(¤tTermios, B3000000); + break; + + case BAUD3500000: + setBaudRate2Termios(¤tTermios, B3500000); + break; + + case BAUD4000000: + setBaudRate2Termios(¤tTermios, B4000000); + break; +#endif +#ifdef Q_OS_MAC + + default: + setBaudRate2Termios(¤tTermios, settings.BaudRate); + break; +#endif + } + } + + if (settingsDirtyFlags & DFE_Parity) { + switch (settings.Parity) { + case PAR_SPACE: + /*space parity not directly supported - add an extra data bit to simulate it*/ + settingsDirtyFlags |= DFE_DataBits; + break; + + case PAR_NONE: + currentTermios.c_cflag &= (~PARENB); + break; + + case PAR_EVEN: + currentTermios.c_cflag &= (~PARODD); + currentTermios.c_cflag |= PARENB; + break; + + case PAR_ODD: + currentTermios.c_cflag |= (PARENB | PARODD); + break; + } + } + + /*must after Parity settings*/ + if (settingsDirtyFlags & DFE_DataBits) { + if (settings.Parity != PAR_SPACE) { + currentTermios.c_cflag &= (~CSIZE); + + switch (settings.DataBits) { + case DATA_5: + currentTermios.c_cflag |= CS5; + break; + + case DATA_6: + currentTermios.c_cflag |= CS6; + break; + + case DATA_7: + currentTermios.c_cflag |= CS7; + break; + + case DATA_8: + currentTermios.c_cflag |= CS8; + break; + } + } else { + /*space parity not directly supported - add an extra data bit to simulate it*/ + currentTermios.c_cflag &= ~(PARENB | CSIZE); + + switch (settings.DataBits) { + case DATA_5: + currentTermios.c_cflag |= CS6; + break; + + case DATA_6: + currentTermios.c_cflag |= CS7; + break; + + case DATA_7: + currentTermios.c_cflag |= CS8; + break; + + case DATA_8: + /*this will never happen, put here to Suppress an warning*/ + break; + } + } + } + + if (settingsDirtyFlags & DFE_StopBits) { + switch (settings.StopBits) { + case STOP_1: + currentTermios.c_cflag &= (~CSTOPB); + break; + + case STOP_2: + currentTermios.c_cflag |= CSTOPB; + break; + } + } + + if (settingsDirtyFlags & DFE_Flow) { + switch (settings.FlowControl) { + case FLOW_OFF: + currentTermios.c_cflag &= (~CRTSCTS); + currentTermios.c_iflag &= (~(IXON | IXOFF | IXANY)); + break; + + case FLOW_XONXOFF: + /*software (XON/XOFF) flow control*/ + currentTermios.c_cflag &= (~CRTSCTS); + currentTermios.c_iflag |= (IXON | IXOFF | IXANY); + break; + + case FLOW_HARDWARE: + currentTermios.c_cflag |= CRTSCTS; + currentTermios.c_iflag &= (~(IXON | IXOFF | IXANY)); + break; + } + } + + /*if any thing in currentTermios changed, flush*/ + if (settingsDirtyFlags & DFE_Settings_Mask) { + ::tcsetattr(fd, TCSAFLUSH, ¤tTermios); + } + + if (settingsDirtyFlags & DFE_TimeOut) { + int millisec = settings.Timeout_Millisec; + + if (millisec == -1) { + ::fcntl(fd, F_SETFL, O_NDELAY); + } else { + //O_SYNC should enable blocking ::write() + //however this seems not working on Linux 2.6.21 (works on OpenBSD 4.2) + ::fcntl(fd, F_SETFL, O_SYNC); + } + + ::tcgetattr(fd, ¤tTermios); + currentTermios.c_cc[VTIME] = millisec / 100; + ::tcsetattr(fd, TCSAFLUSH, ¤tTermios); + } + + settingsDirtyFlags = 0; +} diff --git a/tool/3rd_qextserialport/qextserialport_win.cpp b/tool/3rd_qextserialport/qextserialport_win.cpp new file mode 100644 index 0000000..e48ddde --- /dev/null +++ b/tool/3rd_qextserialport/qextserialport_win.cpp @@ -0,0 +1,482 @@ +/**************************************************************************** +** Copyright (c) 2000-2003 Wayne Roth +** Copyright (c) 2004-2007 Stefan Sander +** Copyright (c) 2007 Michal Policht +** Copyright (c) 2008 Brandon Fosdick +** Copyright (c) 2009-2010 Liam Staskawicz +** Copyright (c) 2011 Debao Zhang +** All right reserved. +** Web: http://code.google.com/p/qextserialport/ +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "qextserialport.h" +#include "qextserialport_p.h" +#include +#include +#include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#else +#include +#endif + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include +#else +#include +#endif + +void QextSerialPortPrivate::platformSpecificInit() +{ + handle = INVALID_HANDLE_VALUE; + ZeroMemory(&overlap, sizeof(OVERLAPPED)); + overlap.hEvent = CreateEvent(NULL, true, false, NULL); + winEventNotifier = 0; + bytesToWriteLock = new QReadWriteLock; +} + +void QextSerialPortPrivate::platformSpecificDestruct() +{ + CloseHandle(overlap.hEvent); + delete bytesToWriteLock; +} + + +/*! + \internal + COM ports greater than 9 need \\.\ prepended + + This is only need when open the port. +*/ +static QString fullPortNameWin(const QString &name) +{ + QRegExp rx(QLatin1String("^COM(\\d+)")); + QString fullName(name); + if (rx.indexIn(fullName) >= 0) { + fullName.prepend(QLatin1String("\\\\.\\")); + } + + return fullName; +} + +bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode) +{ + Q_Q(QextSerialPort); + DWORD confSize = sizeof(COMMCONFIG); + commConfig.dwSize = confSize; + DWORD dwFlagsAndAttributes = 0; + + if (queryMode == QextSerialPort::EventDriven) { + dwFlagsAndAttributes += FILE_FLAG_OVERLAPPED; + } + + /*open the port*/ + handle = CreateFileW((wchar_t *)fullPortNameWin(port).utf16(), GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); + + if (handle != INVALID_HANDLE_VALUE) { + q->setOpenMode(mode); + /*configure port settings*/ + GetCommConfig(handle, &commConfig, &confSize); + GetCommState(handle, &(commConfig.dcb)); + + /*set up parameters*/ + commConfig.dcb.fBinary = TRUE; + commConfig.dcb.fInX = FALSE; + commConfig.dcb.fOutX = FALSE; + commConfig.dcb.fAbortOnError = FALSE; + commConfig.dcb.fNull = FALSE; + /* Dtr default to true. See Issue 122*/ + commConfig.dcb.fDtrControl = TRUE; + /*flush all settings*/ + settingsDirtyFlags = DFE_ALL; + updatePortSettings(); + + //init event driven approach + if (queryMode == QextSerialPort::EventDriven) { + if (!SetCommMask(handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) { + QESP_WARNING() << "failed to set Comm Mask. Error code:" << GetLastError(); + return false; + } + + winEventNotifier = new QWinEventNotifier(overlap.hEvent, q); + qRegisterMetaType("HANDLE"); + q->connect(winEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onWinEvent(HANDLE)), Qt::DirectConnection); + WaitCommEvent(handle, &eventMask, &overlap); + } + + return true; + } + + return false; +} + +bool QextSerialPortPrivate::close_sys() +{ + flush_sys(); + CancelIo(handle); + + if (CloseHandle(handle)) { + handle = INVALID_HANDLE_VALUE; + } + + if (winEventNotifier) { + winEventNotifier->setEnabled(false); + winEventNotifier->deleteLater(); + winEventNotifier = 0; + } + + foreach (OVERLAPPED *o, pendingWrites) { + CloseHandle(o->hEvent); + delete o; + } + + pendingWrites.clear(); + return true; +} + +bool QextSerialPortPrivate::flush_sys() +{ + FlushFileBuffers(handle); + return true; +} + +qint64 QextSerialPortPrivate::bytesAvailable_sys() const +{ + DWORD Errors; + COMSTAT Status; + + if (ClearCommError(handle, &Errors, &Status)) { + return Status.cbInQue; + } + + return (qint64) - 1; +} + +/* + Translates a system-specific error code to a QextSerialPort error code. Used internally. +*/ +void QextSerialPortPrivate::translateError(ulong error) +{ + if (error & CE_BREAK) { + lastErr = E_BREAK_CONDITION; + } else if (error & CE_FRAME) { + lastErr = E_FRAMING_ERROR; + } else if (error & CE_IOE) { + lastErr = E_IO_ERROR; + } else if (error & CE_MODE) { + lastErr = E_INVALID_FD; + } else if (error & CE_OVERRUN) { + lastErr = E_BUFFER_OVERRUN; + } else if (error & CE_RXPARITY) { + lastErr = E_RECEIVE_PARITY_ERROR; + } else if (error & CE_RXOVER) { + lastErr = E_RECEIVE_OVERFLOW; + } else if (error & CE_TXFULL) { + lastErr = E_TRANSMIT_OVERFLOW; + } +} + +/* + Reads a block of data from the serial port. This function will read at most maxlen bytes from + the serial port and place them in the buffer pointed to by data. Return value is the number of + bytes actually read, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPortPrivate::readData_sys(char *data, qint64 maxSize) +{ + DWORD bytesRead = 0; + bool failed = false; + + if (queryMode == QextSerialPort::EventDriven) { + OVERLAPPED overlapRead; + ZeroMemory(&overlapRead, sizeof(OVERLAPPED)); + + if (!ReadFile(handle, (void *)data, (DWORD)maxSize, &bytesRead, &overlapRead)) { + if (GetLastError() == ERROR_IO_PENDING) { + GetOverlappedResult(handle, &overlapRead, &bytesRead, true); + } else { + failed = true; + } + } + } else if (!ReadFile(handle, (void *)data, (DWORD)maxSize, &bytesRead, NULL)) { + failed = true; + } + + if (!failed) { + return (qint64)bytesRead; + } + + lastErr = E_READ_FAILED; + return -1; +} + +/* + Writes a block of data to the serial port. This function will write len bytes + from the buffer pointed to by data to the serial port. Return value is the number + of bytes actually written, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPortPrivate::writeData_sys(const char *data, qint64 maxSize) +{ + DWORD bytesWritten = 0; + bool failed = false; + + if (queryMode == QextSerialPort::EventDriven) { + OVERLAPPED *newOverlapWrite = new OVERLAPPED; + ZeroMemory(newOverlapWrite, sizeof(OVERLAPPED)); + newOverlapWrite->hEvent = CreateEvent(NULL, true, false, NULL); + + if (WriteFile(handle, (void *)data, (DWORD)maxSize, &bytesWritten, newOverlapWrite)) { + CloseHandle(newOverlapWrite->hEvent); + delete newOverlapWrite; + } else if (GetLastError() == ERROR_IO_PENDING) { + // writing asynchronously...not an error + QWriteLocker writelocker(bytesToWriteLock); + pendingWrites.append(newOverlapWrite); + } else { + QESP_WARNING() << "QextSerialPort write error:" << GetLastError(); + failed = true; + + if (!CancelIo(newOverlapWrite->hEvent)) { + QESP_WARNING("QextSerialPort: couldn't cancel IO"); + } + + if (!CloseHandle(newOverlapWrite->hEvent)) { + QESP_WARNING("QextSerialPort: couldn't close OVERLAPPED handle"); + } + + delete newOverlapWrite; + } + } else if (!WriteFile(handle, (void *)data, (DWORD)maxSize, &bytesWritten, NULL)) { + failed = true; + } + + if (!failed) { + return (qint64)bytesWritten; + } + + lastErr = E_WRITE_FAILED; + return -1; +} + +void QextSerialPortPrivate::setDtr_sys(bool set) +{ + EscapeCommFunction(handle, set ? SETDTR : CLRDTR); +} + +void QextSerialPortPrivate::setRts_sys(bool set) +{ + EscapeCommFunction(handle, set ? SETRTS : CLRRTS); +} + +ulong QextSerialPortPrivate::lineStatus_sys(void) +{ + unsigned long Status = 0, Temp = 0; + GetCommModemStatus(handle, &Temp); + + if (Temp & MS_CTS_ON) { + Status |= LS_CTS; + } + + if (Temp & MS_DSR_ON) { + Status |= LS_DSR; + } + + if (Temp & MS_RING_ON) { + Status |= LS_RI; + } + + if (Temp & MS_RLSD_ON) { + Status |= LS_DCD; + } + + return Status; +} + +/* + Triggered when there's activity on our HANDLE. +*/ +void QextSerialPortPrivate::_q_onWinEvent(HANDLE h) +{ + Q_Q(QextSerialPort); + + if (h == overlap.hEvent) { + if (eventMask & EV_RXCHAR) { + if (q->sender() != q && bytesAvailable_sys() > 0) { + _q_canRead(); + } + } + + if (eventMask & EV_TXEMPTY) { + /* + A write completed. Run through the list of OVERLAPPED writes, and if + they completed successfully, take them off the list and delete them. + Otherwise, leave them on there so they can finish. + */ + qint64 totalBytesWritten = 0; + QList overlapsToDelete; + + foreach (OVERLAPPED *o, pendingWrites) { + DWORD numBytes = 0; + + if (GetOverlappedResult(handle, o, &numBytes, false)) { + overlapsToDelete.append(o); + totalBytesWritten += numBytes; + } else if (GetLastError() != ERROR_IO_INCOMPLETE) { + overlapsToDelete.append(o); + QESP_WARNING() << "CommEvent overlapped write error:" << GetLastError(); + } + } + + if (q->sender() != q && totalBytesWritten > 0) { + QWriteLocker writelocker(bytesToWriteLock); + Q_EMIT q->bytesWritten(totalBytesWritten); + } + + foreach (OVERLAPPED *o, overlapsToDelete) { + OVERLAPPED *toDelete = pendingWrites.takeAt(pendingWrites.indexOf(o)); + CloseHandle(toDelete->hEvent); + delete toDelete; + } + } + + if (eventMask & EV_DSR) { + if (lineStatus_sys() & LS_DSR) { + Q_EMIT q->dsrChanged(true); + } else { + Q_EMIT q->dsrChanged(false); + } + } + } + + WaitCommEvent(handle, &eventMask, &overlap); +} + +void QextSerialPortPrivate::updatePortSettings() +{ + if (!q_ptr->isOpen() || !settingsDirtyFlags) { + return; + } + + //fill struct : COMMCONFIG + if (settingsDirtyFlags & DFE_BaudRate) { + commConfig.dcb.BaudRate = settings.BaudRate; + } + + if (settingsDirtyFlags & DFE_Parity) { + commConfig.dcb.Parity = (BYTE)settings.Parity; + commConfig.dcb.fParity = (settings.Parity == PAR_NONE) ? FALSE : TRUE; + } + + if (settingsDirtyFlags & DFE_DataBits) { + commConfig.dcb.ByteSize = (BYTE)settings.DataBits; + } + + if (settingsDirtyFlags & DFE_StopBits) { + switch (settings.StopBits) { + case STOP_1: + commConfig.dcb.StopBits = ONESTOPBIT; + break; + + case STOP_1_5: + commConfig.dcb.StopBits = ONE5STOPBITS; + break; + + case STOP_2: + commConfig.dcb.StopBits = TWOSTOPBITS; + break; + } + } + + if (settingsDirtyFlags & DFE_Flow) { + switch (settings.FlowControl) { + /*no flow control*/ + case FLOW_OFF: + commConfig.dcb.fOutxCtsFlow = FALSE; + commConfig.dcb.fRtsControl = RTS_CONTROL_DISABLE; + commConfig.dcb.fInX = FALSE; + commConfig.dcb.fOutX = FALSE; + break; + + /*software (XON/XOFF) flow control*/ + case FLOW_XONXOFF: + commConfig.dcb.fOutxCtsFlow = FALSE; + commConfig.dcb.fRtsControl = RTS_CONTROL_DISABLE; + commConfig.dcb.fInX = TRUE; + commConfig.dcb.fOutX = TRUE; + break; + + /*hardware flow control*/ + case FLOW_HARDWARE: + commConfig.dcb.fOutxCtsFlow = TRUE; + commConfig.dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; + commConfig.dcb.fInX = FALSE; + commConfig.dcb.fOutX = FALSE; + break; + } + } + + //fill struct : COMMTIMEOUTS + if (settingsDirtyFlags & DFE_TimeOut) { + if (queryMode != QextSerialPort::EventDriven) { + int millisec = settings.Timeout_Millisec; + + if (millisec == -1) { + commTimeouts.ReadIntervalTimeout = MAXDWORD; + commTimeouts.ReadTotalTimeoutConstant = 0; + } else { + commTimeouts.ReadIntervalTimeout = millisec; + commTimeouts.ReadTotalTimeoutConstant = millisec; + } + + commTimeouts.ReadTotalTimeoutMultiplier = 0; + commTimeouts.WriteTotalTimeoutMultiplier = millisec; + commTimeouts.WriteTotalTimeoutConstant = 0; + } else { + commTimeouts.ReadIntervalTimeout = MAXDWORD; + commTimeouts.ReadTotalTimeoutMultiplier = 0; + commTimeouts.ReadTotalTimeoutConstant = 0; + commTimeouts.WriteTotalTimeoutMultiplier = 0; + commTimeouts.WriteTotalTimeoutConstant = 0; + } + } + + + if (settingsDirtyFlags & DFE_Settings_Mask) { + SetCommConfig(handle, &commConfig, sizeof(COMMCONFIG)); + } + + if ((settingsDirtyFlags & DFE_TimeOut)) { + SetCommTimeouts(handle, &commTimeouts); + } + + settingsDirtyFlags = 0; +} diff --git a/tool/3rd_smtpclient/3rd_smtpclient.pri b/tool/3rd_smtpclient/3rd_smtpclient.pri new file mode 100644 index 0000000..90a51fd --- /dev/null +++ b/tool/3rd_smtpclient/3rd_smtpclient.pri @@ -0,0 +1,28 @@ +HEADERS += \ + $$PWD/emailaddress.h \ + $$PWD/mimeattachment.h \ + $$PWD/mimecontentformatter.h \ + $$PWD/mimefile.h \ + $$PWD/mimehtml.h \ + $$PWD/mimeinlinefile.h \ + $$PWD/mimemessage.h \ + $$PWD/mimemultipart.h \ + $$PWD/mimepart.h \ + $$PWD/mimetext.h \ + $$PWD/quotedprintable.h \ + $$PWD/smtpclient.h \ + $$PWD/smtpmime.h + +SOURCES += \ + $$PWD/emailaddress.cpp \ + $$PWD/mimeattachment.cpp \ + $$PWD/mimecontentformatter.cpp \ + $$PWD/mimefile.cpp \ + $$PWD/mimehtml.cpp \ + $$PWD/mimeinlinefile.cpp \ + $$PWD/mimemessage.cpp \ + $$PWD/mimemultipart.cpp \ + $$PWD/mimepart.cpp \ + $$PWD/mimetext.cpp \ + $$PWD/quotedprintable.cpp \ + $$PWD/smtpclient.cpp diff --git a/tool/3rd_smtpclient/emailaddress.cpp b/tool/3rd_smtpclient/emailaddress.cpp new file mode 100644 index 0000000..808ce43 --- /dev/null +++ b/tool/3rd_smtpclient/emailaddress.cpp @@ -0,0 +1,31 @@ +#include "emailaddress.h" + +EmailAddress::EmailAddress(const QString &address, const QString &name) +{ + this->address = address; + this->name = name; +} + +EmailAddress::~EmailAddress() +{ +} + +void EmailAddress::setName(const QString &name) +{ + this->name = name; +} + +void EmailAddress::setAddress(const QString &address) +{ + this->address = address; +} + +const QString &EmailAddress::getName() const +{ + return name; +} + +const QString &EmailAddress::getAddress() const +{ + return address; +} diff --git a/tool/3rd_smtpclient/emailaddress.h b/tool/3rd_smtpclient/emailaddress.h new file mode 100644 index 0000000..8e56938 --- /dev/null +++ b/tool/3rd_smtpclient/emailaddress.h @@ -0,0 +1,25 @@ +#ifndef EMAILADDRESS_H +#define EMAILADDRESS_H + +#include + +class EmailAddress : public QObject +{ + Q_OBJECT +public: + EmailAddress(const QString &address, const QString &name = ""); + ~EmailAddress(); + + void setName(const QString &name); + void setAddress(const QString &address); + + const QString &getName() const; + const QString &getAddress() const; + +private: + QString name; + QString address; + +}; + +#endif // EMAILADDRESS_H diff --git a/tool/3rd_smtpclient/mimeattachment.cpp b/tool/3rd_smtpclient/mimeattachment.cpp new file mode 100644 index 0000000..aae9c4c --- /dev/null +++ b/tool/3rd_smtpclient/mimeattachment.cpp @@ -0,0 +1,17 @@ +#include "mimeattachment.h" +#include + +MimeAttachment::MimeAttachment(QFile *file) + : MimeFile(file) +{ +} + +MimeAttachment::~MimeAttachment() +{ +} + +void MimeAttachment::prepare() +{ + this->header += "Content-disposition: attachment\r\n"; + MimeFile::prepare(); +} diff --git a/tool/3rd_smtpclient/mimeattachment.h b/tool/3rd_smtpclient/mimeattachment.h new file mode 100644 index 0000000..e9ea1fa --- /dev/null +++ b/tool/3rd_smtpclient/mimeattachment.h @@ -0,0 +1,20 @@ +#ifndef MIMEATTACHMENT_H +#define MIMEATTACHMENT_H + +#include +#include "mimepart.h" +#include "mimefile.h" + +class MimeAttachment : public MimeFile +{ + Q_OBJECT +public: + MimeAttachment(QFile *file); + ~MimeAttachment(); + +protected: + virtual void prepare(); + +}; + +#endif // MIMEATTACHMENT_H diff --git a/tool/3rd_smtpclient/mimecontentformatter.cpp b/tool/3rd_smtpclient/mimecontentformatter.cpp new file mode 100644 index 0000000..cadce81 --- /dev/null +++ b/tool/3rd_smtpclient/mimecontentformatter.cpp @@ -0,0 +1,51 @@ +#include "mimecontentformatter.h" + +MimeContentFormatter::MimeContentFormatter(int max_length) : + max_length(max_length) +{} + +QString MimeContentFormatter::format(const QString &content, bool quotedPrintable) const +{ + QString out; + + int chars = 0; + + for (int i = 0; i < content.length() ; ++i) { + chars++; + + if (!quotedPrintable) { + if (chars > max_length) { + out.append("\r\n"); + chars = 1; + } + } else { + if (content.at(i) == '\n') { // new line + out.append(content.at(i)); + chars = 0; + continue; + } + + if ((chars > max_length - 1) + || ((content.at(i) == '=') && (chars > max_length - 3))) { + out.append('='); + out.append("\r\n"); + chars = 1; + } + + } + + out.append(content.at(i)); + } + + return out; +} + +void MimeContentFormatter::setMaxLength(int l) +{ + max_length = l; +} + +int MimeContentFormatter::getMaxLength() const +{ + return max_length; +} diff --git a/tool/3rd_smtpclient/mimecontentformatter.h b/tool/3rd_smtpclient/mimecontentformatter.h new file mode 100644 index 0000000..8b24b9a --- /dev/null +++ b/tool/3rd_smtpclient/mimecontentformatter.h @@ -0,0 +1,23 @@ +#ifndef MIMECONTENTFORMATTER_H +#define MIMECONTENTFORMATTER_H + +#include +#include + +class MimeContentFormatter : public QObject +{ + Q_OBJECT +public: + MimeContentFormatter(int max_length = 76); + + void setMaxLength(int l); + int getMaxLength() const; + + QString format(const QString &content, bool quotedPrintable = false) const; + +protected: + int max_length; + +}; + +#endif // MIMECONTENTFORMATTER_H diff --git a/tool/3rd_smtpclient/mimefile.cpp b/tool/3rd_smtpclient/mimefile.cpp new file mode 100644 index 0000000..02648aa --- /dev/null +++ b/tool/3rd_smtpclient/mimefile.cpp @@ -0,0 +1,23 @@ +#include "mimefile.h" +#include + +MimeFile::MimeFile(QFile *file) +{ + this->file = file; + this->cType = "application/octet-stream"; + this->cName = QFileInfo(*file).fileName(); + this->cEncoding = Base64; +} + +MimeFile::~MimeFile() +{ + delete file; +} + +void MimeFile::prepare() +{ + file->open(QIODevice::ReadOnly); + this->content = file->readAll(); + file->close(); + MimePart::prepare(); +} diff --git a/tool/3rd_smtpclient/mimefile.h b/tool/3rd_smtpclient/mimefile.h new file mode 100644 index 0000000..e85e0c5 --- /dev/null +++ b/tool/3rd_smtpclient/mimefile.h @@ -0,0 +1,21 @@ +#ifndef MIMEFILE_H +#define MIMEFILE_H + +#include "mimepart.h" +#include + +class MimeFile : public MimePart +{ + Q_OBJECT +public: + + MimeFile(QFile *f); + ~MimeFile(); + +protected: + QFile *file; + virtual void prepare(); + +}; + +#endif // MIMEFILE_H diff --git a/tool/3rd_smtpclient/mimehtml.cpp b/tool/3rd_smtpclient/mimehtml.cpp new file mode 100644 index 0000000..2bde903 --- /dev/null +++ b/tool/3rd_smtpclient/mimehtml.cpp @@ -0,0 +1,23 @@ +#include "mimehtml.h" + +MimeHtml::MimeHtml(const QString &html) : MimeText(html) +{ + this->cType = "text/html"; +} + +MimeHtml::~MimeHtml() {} + +void MimeHtml::setHtml(const QString &html) +{ + this->text = html; +} + +const QString &MimeHtml::getHtml() const +{ + return text; +} + +void MimeHtml::prepare() +{ + MimeText::prepare(); +} diff --git a/tool/3rd_smtpclient/mimehtml.h b/tool/3rd_smtpclient/mimehtml.h new file mode 100644 index 0000000..111bb31 --- /dev/null +++ b/tool/3rd_smtpclient/mimehtml.h @@ -0,0 +1,21 @@ +#ifndef MIMEHTML_H +#define MIMEHTML_H + +#include "mimetext.h" + +class MimeHtml : public MimeText +{ + Q_OBJECT +public: + MimeHtml(const QString &html = ""); + ~MimeHtml(); + + void setHtml(const QString &html); + const QString &getHtml() const; + +protected: + virtual void prepare(); + +}; + +#endif // MIMEHTML_H diff --git a/tool/3rd_smtpclient/mimeinlinefile.cpp b/tool/3rd_smtpclient/mimeinlinefile.cpp new file mode 100644 index 0000000..f24be61 --- /dev/null +++ b/tool/3rd_smtpclient/mimeinlinefile.cpp @@ -0,0 +1,15 @@ +#include "mimeinlinefile.h" + +MimeInlineFile::MimeInlineFile(QFile *f) + : MimeFile(f) +{ +} + +MimeInlineFile::~MimeInlineFile() +{} + +void MimeInlineFile::prepare() +{ + this->header += "Content-Disposition: inline\r\n"; + MimeFile::prepare(); +} diff --git a/tool/3rd_smtpclient/mimeinlinefile.h b/tool/3rd_smtpclient/mimeinlinefile.h new file mode 100644 index 0000000..121af25 --- /dev/null +++ b/tool/3rd_smtpclient/mimeinlinefile.h @@ -0,0 +1,18 @@ +#ifndef MIMEINLINEFILE_H +#define MIMEINLINEFILE_H + +#include "mimefile.h" + +class MimeInlineFile : public MimeFile +{ +public: + + MimeInlineFile(QFile *f); + ~MimeInlineFile(); + +protected: + virtual void prepare(); + +}; + +#endif // MIMEINLINEFILE_H diff --git a/tool/3rd_smtpclient/mimemessage.cpp b/tool/3rd_smtpclient/mimemessage.cpp new file mode 100644 index 0000000..f419936 --- /dev/null +++ b/tool/3rd_smtpclient/mimemessage.cpp @@ -0,0 +1,223 @@ +#include "mimemessage.h" + +#include +#include "quotedprintable.h" +#include + +MimeMessage::MimeMessage(bool createAutoMimeContent) : + hEncoding(MimePart::_8Bit) +{ + if (createAutoMimeContent) { + this->content = new MimeMultiPart(); + } +} + +MimeMessage::~MimeMessage() +{ +} + +MimePart &MimeMessage::getContent() +{ + return *content; +} + +void MimeMessage::setContent(MimePart *content) +{ + this->content = content; +} + +void MimeMessage::setSender(EmailAddress *e) +{ + this->sender = e; +} + +void MimeMessage::addRecipient(EmailAddress *rcpt, RecipientType type) +{ + switch (type) { + case To: + recipientsTo << rcpt; + break; + + case Cc: + recipientsCc << rcpt; + break; + + case Bcc: + recipientsBcc << rcpt; + break; + } +} + +void MimeMessage::addTo(EmailAddress *rcpt) +{ + this->recipientsTo << rcpt; +} + +void MimeMessage::addCc(EmailAddress *rcpt) +{ + this->recipientsCc << rcpt; +} + +void MimeMessage::addBcc(EmailAddress *rcpt) +{ + this->recipientsBcc << rcpt; +} + +void MimeMessage::setSubject(const QString &subject) +{ + this->subject = subject; +} + +void MimeMessage::addPart(MimePart *part) +{ + if (typeid(*content) == typeid(MimeMultiPart)) { + ((MimeMultiPart *) content)->addPart(part); + }; +} + +void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc) +{ + this->hEncoding = hEnc; +} + +const EmailAddress &MimeMessage::getSender() const +{ + return *sender; +} + +const QList &MimeMessage::getRecipients(RecipientType type) const +{ + switch (type) { + default: + case To: + return recipientsTo; + + case Cc: + return recipientsCc; + + case Bcc: + return recipientsBcc; + } +} + +const QString &MimeMessage::getSubject() const +{ + return subject; +} + +const QList &MimeMessage::getParts() const +{ + if (typeid(*content) == typeid(MimeMultiPart)) { + return ((MimeMultiPart *) content)->getParts(); + } else { + QList *res = new QList(); + res->append(content); + return *res; + } +} + +QString MimeMessage::toString() +{ + QString mime; + mime = "From:"; + + QByteArray name = sender->getName().toUtf8(); + if (name != "") { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + QByteArray().append(name).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(name)).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += " " + name; + } + } + + mime += " <" + sender->getAddress() + ">\r\n"; + + mime += "To:"; + QList::iterator it; + int i; + + for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i) { + if (i != 0) { + mime += ","; + } + + QByteArray name = (*it)->getName().toUtf8(); + if (name != "") { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + QByteArray().append(name).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(name)).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += " " + name; + } + } + + mime += " <" + (*it)->getAddress() + ">"; + } + + mime += "\r\n"; + if (recipientsCc.size() != 0) { + mime += "Cc:"; + } + + for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i) { + if (i != 0) { + mime += ","; + } + + QByteArray name = (*it)->getName().toUtf8(); + if (name != "") { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + QByteArray().append(name).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(name)).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += " " + name; + } + } + + mime += " <" + (*it)->getAddress() + ">"; + } + + if (recipientsCc.size() != 0) { + mime += "\r\n"; + } + + mime += "Subject: "; + + switch (hEncoding) { + case MimePart::Base64: + mime += "=?utf-8?B?" + QByteArray().append(subject.toUtf8()).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += "=?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(subject.toUtf8())).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += subject; + } + + mime += "\r\n"; + mime += "MIME-Version: 1.0\r\n"; + + mime += content->toString(); + return mime; +} diff --git a/tool/3rd_smtpclient/mimemessage.h b/tool/3rd_smtpclient/mimemessage.h new file mode 100644 index 0000000..569b596 --- /dev/null +++ b/tool/3rd_smtpclient/mimemessage.h @@ -0,0 +1,54 @@ +#ifndef MIMEMESSAGE_H +#define MIMEMESSAGE_H + +#include "mimepart.h" +#include "mimemultipart.h" +#include "emailaddress.h" +#include + +class MimeMessage : public QObject +{ +public: + + enum RecipientType { + To, // primary + Cc, // carbon copy + Bcc // blind carbon copy + }; + + + MimeMessage(bool createAutoMimeConent = true); + ~MimeMessage(); + + void setSender(EmailAddress *e); + void addRecipient(EmailAddress *rcpt, RecipientType type = To); + void addTo(EmailAddress *rcpt); + void addCc(EmailAddress *rcpt); + void addBcc(EmailAddress *rcpt); + void setSubject(const QString &subject); + void addPart(MimePart *part); + + void setHeaderEncoding(MimePart::Encoding); + + const EmailAddress &getSender() const; + const QList &getRecipients(RecipientType type = To) const; + const QString &getSubject() const; + const QList &getParts() const; + + MimePart &getContent(); + void setContent(MimePart *content); + + virtual QString toString(); + + +protected: + EmailAddress *sender; + QList recipientsTo, recipientsCc, recipientsBcc; + QString subject; + MimePart *content; + + MimePart::Encoding hEncoding; + +}; + +#endif // MIMEMESSAGE_H diff --git a/tool/3rd_smtpclient/mimemultipart.cpp b/tool/3rd_smtpclient/mimemultipart.cpp new file mode 100644 index 0000000..dfde103 --- /dev/null +++ b/tool/3rd_smtpclient/mimemultipart.cpp @@ -0,0 +1,66 @@ +#include "mimemultipart.h" +#include "stdlib.h" +#include +#include + +const QString MULTI_PART_NAMES[] = { + "multipart/mixed", // Mixed + "multipart/digest", // Digest + "multipart/alternative", // Alternative + "multipart/related", // Related + "multipart/report", // Report + "multipart/signed", // Signed + "multipart/encrypted" // Encrypted +}; + +MimeMultiPart::MimeMultiPart(MultiPartType type) +{ + this->type = type; + this->cType = MULTI_PART_NAMES[this->type]; + this->cEncoding = _8Bit; + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(QByteArray().append(rand())); + cBoundary = md5.result().toHex(); +} + +MimeMultiPart::~MimeMultiPart() +{ + +} + +void MimeMultiPart::addPart(MimePart *part) +{ + parts.append(part); +} + +const QList &MimeMultiPart::getParts() const +{ + return parts; +} + +void MimeMultiPart::prepare() +{ + QList::iterator it; + content = ""; + + for (it = parts.begin(); it != parts.end(); it++) { + content += "--" + cBoundary.toUtf8() + "\r\n"; + (*it)->prepare(); + content += (*it)->toString().toUtf8(); + }; + + content += "--" + cBoundary.toUtf8() + "--\r\n"; + MimePart::prepare(); +} + +void MimeMultiPart::setMimeType(const MultiPartType type) +{ + this->type = type; + this->cType = MULTI_PART_NAMES[type]; +} + +MimeMultiPart::MultiPartType MimeMultiPart::getMimeType() const +{ + return type; +} diff --git a/tool/3rd_smtpclient/mimemultipart.h b/tool/3rd_smtpclient/mimemultipart.h new file mode 100644 index 0000000..bc716ae --- /dev/null +++ b/tool/3rd_smtpclient/mimemultipart.h @@ -0,0 +1,37 @@ +#ifndef MIMEMULTIPART_H +#define MIMEMULTIPART_H + +#include "mimepart.h" + +class MimeMultiPart : public MimePart +{ + Q_OBJECT +public: + enum MultiPartType { + Mixed = 0, // RFC 2046, section 5.1.3 + Digest = 1, // RFC 2046, section 5.1.5 + Alternative = 2, // RFC 2046, section 5.1.4 + Related = 3, // RFC 2387 + Report = 4, // RFC 6522 + Signed = 5, // RFC 1847, section 2.1 + Encrypted = 6 // RFC 1847, section 2.2 + }; + + MimeMultiPart(const MultiPartType type = Related); + ~MimeMultiPart(); + + void setMimeType(const MultiPartType type); + MultiPartType getMimeType() const; + + const QList &getParts() const; + + void addPart(MimePart *part); + virtual void prepare(); + +protected: + QList parts; + MultiPartType type; + +}; + +#endif // MIMEMULTIPART_H diff --git a/tool/3rd_smtpclient/mimepart.cpp b/tool/3rd_smtpclient/mimepart.cpp new file mode 100644 index 0000000..5bcc457 --- /dev/null +++ b/tool/3rd_smtpclient/mimepart.cpp @@ -0,0 +1,171 @@ +#include "mimepart.h" +#include "quotedprintable.h" + +MimePart::MimePart() +{ + cEncoding = _7Bit; + prepared = false; + cBoundary = ""; +} + +MimePart::~MimePart() +{ + return; +} + +void MimePart::setContent(const QByteArray &content) +{ + this->content = content; +} + +void MimePart::setHeader(const QString &header) +{ + this->header = header; +} + +void MimePart::addHeaderLine(const QString &line) +{ + this->header += line + "\r\n"; +} + +const QString &MimePart::getHeader() const +{ + return header; +} + +const QByteArray &MimePart::getContent() const +{ + return content; +} + +void MimePart::setContentId(const QString &cId) +{ + this->cId = cId; +} + +const QString &MimePart::getContentId() const +{ + return this->cId; +} + +void MimePart::setContentName(const QString &cName) +{ + this->cName = cName; +} + +const QString &MimePart::getContentName() const +{ + return this->cName; +} + +void MimePart::setContentType(const QString &cType) +{ + this->cType = cType; +} + +const QString &MimePart::getContentType() const +{ + return this->cType; +} + +void MimePart::setCharset(const QString &charset) +{ + this->cCharset = charset; +} + +const QString &MimePart::getCharset() const +{ + return this->cCharset; +} + +void MimePart::setEncoding(Encoding enc) +{ + this->cEncoding = enc; +} + +MimePart::Encoding MimePart::getEncoding() const +{ + return this->cEncoding; +} + +MimeContentFormatter &MimePart::getContentFormatter() +{ + return this->formatter; +} + +QString MimePart::toString() +{ + if (!prepared) { + prepare(); + } + + return mimeString; +} + +void MimePart::prepare() +{ + mimeString = QString(); + + mimeString.append("Content-Type: ").append(cType); + + if (cName != "") { + mimeString.append("; name=\"").append(cName).append("\""); + } + + if (cCharset != "") { + mimeString.append("; charset=").append(cCharset); + } + + if (cBoundary != "") { + mimeString.append("; boundary=").append(cBoundary); + } + + mimeString.append("\r\n"); + + mimeString.append("Content-Transfer-Encoding: "); + + switch (cEncoding) { + case _7Bit: + mimeString.append("7bit\r\n"); + break; + + case _8Bit: + mimeString.append("8bit\r\n"); + break; + + case Base64: + mimeString.append("base64\r\n"); + break; + + case QuotedPrintable: + mimeString.append("quoted-printable\r\n"); + break; + } + + if (cId.toInt() != 0) { + mimeString.append("Content-ID: <").append(cId).append(">\r\n"); + } + + mimeString.append(header).append("\r\n"); + + switch (cEncoding) { + case _7Bit: + mimeString.append(QString(content).toLatin1()); + break; + + case _8Bit: + mimeString.append(content); + break; + + case Base64: + mimeString.append(formatter.format(content.toBase64())); + break; + + case QuotedPrintable: + mimeString.append(formatter.format(QuotedPrintable::encode(content), true)); + break; + } + + mimeString.append("\r\n"); + prepared = true; +} diff --git a/tool/3rd_smtpclient/mimepart.h b/tool/3rd_smtpclient/mimepart.h new file mode 100644 index 0000000..496f645 --- /dev/null +++ b/tool/3rd_smtpclient/mimepart.h @@ -0,0 +1,67 @@ +#ifndef MIMEPART_H +#define MIMEPART_H + +#include +#include "mimecontentformatter.h" + +class MimePart : public QObject +{ + Q_OBJECT +public: + enum Encoding { + _7Bit, + _8Bit, + Base64, + QuotedPrintable + }; + + MimePart(); + ~MimePart(); + + const QString &getHeader() const; + const QByteArray &getContent() const; + + void setContent(const QByteArray &content); + void setHeader(const QString &header); + + void addHeaderLine(const QString &line); + + void setContentId(const QString &cId); + const QString &getContentId() const; + + void setContentName(const QString &cName); + const QString &getContentName() const; + + void setContentType(const QString &cType); + const QString &getContentType() const; + + void setCharset(const QString &charset); + const QString &getCharset() const; + + void setEncoding(Encoding enc); + Encoding getEncoding() const; + + MimeContentFormatter &getContentFormatter(); + + virtual QString toString(); + virtual void prepare(); + +protected: + QString header; + QByteArray content; + + QString cId; + QString cName; + QString cType; + QString cCharset; + QString cBoundary; + Encoding cEncoding; + + QString mimeString; + bool prepared; + + MimeContentFormatter formatter; + +}; + +#endif // MIMEPART_H diff --git a/tool/3rd_smtpclient/mimetext.cpp b/tool/3rd_smtpclient/mimetext.cpp new file mode 100644 index 0000000..f1161e9 --- /dev/null +++ b/tool/3rd_smtpclient/mimetext.cpp @@ -0,0 +1,28 @@ +#include "mimetext.h" + +MimeText::MimeText(const QString &txt) +{ + this->text = txt; + this->cType = "text/plain"; + this->cCharset = "utf-8"; + this->cEncoding = _8Bit; +} + +MimeText::~MimeText() { } + +void MimeText::setText(const QString &text) +{ + this->text = text; +} + +const QString &MimeText::getText() const +{ + return text; +} + +void MimeText::prepare() +{ + this->content.clear(); + this->content.append(text.toUtf8()); + MimePart::prepare(); +} diff --git a/tool/3rd_smtpclient/mimetext.h b/tool/3rd_smtpclient/mimetext.h new file mode 100644 index 0000000..f1e9fbc --- /dev/null +++ b/tool/3rd_smtpclient/mimetext.h @@ -0,0 +1,22 @@ +#ifndef MIMETEXT_H +#define MIMETEXT_H + +#include "mimepart.h" + +class MimeText : public MimePart +{ +public: + + MimeText(const QString &text = ""); + ~MimeText(); + + void setText(const QString &text); + const QString &getText() const; + +protected: + QString text; + void prepare(); + +}; + +#endif // MIMETEXT_H diff --git a/tool/3rd_smtpclient/quotedprintable.cpp b/tool/3rd_smtpclient/quotedprintable.cpp new file mode 100644 index 0000000..6d88fcc --- /dev/null +++ b/tool/3rd_smtpclient/quotedprintable.cpp @@ -0,0 +1,43 @@ +#include "quotedprintable.h" + +QString &QuotedPrintable::encode(const QByteArray &input) +{ + QString *output = new QString(); + + char byte; + const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + for (int i = 0; i < input.length() ; ++i) { + byte = input.at(i); + + if ((byte == 0x20) || ((byte >= 33) && (byte <= 126) && (byte != 61))) { + output->append(byte); + } else { + output->append('='); + output->append(hex[((byte >> 4) & 0x0F)]); + output->append(hex[(byte & 0x0F)]); + } + } + + return *output; +} + + +QByteArray &QuotedPrintable::decode(const QString &input) +{ + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F + const int hexVal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15}; + + QByteArray *output = new QByteArray(); + + for (int i = 0; i < input.length(); ++i) { + if (input.at(i).toLatin1() == '=') { + int index = ++i; + output->append((hexVal[input.at(index).toLatin1() - '0'] << 4) + hexVal[input.at(++i).toLatin1() - '0']); + } else { + output->append(input.at(i).toLatin1()); + } + } + + return *output; +} diff --git a/tool/3rd_smtpclient/quotedprintable.h b/tool/3rd_smtpclient/quotedprintable.h new file mode 100644 index 0000000..e295628 --- /dev/null +++ b/tool/3rd_smtpclient/quotedprintable.h @@ -0,0 +1,19 @@ +#ifndef QUOTEDPRINTABLE_H +#define QUOTEDPRINTABLE_H + +#include +#include + +class QuotedPrintable : public QObject +{ + Q_OBJECT +public: + + static QString &encode(const QByteArray &input); + static QByteArray &decode(const QString &input); + +private: + QuotedPrintable(); +}; + +#endif // QUOTEDPRINTABLE_H diff --git a/tool/3rd_smtpclient/smtpclient.cpp b/tool/3rd_smtpclient/smtpclient.cpp new file mode 100644 index 0000000..886c1b9 --- /dev/null +++ b/tool/3rd_smtpclient/smtpclient.cpp @@ -0,0 +1,390 @@ +#include "smtpclient.h" + +SmtpClient::SmtpClient(const QString &host, int port, ConnectionType connectionType) : + name("localhost"), + authMethod(AuthPlain), + connectionTimeout(5000), + responseTimeout(5000) +{ + setConnectionType(connectionType); + + this->host = host; + this->port = port; +} + +SmtpClient::~SmtpClient() {} + +void SmtpClient::setUser(const QString &user) +{ + this->user = user; +} + +void SmtpClient::setPassword(const QString &password) +{ + this->password = password; +} + +void SmtpClient::setAuthMethod(AuthMethod method) +{ + this->authMethod = method; +} + +void SmtpClient::setHost(QString &host) +{ + this->host = host; +} + +void SmtpClient::setPort(int port) +{ + this->port = port; +} + +void SmtpClient::setConnectionType(ConnectionType ct) +{ + this->connectionType = ct; + + switch (connectionType) { + case TcpConnection: + socket = new QTcpSocket(this); + break; +#ifdef ssl + case SslConnection: + case TlsConnection: + socket = new QSslSocket(this); +#endif + } +} + +const QString &SmtpClient::getHost() const +{ + return this->host; +} + +const QString &SmtpClient::getUser() const +{ + return this->user; +} + +const QString &SmtpClient::getPassword() const +{ + return this->password; +} + +SmtpClient::AuthMethod SmtpClient::getAuthMethod() const +{ + return this->authMethod; +} + +int SmtpClient::getPort() const +{ + return this->port; +} + +SmtpClient::ConnectionType SmtpClient::getConnectionType() const +{ + return connectionType; +} + +const QString &SmtpClient::getName() const +{ + return this->name; +} + +void SmtpClient::setName(const QString &name) +{ + this->name = name; +} + +const QString &SmtpClient::getResponseText() const +{ + return responseText; +} + +int SmtpClient::getResponseCode() const +{ + return responseCode; +} + +QTcpSocket *SmtpClient::getSocket() +{ + return socket; +} + +int SmtpClient::getConnectionTimeout() const +{ + return connectionTimeout; +} + +void SmtpClient::setConnectionTimeout(int msec) +{ + connectionTimeout = msec; +} + +int SmtpClient::getResponseTimeout() const +{ + return responseTimeout; +} + +void SmtpClient::setResponseTimeout(int msec) +{ + responseTimeout = msec; +} + +bool SmtpClient::connectToHost() +{ + switch (connectionType) { + case TlsConnection: + case TcpConnection: + socket->connectToHost(host, port); + break; +#ifdef ssl + case SslConnection: + ((QSslSocket *) socket)->connectToHostEncrypted(host, port); + break; +#endif + } + + if (!socket->waitForConnected(connectionTimeout)) { + emit smtpError(ConnectionTimeoutError); + return false; + } + + try { + // Wait for the server's response + waitForResponse(); + + // If the response code is not 220 (Service ready) + // means that is something wrong with the server + if (responseCode != 220) { + emit smtpError(ServerError); + return false; + } + + // Send a EHLO/HELO message to the server + // The client's first command must be EHLO/HELO + sendMessage("EHLO " + name); + + // Wait for the server's response + waitForResponse(); + + // The response code needs to be 250. + if (responseCode != 250) { + emit smtpError(ServerError); + return false; + } + + if (connectionType == TlsConnection) { + // send a request to start TLS handshake + sendMessage("STARTTLS"); + + // Wait for the server's response + waitForResponse(); + + // The response code needs to be 220. + if (responseCode != 220) { + emit smtpError(ServerError); + return false; + }; +#ifdef ssl + ((QSslSocket *) socket)->startClientEncryption(); + if (!((QSslSocket *) socket)->waitForEncrypted(connectionTimeout)) { + qDebug() << ((QSslSocket *) socket)->errorString(); + emit smtpError(ConnectionTimeoutError); + return false; + } +#endif + // Send ELHO one more time + sendMessage("EHLO " + name); + + // Wait for the server's response + waitForResponse(); + + // The response code needs to be 250. + if (responseCode != 250) { + emit smtpError(ServerError); + return false; + } + } + } catch (ResponseTimeoutException) { + return false; + } + + return true; +} + +bool SmtpClient::login() +{ + return login(user, password, authMethod); +} + +bool SmtpClient::login(const QString &user, const QString &password, AuthMethod method) +{ + try { + if (method == AuthPlain) { + // Sending command: AUTH PLAIN base64('\0' + username + '\0' + password) + sendMessage("AUTH PLAIN " + QByteArray().append((char) 0).append(user.toUtf8()).append((char) 0).append(password.toUtf8()).toBase64()); + + // Wait for the server's response + waitForResponse(); + + // If the response is not 235 then the authentication was faild + if (responseCode != 235) { + emit smtpError(AuthenticationFailedError); + return false; + } + } else if (method == AuthLogin) { + // Sending command: AUTH LOGIN + sendMessage("AUTH LOGIN"); + + // Wait for 334 response code + waitForResponse(); + + if (responseCode != 334) { + emit smtpError(AuthenticationFailedError); + return false; + } + + // Send the username in base64 + sendMessage(QByteArray().append(user.toUtf8()).toBase64()); + + // Wait for 334 + waitForResponse(); + + if (responseCode != 334) { + emit smtpError(AuthenticationFailedError); + return false; + } + + // Send the password in base64 + sendMessage(QByteArray().append(password.toUtf8()).toBase64()); + + // Wait for the server's responce + waitForResponse(); + + // If the response is not 235 then the authentication was faild + if (responseCode != 235) { + emit smtpError(AuthenticationFailedError); + return false; + } + } + } catch (ResponseTimeoutException e) { + // Responce Timeout exceeded + emit smtpError(AuthenticationFailedError); + return false; + } + + return true; +} + +bool SmtpClient::sendMail(MimeMessage &email) +{ + try { + // Send the MAIL command with the sender + sendMessage("MAIL FROM: <" + email.getSender().getAddress() + ">"); + + waitForResponse(); + + if (responseCode != 250) { + return false; + } + + // Send RCPT command for each recipient + QList::const_iterator it, itEnd; + + // To (primary recipients) + for (it = email.getRecipients().begin(), itEnd = email.getRecipients().end(); + it != itEnd; ++it) { + sendMessage("RCPT TO: <" + (*it)->getAddress() + ">"); + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } + + // Cc (carbon copy) + for (it = email.getRecipients(MimeMessage::Cc).begin(), itEnd = email.getRecipients(MimeMessage::Cc).end(); + it != itEnd; ++it) { + sendMessage("RCPT TO: <" + (*it)->getAddress() + ">"); + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } + + // Bcc (blind carbon copy) + for (it = email.getRecipients(MimeMessage::Bcc).begin(), itEnd = email.getRecipients(MimeMessage::Bcc).end(); + it != itEnd; ++it) { + sendMessage("RCPT TO: <" + (*it)->getAddress() + ">"); + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } + + // Send DATA command + sendMessage("DATA"); + waitForResponse(); + + if (responseCode != 354) { + return false; + } + + sendMessage(email.toString()); + + // Send \r\n.\r\n to end the mail data + sendMessage("."); + + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } catch (ResponseTimeoutException) { + return false; + } + + return true; +} + +void SmtpClient::quit() +{ + sendMessage("QUIT"); +} + +void SmtpClient::waitForResponse() +{ + do { + if (!socket->waitForReadyRead(responseTimeout)) { + emit smtpError(ResponseTimeoutError); + throw ResponseTimeoutException(); + } + + while (socket->canReadLine()) { + // Save the server's response + responseText = socket->readLine(); + + // Extract the respose code from the server's responce (first 3 digits) + responseCode = responseText.left(3).toInt(); + + if (responseCode / 100 == 4) { + emit smtpError(ServerError); + } + + if (responseCode / 100 == 5) { + emit smtpError(ClientError); + } + + if (responseText.at(3) == ' ') { + return; + } + } + } while (true); +} + +void SmtpClient::sendMessage(const QString &text) +{ + socket->write(text.toUtf8() + "\r\n"); +} diff --git a/tool/3rd_smtpclient/smtpclient.h b/tool/3rd_smtpclient/smtpclient.h new file mode 100644 index 0000000..1c3b097 --- /dev/null +++ b/tool/3rd_smtpclient/smtpclient.h @@ -0,0 +1,103 @@ +#ifndef SMTPCLIENT_H +#define SMTPCLIENT_H + +#include +#include +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) +#include +#endif +#include "mimemessage.h" + +class SmtpClient : public QObject +{ + Q_OBJECT +public: + enum AuthMethod { + AuthPlain, + AuthLogin + }; + + enum SmtpError { + ConnectionTimeoutError, + ResponseTimeoutError, + AuthenticationFailedError, + ServerError, // 4xx smtp error + ClientError // 5xx smtp error + }; + + enum ConnectionType { + TcpConnection, + SslConnection, + TlsConnection // STARTTLS + }; + + SmtpClient(const QString &host = "locahost", int port = 25, ConnectionType ct = TcpConnection); + + ~SmtpClient(); + + const QString &getHost() const; + void setHost(QString &host); + + int getPort() const; + void setPort(int port); + + const QString &getName() const; + void setName(const QString &name); + + ConnectionType getConnectionType() const; + void setConnectionType(ConnectionType ct); + + const QString &getUser() const; + void setUser(const QString &host); + + const QString &getPassword() const; + void setPassword(const QString &password); + + SmtpClient::AuthMethod getAuthMethod() const; + void setAuthMethod(AuthMethod method); + + const QString &getResponseText() const; + int getResponseCode() const; + + int getConnectionTimeout() const; + void setConnectionTimeout(int msec); + + int getResponseTimeout() const; + void setResponseTimeout(int msec); + + QTcpSocket *getSocket(); + + bool connectToHost(); + bool login(); + bool login(const QString &user, const QString &password, AuthMethod method = AuthLogin); + + bool sendMail(MimeMessage &email); + void quit(); + +protected: + QTcpSocket *socket; + QString host; + int port; + ConnectionType connectionType; + QString name; + + QString user; + QString password; + AuthMethod authMethod; + + int connectionTimeout; + int responseTimeout; + + QString responseText; + int responseCode; + + class ResponseTimeoutException {}; + void waitForResponse(); + void sendMessage(const QString &text); + +signals: + void smtpError(SmtpError e); + +}; + +#endif // SMTPCLIENT_H diff --git a/tool/3rd_smtpclient/smtpmime.h b/tool/3rd_smtpclient/smtpmime.h new file mode 100644 index 0000000..fe782aa --- /dev/null +++ b/tool/3rd_smtpclient/smtpmime.h @@ -0,0 +1,13 @@ +#ifndef SMTPMIME_H +#define SMTPMIME_H + +#include "smtpclient.h" +#include "mimepart.h" +#include "mimehtml.h" +#include "mimeattachment.h" +#include "mimemessage.h" +#include "mimetext.h" +#include "mimeinlinefile.h" +#include "mimefile.h" + +#endif // SMTPMIME_H diff --git a/tool/base64helper/base64helper.cpp b/tool/base64helper/base64helper.cpp new file mode 100644 index 0000000..e294fcd --- /dev/null +++ b/tool/base64helper/base64helper.cpp @@ -0,0 +1,41 @@ +#include "base64helper.h" +#include "qbuffer.h" +#include "qdebug.h" + +QString Base64Helper::imageToBase64(const QImage &image) +{ + return QString(imageToBase64x(image)); +} + +QByteArray Base64Helper::imageToBase64x(const QImage &image) +{ + //这个转换可能比较耗时建议在线程中执行 + QByteArray data; + QBuffer buffer(&data); + image.save(&buffer, "JPG"); + data = data.toBase64(); + return data; +} + +QImage Base64Helper::base64ToImage(const QString &data) +{ + return base64ToImagex(data.toUtf8()); +} + +QImage Base64Helper::base64ToImagex(const QByteArray &data) +{ + //这个转换可能比较耗时建议在线程中执行 + QImage image; + image.loadFromData(QByteArray::fromBase64(data)); + return image; +} + +QString Base64Helper::textToBase64(const QString &text) +{ + return QString(text.toUtf8().toBase64()); +} + +QString Base64Helper::base64ToText(const QString &text) +{ + return QString(QByteArray::fromBase64(text.toUtf8())); +} diff --git a/tool/base64helper/base64helper.h b/tool/base64helper/base64helper.h new file mode 100644 index 0000000..e17cae6 --- /dev/null +++ b/tool/base64helper/base64helper.h @@ -0,0 +1,37 @@ +#ifndef BASE64HELPER_H +#define BASE64HELPER_H + +/** + * base64编码转换类 作者:feiyangqingyun(QQ:517216493) 2016-12-16 + * 1. 图片转base64字符串。 + * 2. base64字符串转图片。 + * 3. 字符转base64字符串。 + * 4. base64字符串转字符。 + * 5. 后期增加数据压缩。 + * 6. Qt6对base64编码转换进行了重写效率提升至少200%。 + */ + +#include + +#ifdef quc +class Q_DECL_EXPORT Base64Helper +#else +class Base64Helper +#endif + +{ +public: + //图片转base64字符串 + static QString imageToBase64(const QImage &image); + static QByteArray imageToBase64x(const QImage &image); + + //base64字符串转图片 + static QImage base64ToImage(const QString &data); + static QImage base64ToImagex(const QByteArray &data); + + //字符串与base64互转 + static QString textToBase64(const QString &text); + static QString base64ToText(const QString &text); +}; + +#endif // BASE64HELPER_H diff --git a/tool/base64helper/base64helper.pro b/tool/base64helper/base64helper.pro new file mode 100644 index 0000000..4a0a580 --- /dev/null +++ b/tool/base64helper/base64helper.pro @@ -0,0 +1,19 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = base64helper +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp + +SOURCES += frmbase64helper.cpp +SOURCES += base64helper.cpp + +HEADERS += frmbase64helper.h +HEADERS += base64helper.h + +FORMS += frmbase64helper.ui + diff --git a/tool/base64helper/frmbase64helper.cpp b/tool/base64helper/frmbase64helper.cpp new file mode 100644 index 0000000..3769725 --- /dev/null +++ b/tool/base64helper/frmbase64helper.cpp @@ -0,0 +1,104 @@ +#pragma execution_character_set("utf-8") + +#include "frmbase64helper.h" +#include "ui_frmbase64helper.h" +#include "base64helper.h" +#include "qfiledialog.h" +#include "qdebug.h" + +frmBase64Helper::frmBase64Helper(QWidget *parent) : QWidget(parent), ui(new Ui::frmBase64Helper) +{ + ui->setupUi(this); +} + +frmBase64Helper::~frmBase64Helper() +{ + delete ui; +} + +void frmBase64Helper::showTime(qint64 size1, qint64 size2) +{ + //统计用时 +#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0)) + double elapsed = (double)timer.nsecsElapsed() / 1000000; +#else + double elapsed = (double)timer.elapsed(); +#endif + QString time = QString::number(elapsed, 'f', 3); + ui->labInfo->setText(QString("用时: %1 毫秒 大小: %2 -> %3").arg(time).arg(size1).arg(size2)); +} + +void frmBase64Helper::on_btnOpen_clicked() +{ + QString fileName = QFileDialog::getOpenFileName(this, "选择文件", "", "图片(*.png *.bmp *.jpg)"); + if (!fileName.isEmpty()) { + ui->txtFile->setText(fileName); + QPixmap pix(fileName); + pix = pix.scaled(ui->labImage->size() - QSize(4, 4), Qt::KeepAspectRatio); + ui->labImage->setPixmap(pix); + } +} + +void frmBase64Helper::on_btnClear_clicked() +{ + ui->txtFile->clear(); + ui->txtText->clear(); + ui->txtBase64->clear(); + ui->labImage->clear(); +} + +void frmBase64Helper::on_btnImageToBase64_clicked() +{ + QString fileName = ui->txtFile->text().trimmed(); + if (fileName.isEmpty()) { + return; + } + + timer.restart(); + QImage image(fileName); + QString text = Base64Helper::imageToBase64(image); + showTime(QFile(fileName).size(), text.size()); + ui->txtBase64->setText(text); +} + +void frmBase64Helper::on_btnBase64ToImage_clicked() +{ + QString fileName = ui->txtFile->text().trimmed(); + QString text = ui->txtBase64->toPlainText().trimmed(); + if (text.isEmpty()) { + return; + } + + timer.restart(); + QImage image = Base64Helper::base64ToImage(text); + showTime(text.size(), QFile(fileName).size()); + QPixmap pix = QPixmap::fromImage(image); + pix = pix.scaled(ui->labImage->size() - QSize(4, 4), Qt::KeepAspectRatio); + ui->labImage->setPixmap(pix); +} + +void frmBase64Helper::on_btnTextToBase64_clicked() +{ + QString text = ui->txtText->text().trimmed(); + if (text.isEmpty()) { + return; + } + + timer.restart(); + QString result = Base64Helper::textToBase64(text); + showTime(text.size(), result.size()); + ui->txtBase64->setText(result); +} + +void frmBase64Helper::on_btnBase64ToText_clicked() +{ + QString text = ui->txtBase64->toPlainText().trimmed(); + if (text.isEmpty()) { + return; + } + + timer.restart(); + QString result = Base64Helper::base64ToText(text); + showTime(text.size(), result.size()); + ui->txtText->setText(result); +} diff --git a/tool/base64helper/frmbase64helper.h b/tool/base64helper/frmbase64helper.h new file mode 100644 index 0000000..3477f73 --- /dev/null +++ b/tool/base64helper/frmbase64helper.h @@ -0,0 +1,35 @@ +#ifndef FRMBASE64HELPER_H +#define FRMBASE64HELPER_H + +#include +#include + +namespace Ui { +class frmBase64Helper; +} + +class frmBase64Helper : public QWidget +{ + Q_OBJECT + +public: + explicit frmBase64Helper(QWidget *parent = 0); + ~frmBase64Helper(); + +private: + Ui::frmBase64Helper *ui; + QElapsedTimer timer; + +private slots: + void showTime(qint64 size1, qint64 size2); + void on_btnOpen_clicked(); + void on_btnClear_clicked(); + + void on_btnImageToBase64_clicked(); + void on_btnBase64ToImage_clicked(); + + void on_btnTextToBase64_clicked(); + void on_btnBase64ToText_clicked(); +}; + +#endif // FRMBASE64HELPER_H diff --git a/tool/base64helper/frmbase64helper.ui b/tool/base64helper/frmbase64helper.ui new file mode 100644 index 0000000..d23b970 --- /dev/null +++ b/tool/base64helper/frmbase64helper.ui @@ -0,0 +1,163 @@ + + + frmBase64Helper + + + + 0 + 0 + 800 + 600 + + + + Widget + + + + + + E:/myFile/美女图片/2.jpg + + + + + + + + 120 + 0 + + + + 打开文件 + + + + + + + + 120 + 0 + + + + 图片转base64 + + + + + + + + 120 + 0 + + + + base64转图片 + + + + + + + 游龙 feiyangqingyun QQ: 517216493 + + + + + + + + 120 + 0 + + + + 清空数据 + + + + + + + + 120 + 0 + + + + 文字转base64 + + + + + + + + 120 + 0 + + + + base64转文字 + + + + + + + QFrame::Box + + + QFrame::Sunken + + + + + + + + + + + 0 + 0 + + + + QFrame::Box + + + QFrame::Sunken + + + + + + Qt::AlignCenter + + + + + + + + + + + txtFile + txtText + btnOpen + btnClear + btnImageToBase64 + btnBase64ToImage + btnTextToBase64 + btnBase64ToText + txtBase64 + + + + diff --git a/tool/base64helper/main.cpp b/tool/base64helper/main.cpp new file mode 100644 index 0000000..fc0e953 --- /dev/null +++ b/tool/base64helper/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") + +#include "frmbase64helper.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmBase64Helper w; + w.setWindowTitle("图片文字base64编码互换 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/bin/base64helper.exe b/tool/bin/base64helper.exe new file mode 100644 index 0000000..a11067a Binary files /dev/null and b/tool/bin/base64helper.exe differ diff --git a/tool/bin/base64helper.ilk b/tool/bin/base64helper.ilk new file mode 100644 index 0000000..25c44d9 Binary files /dev/null and b/tool/bin/base64helper.ilk differ diff --git a/tool/bin/base64helper.pdb b/tool/bin/base64helper.pdb new file mode 100644 index 0000000..099cbee Binary files /dev/null and b/tool/bin/base64helper.pdb differ diff --git a/tool/bin/comtool.exe b/tool/bin/comtool.exe new file mode 100644 index 0000000..8a2f896 Binary files /dev/null and b/tool/bin/comtool.exe differ diff --git a/tool/bin/comtool.ilk b/tool/bin/comtool.ilk new file mode 100644 index 0000000..a6ba628 Binary files /dev/null and b/tool/bin/comtool.ilk differ diff --git a/tool/bin/comtool.ini b/tool/bin/comtool.ini new file mode 100644 index 0000000..d3b8abe --- /dev/null +++ b/tool/bin/comtool.ini @@ -0,0 +1,22 @@ +[ComConfig] +PortName=COM1 +BaudRate=9600 +DataBit=8 +Parity=\x65e0 +StopBit=1 +HexSend=false +HexReceive=false +Debug=false +AutoClear=false +AutoSend=false +SendInterval=1000 +AutoSave=false +SaveInterval=5000 + +[NetConfig] +Mode=Tcp_Client +ServerIP=127.0.0.1 +ServerPort=6000 +ListenPort=6000 +SleepTime=100 +AutoConnect=false diff --git a/tool/bin/comtool.pdb b/tool/bin/comtool.pdb new file mode 100644 index 0000000..13b2cf8 Binary files /dev/null and b/tool/bin/comtool.pdb differ diff --git a/tool/bin/countcode.exe b/tool/bin/countcode.exe new file mode 100644 index 0000000..3d21e7d Binary files /dev/null and b/tool/bin/countcode.exe differ diff --git a/tool/bin/countcode.ilk b/tool/bin/countcode.ilk new file mode 100644 index 0000000..1d51e47 Binary files /dev/null and b/tool/bin/countcode.ilk differ diff --git a/tool/bin/countcode.pdb b/tool/bin/countcode.pdb new file mode 100644 index 0000000..b5a9273 Binary files /dev/null and b/tool/bin/countcode.pdb differ diff --git a/tool/bin/emailtool.exe b/tool/bin/emailtool.exe new file mode 100644 index 0000000..c96cb49 Binary files /dev/null and b/tool/bin/emailtool.exe differ diff --git a/tool/bin/emailtool.ilk b/tool/bin/emailtool.ilk new file mode 100644 index 0000000..66c10fc Binary files /dev/null and b/tool/bin/emailtool.ilk differ diff --git a/tool/bin/emailtool.pdb b/tool/bin/emailtool.pdb new file mode 100644 index 0000000..b6e73aa Binary files /dev/null and b/tool/bin/emailtool.pdb differ diff --git a/tool/bin/keydemo.exe b/tool/bin/keydemo.exe new file mode 100644 index 0000000..cb99680 Binary files /dev/null and b/tool/bin/keydemo.exe differ diff --git a/tool/bin/keydemo.ilk b/tool/bin/keydemo.ilk new file mode 100644 index 0000000..cf2d357 Binary files /dev/null and b/tool/bin/keydemo.ilk differ diff --git a/tool/bin/keydemo.pdb b/tool/bin/keydemo.pdb new file mode 100644 index 0000000..4e419dd Binary files /dev/null and b/tool/bin/keydemo.pdb differ diff --git a/tool/bin/keytool.exe b/tool/bin/keytool.exe new file mode 100644 index 0000000..d420afd Binary files /dev/null and b/tool/bin/keytool.exe differ diff --git a/tool/bin/keytool.ilk b/tool/bin/keytool.ilk new file mode 100644 index 0000000..1cf8259 Binary files /dev/null and b/tool/bin/keytool.ilk differ diff --git a/tool/bin/keytool.pdb b/tool/bin/keytool.pdb new file mode 100644 index 0000000..ac7350f Binary files /dev/null and b/tool/bin/keytool.pdb differ diff --git a/tool/bin/livedemo.exe b/tool/bin/livedemo.exe new file mode 100644 index 0000000..21d4ba6 Binary files /dev/null and b/tool/bin/livedemo.exe differ diff --git a/tool/bin/livedemo.ilk b/tool/bin/livedemo.ilk new file mode 100644 index 0000000..f078a86 Binary files /dev/null and b/tool/bin/livedemo.ilk differ diff --git a/tool/bin/livedemo.pdb b/tool/bin/livedemo.pdb new file mode 100644 index 0000000..e6b5912 Binary files /dev/null and b/tool/bin/livedemo.pdb differ diff --git a/tool/bin/livetool.exe b/tool/bin/livetool.exe new file mode 100644 index 0000000..ea656e1 Binary files /dev/null and b/tool/bin/livetool.exe differ diff --git a/tool/bin/livetool.ilk b/tool/bin/livetool.ilk new file mode 100644 index 0000000..4e58099 Binary files /dev/null and b/tool/bin/livetool.ilk differ diff --git a/tool/bin/livetool.pdb b/tool/bin/livetool.pdb new file mode 100644 index 0000000..193bb73 Binary files /dev/null and b/tool/bin/livetool.pdb differ diff --git a/tool/bin/moneytool.exe b/tool/bin/moneytool.exe new file mode 100644 index 0000000..f63b9c1 Binary files /dev/null and b/tool/bin/moneytool.exe differ diff --git a/tool/bin/moneytool.ilk b/tool/bin/moneytool.ilk new file mode 100644 index 0000000..f7e5216 Binary files /dev/null and b/tool/bin/moneytool.ilk differ diff --git a/tool/bin/moneytool.pdb b/tool/bin/moneytool.pdb new file mode 100644 index 0000000..674253d Binary files /dev/null and b/tool/bin/moneytool.pdb differ diff --git a/tool/bin/netserver.exe b/tool/bin/netserver.exe new file mode 100644 index 0000000..e3d23c3 Binary files /dev/null and b/tool/bin/netserver.exe differ diff --git a/tool/bin/netserver.ilk b/tool/bin/netserver.ilk new file mode 100644 index 0000000..edb1381 Binary files /dev/null and b/tool/bin/netserver.ilk differ diff --git a/tool/bin/netserver.pdb b/tool/bin/netserver.pdb new file mode 100644 index 0000000..1202453 Binary files /dev/null and b/tool/bin/netserver.pdb differ diff --git a/tool/bin/nettool.exe b/tool/bin/nettool.exe new file mode 100644 index 0000000..c2e709b Binary files /dev/null and b/tool/bin/nettool.exe differ diff --git a/tool/bin/nettool.ilk b/tool/bin/nettool.ilk new file mode 100644 index 0000000..5af41b2 Binary files /dev/null and b/tool/bin/nettool.ilk differ diff --git a/tool/bin/nettool.pdb b/tool/bin/nettool.pdb new file mode 100644 index 0000000..d3a71f4 Binary files /dev/null and b/tool/bin/nettool.pdb differ diff --git a/tool/bin/pngtool.exe b/tool/bin/pngtool.exe new file mode 100644 index 0000000..c01eaf8 Binary files /dev/null and b/tool/bin/pngtool.exe differ diff --git a/tool/bin/pngtool.ilk b/tool/bin/pngtool.ilk new file mode 100644 index 0000000..d317754 Binary files /dev/null and b/tool/bin/pngtool.ilk differ diff --git a/tool/bin/pngtool.pdb b/tool/bin/pngtool.pdb new file mode 100644 index 0000000..8323aed Binary files /dev/null and b/tool/bin/pngtool.pdb differ diff --git a/tool/comtool/api/api.pri b/tool/comtool/api/api.pri new file mode 100644 index 0000000..510574e --- /dev/null +++ b/tool/comtool/api/api.pri @@ -0,0 +1,11 @@ +HEADERS += \ + $$PWD/appconfig.h \ + $$PWD/appdata.h \ + $$PWD/qthelper.h \ + $$PWD/qthelperdata.h + +SOURCES += \ + $$PWD/appconfig.cpp \ + $$PWD/appdata.cpp \ + $$PWD/qthelper.cpp \ + $$PWD/qthelperdata.cpp diff --git a/tool/comtool/api/appconfig.cpp b/tool/comtool/api/appconfig.cpp new file mode 100644 index 0000000..5cd4e8e --- /dev/null +++ b/tool/comtool/api/appconfig.cpp @@ -0,0 +1,99 @@ +#include "appconfig.h" +#include "qthelper.h" + +QString AppConfig::ConfigFile = "config.ini"; +QString AppConfig::SendFileName = "send.txt"; +QString AppConfig::DeviceFileName = "device.txt"; + +QString AppConfig::PortName = "COM1"; +int AppConfig::BaudRate = 9600; +int AppConfig::DataBit = 8; +QString AppConfig::Parity = QString::fromUtf8("无"); +double AppConfig::StopBit = 1; + +bool AppConfig::HexSend = false; +bool AppConfig::HexReceive = false; +bool AppConfig::Debug = false; +bool AppConfig::AutoClear = false; + +bool AppConfig::AutoSend = false; +int AppConfig::SendInterval = 1000; +bool AppConfig::AutoSave = false; +int AppConfig::SaveInterval = 5000; + +QString AppConfig::Mode = "Tcp_Client"; +QString AppConfig::ServerIP = "127.0.0.1"; +int AppConfig::ServerPort = 6000; +int AppConfig::ListenPort = 6000; +int AppConfig::SleepTime = 100; +bool AppConfig::AutoConnect = false; + +void AppConfig::readConfig() +{ + QSettings set(AppConfig::ConfigFile, QSettings::IniFormat); + + set.beginGroup("ComConfig"); + AppConfig::PortName = set.value("PortName", AppConfig::PortName).toString(); + AppConfig::BaudRate = set.value("BaudRate", AppConfig::BaudRate).toInt(); + AppConfig::DataBit = set.value("DataBit", AppConfig::DataBit).toInt(); + AppConfig::Parity = set.value("Parity", AppConfig::Parity).toString(); + AppConfig::StopBit = set.value("StopBit", AppConfig::StopBit).toInt(); + + AppConfig::HexSend = set.value("HexSend", AppConfig::HexSend).toBool(); + AppConfig::HexReceive = set.value("HexReceive", AppConfig::HexReceive).toBool(); + AppConfig::Debug = set.value("Debug", AppConfig::Debug).toBool(); + AppConfig::AutoClear = set.value("AutoClear", AppConfig::AutoClear).toBool(); + + AppConfig::AutoSend = set.value("AutoSend", AppConfig::AutoSend).toBool(); + AppConfig::SendInterval = set.value("SendInterval", AppConfig::SendInterval).toInt(); + AppConfig::AutoSave = set.value("AutoSave", AppConfig::AutoSave).toBool(); + AppConfig::SaveInterval = set.value("SaveInterval", AppConfig::SaveInterval).toInt(); + set.endGroup(); + + set.beginGroup("NetConfig"); + AppConfig::Mode = set.value("Mode", AppConfig::Mode).toString(); + AppConfig::ServerIP = set.value("ServerIP", AppConfig::ServerIP).toString(); + AppConfig::ServerPort = set.value("ServerPort", AppConfig::ServerPort).toInt(); + AppConfig::ListenPort = set.value("ListenPort", AppConfig::ListenPort).toInt(); + AppConfig::SleepTime = set.value("SleepTime", AppConfig::SleepTime).toInt(); + AppConfig::AutoConnect = set.value("AutoConnect", AppConfig::AutoConnect).toBool(); + set.endGroup(); + + //配置文件不存在或者不全则重新生成 + if (!QtHelper::checkIniFile(AppConfig::ConfigFile)) { + writeConfig(); + return; + } +} + +void AppConfig::writeConfig() +{ + QSettings set(AppConfig::ConfigFile, QSettings::IniFormat); + + set.beginGroup("ComConfig"); + set.setValue("PortName", AppConfig::PortName); + set.setValue("BaudRate", AppConfig::BaudRate); + set.setValue("DataBit", AppConfig::DataBit); + set.setValue("Parity", AppConfig::Parity); + set.setValue("StopBit", AppConfig::StopBit); + + set.setValue("HexSend", AppConfig::HexSend); + set.setValue("HexReceive", AppConfig::HexReceive); + set.setValue("Debug", AppConfig::Debug); + set.setValue("AutoClear", AppConfig::AutoClear); + + set.setValue("AutoSend", AppConfig::AutoSend); + set.setValue("SendInterval", AppConfig::SendInterval); + set.setValue("AutoSave", AppConfig::AutoSave); + set.setValue("SaveInterval", AppConfig::SaveInterval); + set.endGroup(); + + set.beginGroup("NetConfig"); + set.setValue("Mode", AppConfig::Mode); + set.setValue("ServerIP", AppConfig::ServerIP); + set.setValue("ServerPort", AppConfig::ServerPort); + set.setValue("ListenPort", AppConfig::ListenPort); + set.setValue("SleepTime", AppConfig::SleepTime); + set.setValue("AutoConnect", AppConfig::AutoConnect); + set.endGroup(); +} diff --git a/tool/comtool/api/appconfig.h b/tool/comtool/api/appconfig.h new file mode 100644 index 0000000..5603bc1 --- /dev/null +++ b/tool/comtool/api/appconfig.h @@ -0,0 +1,41 @@ +#ifndef APPCONFIG_H +#define APPCONFIG_H + +#include "head.h" + +class AppConfig +{ +public: + static QString ConfigFile; //配置文件路径 + static QString SendFileName; //发送配置文件名 + static QString DeviceFileName; //模拟设备数据文件名 + + static QString PortName; //串口号 + static int BaudRate; //波特率 + static int DataBit; //数据位 + static QString Parity; //校验位 + static double StopBit; //停止位 + + static bool HexSend; //16进制发送 + static bool HexReceive; //16进制接收 + static bool Debug; //模拟设备 + static bool AutoClear; //自动清空 + + static bool AutoSend; //自动发送 + static int SendInterval; //自动发送间隔 + static bool AutoSave; //自动保存 + static int SaveInterval; //自动保存间隔 + + static QString Mode; //转换模式 + static QString ServerIP; //服务器IP + static int ServerPort; //服务器端口 + static int ListenPort; //监听端口 + static int SleepTime; //延时时间 + static bool AutoConnect; //自动重连 + + //读写配置参数 + static void readConfig(); //读取配置参数 + static void writeConfig(); //写入配置参数 +}; + +#endif // APPCONFIG_H diff --git a/tool/comtool/api/appdata.cpp b/tool/comtool/api/appdata.cpp new file mode 100644 index 0000000..0d75b48 --- /dev/null +++ b/tool/comtool/api/appdata.cpp @@ -0,0 +1,122 @@ +#include "appdata.h" +#include "qthelper.h" + +QStringList AppData::Intervals = QStringList(); +QStringList AppData::Datas = QStringList(); +QStringList AppData::Keys = QStringList(); +QStringList AppData::Values = QStringList(); + +QString AppData::SendFileName = "send.txt"; +void AppData::readSendData() +{ + //读取发送数据列表 + AppData::Datas.clear(); + QString fileName = QString("%1/%2").arg(QtHelper::appPath()).arg(AppData::SendFileName); + QFile file(fileName); + if (file.size() > 0 && file.open(QFile::ReadOnly | QIODevice::Text)) { + while (!file.atEnd()) { + QString line = file.readLine(); + line = line.trimmed(); + line = line.replace("\r", ""); + line = line.replace("\n", ""); + if (!line.isEmpty()) { + AppData::Datas.append(line); + } + } + + file.close(); + } + + //没有的时候主动添加点免得太空 + if (AppData::Datas.count() == 0) { + AppData::Datas << "16 FF 01 01 E0 E1" << "16 FF 01 01 E1 E2"; + } +} + +QString AppData::DeviceFileName = "device.txt"; +void AppData::readDeviceData() +{ + //读取转发数据列表 + AppData::Keys.clear(); + AppData::Values.clear(); + QString fileName = QString("%1/%2").arg(QtHelper::appPath()).arg(AppData::DeviceFileName); + QFile file(fileName); + if (file.size() > 0 && file.open(QFile::ReadOnly | QIODevice::Text)) { + while (!file.atEnd()) { + QString line = file.readLine(); + line = line.trimmed(); + line = line.replace("\r", ""); + line = line.replace("\n", ""); + if (!line.isEmpty()) { + QStringList list = line.split(";"); + QString key = list.at(0); + QString value; + for (int i = 1; i < list.count(); i++) { + value += QString("%1;").arg(list.at(i)); + } + + //去掉末尾分号 + value = value.mid(0, value.length() - 1); + AppData::Keys.append(key); + AppData::Values.append(value); + } + } + + file.close(); + } +} + +void AppData::saveData(const QString &data) +{ + if (data.length() <= 0) { + return; + } + + QString fileName = QString("%1/%2.txt").arg(QtHelper::appPath()).arg(STRDATETIME); + QFile file(fileName); + if (file.open(QFile::WriteOnly | QFile::Text)) { + file.write(data.toUtf8()); + file.close(); + } +} + +void AppData::loadIP(QComboBox *cbox) +{ + //获取本机所有IP + static QStringList ips; + if (ips.count() == 0) { +#ifdef emsdk + ips << "127.0.0.1"; +#else + QList netInterfaces = QNetworkInterface::allInterfaces(); + foreach (const QNetworkInterface &netInterface, netInterfaces) { + //移除虚拟机和抓包工具的虚拟网卡 + QString humanReadableName = netInterface.humanReadableName().toLower(); + if (humanReadableName.startsWith("vmware network adapter") || humanReadableName.startsWith("npcap loopback adapter")) { + continue; + } + + //过滤当前网络接口 + bool flag = (netInterface.flags() == (QNetworkInterface::IsUp | QNetworkInterface::IsRunning | QNetworkInterface::CanBroadcast | QNetworkInterface::CanMulticast)); + if (flag) { + QList addrs = netInterface.addressEntries(); + foreach (QNetworkAddressEntry addr, addrs) { + //只取出IPV4的地址 + if (addr.ip().protocol() == QAbstractSocket::IPv4Protocol) { + QString ip4 = addr.ip().toString(); + if (ip4 != "127.0.0.1") { + ips << ip4; + } + } + } + } + } +#endif + } + + cbox->clear(); + cbox->addItems(ips); + if (!ips.contains("127.0.0.1")) { + cbox->addItem("127.0.0.1"); + } +} diff --git a/tool/comtool/api/appdata.h b/tool/comtool/api/appdata.h new file mode 100644 index 0000000..13091c7 --- /dev/null +++ b/tool/comtool/api/appdata.h @@ -0,0 +1,30 @@ +#ifndef APPDATA_H +#define APPDATA_H + +#include "head.h" + +class AppData +{ +public: + //全局变量 + static QStringList Intervals; + static QStringList Datas; + static QStringList Keys; + static QStringList Values; + + //读取发送数据列表 + static QString SendFileName; + static void readSendData(); + + //读取转发数据列表 + static QString DeviceFileName; + static void readDeviceData(); + + //保存数据到文件 + static void saveData(const QString &data); + + //添加网卡IP地址到下拉框 + static void loadIP(QComboBox *cbox); +}; + +#endif // APPDATA_H diff --git a/tool/comtool/api/qthelper.cpp b/tool/comtool/api/qthelper.cpp new file mode 100644 index 0000000..1911055 --- /dev/null +++ b/tool/comtool/api/qthelper.cpp @@ -0,0 +1,1234 @@ +#include "qthelper.h" +#include "qnetworkinterface.h" +#include "qnetworkproxy.h" + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +QList QtHelper::getScreenRects(bool available) +{ + QList rects; +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + int screenCount = qApp->screens().count(); + QList screens = qApp->screens(); + for (int i = 0; i < screenCount; ++i) { + QScreen *screen = screens.at(i); + rects << (available ? screen->availableGeometry() : screen->geometry()); + } +#else + int screenCount = qApp->desktop()->screenCount(); + QDesktopWidget *desk = qApp->desktop(); + for (int i = 0; i < screenCount; ++i) { + rects << (available ? desk->availableGeometry(i) : desk->screenGeometry(i)); + } +#endif + return rects; +} + +int QtHelper::getScreenIndex() +{ + //需要对多个屏幕进行处理 + int screenIndex = 0; + QList rects = getScreenRects(false); + int count = rects.count(); + for (int i = 0; i < count; ++i) { + //找到当前鼠标所在屏幕 + QPoint pos = QCursor::pos(); + if (rects.at(i).contains(pos)) { + screenIndex = i; + break; + } + } + + return screenIndex; +} + +QRect QtHelper::getScreenRect(bool available) +{ + int screenIndex = getScreenIndex(); + QList rects = getScreenRects(available); + return rects.at(screenIndex); +} + +qreal QtHelper::getScreenRatio(bool devicePixel) +{ + qreal ratio = 1.0; + int screenIndex = getScreenIndex(); +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + QScreen *screen = qApp->screens().at(screenIndex); + if (devicePixel) { + //需要开启 AA_EnableHighDpiScaling 属性才能正常获取 + ratio = screen->devicePixelRatio() * 100; + } else { + ratio = screen->logicalDotsPerInch(); + } +#else + //Qt4不能动态识别缩放更改后的值 + ratio = qApp->desktop()->screen(screenIndex)->logicalDpiX(); +#endif + return ratio / 96; +} + +QRect QtHelper::checkCenterRect(QRect &rect, bool available) +{ + QRect deskRect = QtHelper::getScreenRect(available); + int formWidth = rect.width(); + int formHeight = rect.height(); + int deskWidth = deskRect.width(); + int deskHeight = deskRect.height(); + int formX = deskWidth / 2 - formWidth / 2 + deskRect.x(); + int formY = deskHeight / 2 - formHeight / 2; + rect = QRect(formX, formY, formWidth, formHeight); + return deskRect; +} + +int QtHelper::deskWidth() +{ + return getScreenRect().width(); +} + +int QtHelper::deskHeight() +{ + return getScreenRect().height(); +} + +QSize QtHelper::deskSize() +{ + return getScreenRect().size(); +} + +QWidget *QtHelper::centerBaseForm = 0; +void QtHelper::setFormInCenter(QWidget *form) +{ + int formWidth = form->width(); + int formHeight = form->height(); + + //如果=0表示采用系统桌面屏幕为参照 + QRect rect; + if (centerBaseForm == 0) { + rect = getScreenRect(); + } else { + rect = centerBaseForm->geometry(); + } + + int deskWidth = rect.width(); + int deskHeight = rect.height(); + QPoint movePoint(deskWidth / 2 - formWidth / 2 + rect.x(), deskHeight / 2 - formHeight / 2 + rect.y()); + form->move(movePoint); +} + +void QtHelper::showForm(QWidget *form) +{ + setFormInCenter(form); + form->show(); + + //判断宽高是否超过了屏幕分辨率,超过了则最大化显示 + //qDebug() << TIMEMS << form->size() << deskSize(); + if (form->width() + 20 > deskWidth() || form->height() + 50 > deskHeight()) { + QMetaObject::invokeMethod(form, "showMaximized", Qt::QueuedConnection); + } +} + +QString QtHelper::appName() +{ + //没有必要每次都获取,只有当变量为空时才去获取一次 + static QString name; + if (name.isEmpty()) { + name = qApp->applicationFilePath(); + //下面的方法主要为了过滤安卓的路径 lib程序名_armeabi-v7a/lib程序名_arm64-v8a + QStringList list = name.split("/"); + name = list.at(list.count() - 1).split(".").at(0); + name.replace("_armeabi-v7a", ""); + name.replace("_arm64-v8a", ""); + } + + return name; +} + +QString QtHelper::appPath() +{ + static QString path; + if (path.isEmpty()) { +#ifdef Q_OS_ANDROID + //默认安卓根目录 + path = "/storage/emulated/0"; + //带上程序名称作为目录 前面加个0方便排序 + path = path + "/0" + appName(); +#else + path = qApp->applicationDirPath(); +#endif + } + + return path; +} + +void QtHelper::getCurrentInfo(char *argv[], QString &path, QString &name) +{ + //必须用fromLocal8Bit保证中文路径正常 + QString argv0 = QString::fromLocal8Bit(argv[0]); + QFileInfo file(argv0); + path = file.path(); + name = file.baseName(); +} + +QString QtHelper::getIniValue(const QString &fileName, const QString &key) +{ + QString value; + QFile file(fileName); + if (file.open(QFile::ReadOnly | QFile::Text)) { + while (!file.atEnd()) { + QString line = file.readLine(); + if (line.startsWith(key)) { + line = line.replace("\n", ""); + line = line.trimmed(); + value = line.split("=").last(); + break; + } + } + } + return value; +} + +QString QtHelper::getIniValue(char *argv[], const QString &key, const QString &dir) +{ + QString path, name; + QtHelper::getCurrentInfo(argv, path, name); + QString fileName = QString("%1/%2%3.ini").arg(path).arg(dir).arg(name); + return getIniValue(fileName, key); +} + +QStringList QtHelper::getLocalIPs() +{ + static QStringList ips; + if (ips.count() == 0) { +#ifdef Q_OS_WASM + ips << "127.0.0.1"; +#else + QList netInterfaces = QNetworkInterface::allInterfaces(); + foreach (QNetworkInterface netInterface, netInterfaces) { + //移除虚拟机和抓包工具的虚拟网卡 + QString humanReadableName = netInterface.humanReadableName().toLower(); + if (humanReadableName.startsWith("vmware network adapter") || humanReadableName.startsWith("npcap loopback adapter")) { + continue; + } + + //过滤当前网络接口 + bool flag = (netInterface.flags() == (QNetworkInterface::IsUp | QNetworkInterface::IsRunning | QNetworkInterface::CanBroadcast | QNetworkInterface::CanMulticast)); + if (!flag) { + continue; + } + + QList addrs = netInterface.addressEntries(); + foreach (QNetworkAddressEntry addr, addrs) { + //只取出IPV4的地址 + if (addr.ip().protocol() != QAbstractSocket::IPv4Protocol) { + continue; + } + + QString ip4 = addr.ip().toString(); + if (ip4 != "127.0.0.1") { + ips << ip4; + } + } + } +#endif + } + + return ips; +} + +QList QtHelper::colors = QList(); +QList QtHelper::getColorList() +{ + //备用颜色集合 可以自行添加 + if (colors.count() == 0) { + colors << QColor(0, 176, 180) << QColor(0, 113, 193) << QColor(255, 192, 0); + colors << QColor(72, 103, 149) << QColor(185, 87, 86) << QColor(0, 177, 125); + colors << QColor(214, 77, 84) << QColor(71, 164, 233) << QColor(34, 163, 169); + colors << QColor(59, 123, 156) << QColor(162, 121, 197) << QColor(72, 202, 245); + colors << QColor(0, 150, 121) << QColor(111, 9, 176) << QColor(250, 170, 20); + } + + return colors; +} + +QStringList QtHelper::getColorNames() +{ + QList colors = getColorList(); + QStringList colorNames; + foreach (QColor color, colors) { + colorNames << color.name(); + } + return colorNames; +} + +QColor QtHelper::getRandColor() +{ + QList colors = getColorList(); + int index = getRandValue(0, colors.count(), true); + return colors.at(index); +} + +void QtHelper::initRand() +{ + //初始化随机数种子 + QTime t = QTime::currentTime(); + srand(t.msec() + t.second() * 1000); +} + +float QtHelper::getRandFloat(float min, float max) +{ + double diff = fabs(max - min); + double value = (double)(rand() % 100) / 100; + value = min + value * diff; + return value; +} + +double QtHelper::getRandValue(int min, int max, bool contansMin, bool contansMax) +{ + int value; +#if (QT_VERSION <= QT_VERSION_CHECK(5,10,0)) + //通用公式 a是起始值,n是整数的范围 + //int value = a + rand() % n; + if (contansMin) { + if (contansMax) { + value = min + 0 + (rand() % (max - min + 1)); + } else { + value = min + 0 + (rand() % (max - min + 0)); + } + } else { + if (contansMax) { + value = min + 1 + (rand() % (max - min + 0)); + } else { + value = min + 1 + (rand() % (max - min - 1)); + } + } +#else + if (contansMin) { + if (contansMax) { + value = QRandomGenerator::global()->bounded(min + 0, max + 1); + } else { + value = QRandomGenerator::global()->bounded(min + 0, max + 0); + } + } else { + if (contansMax) { + value = QRandomGenerator::global()->bounded(min + 1, max + 1); + } else { + value = QRandomGenerator::global()->bounded(min + 1, max + 0); + } + } +#endif + return value; +} + +QStringList QtHelper::getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat) +{ + //随机生成点坐标 + QStringList points; + for (int i = 0; i < count; ++i) { + //0.00881415 0.000442928 +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) + float lngx = QRandomGenerator::global()->bounded(dotLng); + float latx = QRandomGenerator::global()->bounded(dotLat); +#else + float lngx = getRandFloat(dotLng / 10, dotLng); + float latx = getRandFloat(dotLat / 10, dotLat); +#endif + //需要先用精度转换成字符串 + QString lng2 = QString::number(mainLng + lngx, 'f', 8); + QString lat2 = QString::number(mainLat + latx, 'f', 8); + QString point = QString("%1,%2").arg(lng2).arg(lat2); + points << point; + } + + return points; +} + +int QtHelper::getRangeValue(int oldMin, int oldMax, int oldValue, int newMin, int newMax) +{ + return (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin; +} + +QString QtHelper::getUuid() +{ + QString uuid = QUuid::createUuid().toString(); + uuid.replace("{", ""); + uuid.replace("}", ""); + return uuid; +} + +void QtHelper::checkPath(const QString &dirName) +{ + //相对路径需要补全完整路径 + QString path = dirName; + if (path.startsWith("./")) { + path.replace(".", ""); + path = QtHelper::appPath() + path; + } else if (!path.startsWith("/") && !path.contains(":/")) { + path = QtHelper::appPath() + "/" + path; + } + + //目录不存在则新建 + QDir dir(path); + if (!dir.exists()) { + dir.mkpath(path); + } +} + +void QtHelper::sleep(int msec, bool exec) +{ + if (msec <= 0) { + return; + } + + if (exec) { +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //阻塞方式延时(如果在主线程会卡住主界面) + QThread::msleep(msec); +#else + //非阻塞方式延时(不会卡住主界面/据说可能有问题) + QTime endTime = QTime::currentTime().addMSecs(msec); + while (QTime::currentTime() < endTime) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } +#endif + } else { + //非阻塞方式延时(现在很多人推荐的方法) + QEventLoop loop; + QTimer::singleShot(msec, &loop, SLOT(quit())); + loop.exec(); + } +} + +void QtHelper::checkRun() +{ +#ifdef Q_OS_WIN + //延时1秒钟,等待程序释放完毕 + QtHelper::sleep(1000); + //创建共享内存,判断是否已经运行程序 + static QSharedMemory mem(QtHelper::appName()); + if (!mem.create(1)) { + QtHelper::showMessageBoxError("程序已运行, 软件将自动关闭!", 5, true); + exit(0); + } +#endif +} + +void QtHelper::setStyle() +{ + //打印下所有内置风格的名字 + qDebug() << TIMEMS << "QStyleFactory::keys" << QStyleFactory::keys(); + //设置内置风格 +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + qApp->setStyle("Fusion"); +#else + qApp->setStyle("Cleanlooks"); +#endif + + //设置指定颜色 + QPalette palette; + palette.setBrush(QPalette::Window, QColor("#F0F0F0")); + qApp->setPalette(palette); +} + +QFont QtHelper::addFont(const QString &fontFile, const QString &fontName) +{ + //判断图形字体是否存在,不存在则加入 + QFontDatabase fontDb; + if (!fontDb.families().contains(fontName)) { + int fontId = fontDb.addApplicationFont(fontFile); + QStringList listName = fontDb.applicationFontFamilies(fontId); + if (listName.count() == 0) { + qDebug() << QString("load %1 error").arg(fontName); + } + } + + //再次判断是否包含字体名称防止加载失败 + QFont font; + if (fontDb.families().contains(fontName)) { + font = QFont(fontName); +#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0)) + font.setHintingPreference(QFont::PreferNoHinting); +#endif + } + + return font; +} + +void QtHelper::setFont(int fontSize) +{ + //安卓套件在有些手机上默认字体不好看需要主动设置字体 + //网页套件需要主动加载中文字体才能正常显示中文 +#if (defined Q_OS_ANDROID) || (defined Q_OS_WASM) + QString fontFile = ":/font/DroidSansFallback.ttf"; + QString fontName = "Droid Sans Fallback"; + qApp->setFont(addFont(fontFile, fontName)); + return; +#endif + +#ifdef __arm__ + fontSize = 25; +#endif + + QFont font; + font.setFamily("MicroSoft Yahei"); + font.setPixelSize(fontSize); + qApp->setFont(font); +} + +void QtHelper::setCode(bool utf8) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //如果想要控制台打印信息中文正常就注释掉这个设置 + if (utf8) { + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); + } +#else +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#endif +} + +void QtHelper::setTranslator(const QString &qmFile) +{ + //过滤下不存在的就不用设置了 + if (!QFile(qmFile).exists()) { + return; + } + + QTranslator *translator = new QTranslator(qApp); + if (translator->load(qmFile)) { + qApp->installTranslator(translator); + } +} + +#ifdef Q_OS_ANDROID +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) +#include +#else +//Qt6中将相关类移到了core模块而且名字变了 +#include +#endif +#endif + +bool QtHelper::checkPermission(const QString &permission) +{ +#ifdef Q_OS_ANDROID +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0) && QT_VERSION < QT_VERSION_CHECK(6,0,0)) + QtAndroid::PermissionResult result = QtAndroid::checkPermission(permission); + if (result == QtAndroid::PermissionResult::Denied) { + QtAndroid::requestPermissionsSync(QStringList() << permission); + result = QtAndroid::checkPermission(permission); + if (result == QtAndroid::PermissionResult::Denied) { + return false; + } + } +#else + QFuture result = QtAndroidPrivate::requestPermission(permission); + if (result.resultAt(0) == QtAndroidPrivate::PermissionResult::Denied) { + return false; + } +#endif +#endif + return true; +} + +void QtHelper::initAndroidPermission() +{ + //可以把所有要动态申请的权限都写在这里 + checkPermission("android.permission.CALL_PHONE"); + checkPermission("android.permission.SEND_SMS"); + checkPermission("android.permission.CAMERA"); + checkPermission("android.permission.READ_EXTERNAL_STORAGE"); + checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); + + checkPermission("android.permission.ACCESS_COARSE_LOCATION"); + checkPermission("android.permission.BLUETOOTH"); + checkPermission("android.permission.BLUETOOTH_SCAN"); + checkPermission("android.permission.BLUETOOTH_CONNECT"); + checkPermission("android.permission.BLUETOOTH_ADVERTISE"); +} + +void QtHelper::initAll(bool utf8, bool style, int fontSize) +{ + //初始化安卓权限 + QtHelper::initAndroidPermission(); + //初始化随机数种子 + QtHelper::initRand(); + //设置编码 + QtHelper::setCode(utf8); + //设置字体 + QtHelper::setFont(fontSize); + //设置样式风格 + if (style) { + QtHelper::setStyle(); + } + + //设置翻译文件支持多个 + QtHelper::setTranslator(":/qm/widgets.qm"); + QtHelper::setTranslator(":/qm/qt_zh_CN.qm"); + QtHelper::setTranslator(":/qm/designer_zh_CN.qm"); + + //设置不使用本地系统环境代理配置 + QNetworkProxyFactory::setUseSystemConfiguration(false); + //设置当前目录为程序可执行文件所在目录 + QDir::setCurrent(QtHelper::appPath()); + //Qt4中默认没有程序名称需要主动设置 +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) + qApp->setApplicationName(QtHelper::appName()); +#endif +} + +void QtHelper::initMain(bool desktopSettingsAware, bool use96Dpi, bool logCritical) +{ +#ifdef Q_OS_WIN + //Qt6.5开始默认是ffmpeg后端但是不成熟需要换成系统的 + qputenv("QT_MEDIA_BACKEND", "windows"); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //设置是否应用操作系统设置比如字体 + QApplication::setDesktopSettingsAware(desktopSettingsAware); +#endif + + bool highDpi = !use96Dpi; +#ifdef Q_OS_ANDROID + highDpi = true; +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,6,0)) + //开启高分屏缩放支持 + if (highDpi) { + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + } +#endif + +#ifdef Q_OS_WIN + if (use96Dpi) { + //Qt6中AA_Use96Dpi没效果必须下面方式设置强制指定缩放DPI + qputenv("QT_FONT_DPI", "96"); +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //不应用任何缩放 + QApplication::setAttribute(Qt::AA_Use96Dpi); +#endif + } +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + //高分屏缩放策略 + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //下面这行表示不打印Qt内部类的警告提示信息 + if (!logCritical) { + QLoggingCategory::setFilterRules("*.critical=false\n*.warning=false"); + } +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0)) + //设置opengl共享上下文 + QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); +#endif +} + +void QtHelper::initOpenGL(quint8 type, bool checkCardEnable, bool checkVirtualSystem) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0)) + //设置opengl模式 AA_UseDesktopOpenGL(默认) AA_UseOpenGLES AA_UseSoftwareOpenGL + //在一些很旧的设备上或者对opengl支持很低的设备上需要使用AA_UseOpenGLES表示禁用硬件加速 + //如果开启的是AA_UseOpenGLES则无法使用硬件加速比如ffmpeg的dxva2 + if (type == 1) { + QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); + } else if (type == 2) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } else if (type == 3) { + QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); + } + + //检测显卡是否被禁用 + if (checkCardEnable && !isVideoCardEnable()) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } + + //检测是否是虚拟机系统 + if (checkVirtualSystem && isVirtualSystem()) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } +#endif +} + +QString QtHelper::doCmd(const QString &program, const QStringList &arguments, int timeout) +{ + QString result; +#ifndef Q_OS_WASM + QProcess p; + p.start(program, arguments); + p.waitForFinished(timeout); + result = QString::fromLocal8Bit(p.readAllStandardOutput()); + result.replace("\r", ""); + result.replace("\n", ""); + result = result.simplified(); + result = result.trimmed(); +#endif + return result; +} + +bool QtHelper::isVideoCardEnable() +{ + QString result; + bool videoCardEnable = true; + +#if defined(Q_OS_WIN) + QStringList args; + //wmic path win32_VideoController get name,Status + args << "path" << "win32_VideoController" << "get" << "name,Status"; + result = doCmd("wmic", args); +#endif + + //Name Status Intel(R) UHD Graphics 630 OK + //Name Status Intel(R) UHD Graphics 630 Error + if (result.contains("Error")) { + videoCardEnable = false; + } + + return videoCardEnable; +} + +bool QtHelper::isVirtualSystem() +{ + QString result; + bool virtualSystem = false; + +#if defined(Q_OS_WIN) + QStringList args; + //wmic computersystem get Model + args << "computersystem" << "get" << "Model"; + result = doCmd("wmic", args); +#elif defined(Q_OS_LINUX) + QStringList args; + //还有个命令需要root权限运行 dmidecode -s system-product-name 执行结果和win一样 + result = doCmd("lscpu", args); +#endif + + //Model MS-7C00 + //Model VMWare Virtual Platform + //Model VirtualBox Virtual Platform + //Model Alibaba Cloud ECS + if (result.contains("VMware") || result.contains("VirtualBox") || result.contains("Alibaba")) { + virtualSystem = true; + } + + return virtualSystem; +} + +QVector QtHelper::msgTypes = QVector() << 0 << 1 << 2 << 3 << 4; +QVector QtHelper::msgKeys = QVector() << QString::fromUtf8("发送") << QString::fromUtf8("接收") << QString::fromUtf8("解析") << QString::fromUtf8("错误") << QString::fromUtf8("提示"); +QVector QtHelper::msgColors = QVector() << QColor("#3BA372") << QColor("#EE6668") << QColor("#9861B4") << QColor("#FA8359") << QColor("#22A3A9"); +QString QtHelper::appendMsg(QTextEdit *textEdit, int type, const QString &data, int maxCount, int ¤tCount, bool clear, bool pause) +{ + if (clear) { + textEdit->clear(); + currentCount = 0; + return QString(); + } + + if (pause) { + return QString(); + } + + if (currentCount >= maxCount) { + textEdit->clear(); + currentCount = 0; + } + + //不同类型不同颜色显示 + QString strType; + int index = msgTypes.indexOf(type); + if (index >= 0) { + strType = msgKeys.at(index); + textEdit->setTextColor(msgColors.at(index)); + } + + //过滤回车换行符 + QString strData = data; + strData.replace("\r", ""); + strData.replace("\n", ""); + strData = QString("时间[%1] %2: %3").arg(TIMEMS).arg(strType).arg(strData); + textEdit->append(strData); + currentCount++; + return strData; +} + +void QtHelper::setFramelessForm(QWidget *widgetMain, bool tool, bool top, bool menu) +{ + widgetMain->setProperty("form", true); + widgetMain->setProperty("canMove", true); + + //根据设定逐个追加属性 +#ifdef __arm__ + widgetMain->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); +#else + widgetMain->setWindowFlags(Qt::FramelessWindowHint); +#endif + if (tool) { + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::Tool); + } + if (top) { + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::WindowStaysOnTopHint); + } + if (menu) { + //如果是其他系统比如neokylin会产生系统边框 +#ifdef Q_OS_WIN + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); +#endif + } +} + +int QtHelper::showMessageBox(const QString &text, int type, int closeSec, bool exec) +{ + int result = 0; + if (type == 0) { + showMessageBoxInfo(text, closeSec, exec); + } else if (type == 1) { + showMessageBoxError(text, closeSec, exec); + } else if (type == 2) { + result = showMessageBoxQuestion(text); + } + + return result; +} + +void QtHelper::showMessageBoxInfo(const QString &text, int closeSec, bool exec) +{ + QMessageBox box(QMessageBox::Information, "提示", text); + box.setStandardButtons(QMessageBox::Yes); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.exec(); + //QMessageBox::information(0, "提示", info, QMessageBox::Yes); +} + +void QtHelper::showMessageBoxError(const QString &text, int closeSec, bool exec) +{ + QMessageBox box(QMessageBox::Critical, "错误", text); + box.setStandardButtons(QMessageBox::Yes); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.exec(); + //QMessageBox::critical(0, "错误", info, QMessageBox::Yes); +} + +int QtHelper::showMessageBoxQuestion(const QString &text) +{ + QMessageBox box(QMessageBox::Question, "询问", text); + box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.setButtonText(QMessageBox::No, QString("取 消")); + return box.exec(); + //return QMessageBox::question(0, "询问", info, QMessageBox::Yes | QMessageBox::No); +} + +void QtHelper::initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName, + const QString &dirName, bool native, int width, int height) +{ + //设置标题 + dialog->setWindowTitle(title); + //设置标签文本 + dialog->setLabelText(QFileDialog::Accept, acceptName); + dialog->setLabelText(QFileDialog::Reject, "取消(&C)"); + dialog->setLabelText(QFileDialog::LookIn, "查看"); + dialog->setLabelText(QFileDialog::FileName, "名称"); + dialog->setLabelText(QFileDialog::FileType, "类型"); + + //设置默认显示目录 + if (!dirName.isEmpty()) { + dialog->setDirectory(dirName); + } + + //设置对话框宽高 + if (width > 0 && height > 0) { +#ifdef Q_OS_ANDROID + bool horizontal = (QtHelper::deskWidth() > QtHelper::deskHeight()); + if (horizontal) { + width = QtHelper::deskWidth() / 2; + height = QtHelper::deskHeight() - 50; + } else { + width = QtHelper::deskWidth() - 10; + height = QtHelper::deskHeight() / 2; + } +#endif + dialog->setFixedSize(width, height); + } + + //设置是否采用本地对话框 + dialog->setOption(QFileDialog::DontUseNativeDialog, !native); + //设置只读可以取消右上角的新建按钮 + //dialog->setReadOnly(true); +} + +QString QtHelper::getDialogResult(QFileDialog *dialog) +{ + QString result; + if (dialog->exec() == QFileDialog::Accepted) { + result = dialog->selectedFiles().first(); + if (!result.contains(".")) { + //自动补全拓展名 保存文件(*.txt *.exe) + QString filter = dialog->selectedNameFilter(); + if (filter.contains("*.")) { + filter = filter.split("(").last(); + filter = filter.mid(0, filter.length() - 1); + //取出第一个作为拓展名 + if (!filter.contains("*.*")) { + filter = filter.split(" ").first(); + result = result + filter.mid(1, filter.length()); + } + } + } + } + return result; +} + +QString QtHelper::getOpenFileName(const QString &filter, const QString &dirName, const QString &fileName, + bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "打开文件", "选择(&S)", dirName, native, width, height); + + //设置文件类型 + if (!filter.isEmpty()) { + dialog.setNameFilter(filter); + } + + //设置默认文件名称 + dialog.selectFile(fileName); + return getDialogResult(&dialog); +} + +QString QtHelper::getSaveFileName(const QString &filter, const QString &dirName, const QString &fileName, + bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "保存文件", "保存(&S)", dirName, native, width, height); + + //设置文件类型 + if (!filter.isEmpty()) { + dialog.setNameFilter(filter); + } + + //设置默认文件名称 + dialog.selectFile(fileName); + //设置模态类型允许输入 + dialog.setWindowModality(Qt::WindowModal); + //设置置顶显示 + dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint); + return getDialogResult(&dialog); +} + +QString QtHelper::getExistingDirectory(const QString &dirName, bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "选择目录", "选择(&S)", dirName, native, width, height); + dialog.setOption(QFileDialog::ReadOnly); + //设置只显示目录 +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + dialog.setFileMode(QFileDialog::DirectoryOnly); +#endif + dialog.setOption(QFileDialog::ShowDirsOnly); + return getDialogResult(&dialog); +} + +QString QtHelper::getXorEncryptDecrypt(const QString &value, char key) +{ + //矫正范围外的数据 + if (key < 0 || key >= 127) { + key = 127; + } + + //大概从5.9版本输出的加密密码字符串前面会加上 @String 字符 + QString result = value; + if (result.startsWith("@String")) { + result = result.mid(8, result.length() - 9); + } + + for (int i = 0; i < result.length(); ++i) { + result[i] = QChar(result.at(i).toLatin1() ^ key); + } + return result; +} + +quint8 QtHelper::getOrCode(const QByteArray &data) +{ + int len = data.length(); + quint8 result = 0; + for (int i = 0; i < len; ++i) { + result ^= data.at(i); + } + + return result; +} + +quint8 QtHelper::getCheckCode(const QByteArray &data) +{ + int len = data.length(); + quint8 temp = 0; + for (int i = 0; i < len; ++i) { + temp += data.at(i); + } + + return temp % 256; +} + +void QtHelper::initTableView(QTableView *tableView, int rowHeight, bool headVisible, bool edit, bool stretchLast) +{ + //设置弱属性用于应用qss特殊样式 + tableView->setProperty("model", true); + //取消自动换行 + tableView->setWordWrap(false); + //超出文本不显示省略号 + tableView->setTextElideMode(Qt::ElideNone); + //奇数偶数行颜色交替 + tableView->setAlternatingRowColors(false); + //垂直表头是否可见 + tableView->verticalHeader()->setVisible(headVisible); + //选中一行表头是否加粗 + tableView->horizontalHeader()->setHighlightSections(false); + //最后一行拉伸填充 + tableView->horizontalHeader()->setStretchLastSection(stretchLast); + //行标题最小宽度尺寸 + tableView->horizontalHeader()->setMinimumSectionSize(0); + //行标题最小高度,等同于和默认行高一致 + tableView->horizontalHeader()->setFixedHeight(rowHeight); + //默认行高 + tableView->verticalHeader()->setDefaultSectionSize(rowHeight); + //选中时一行整体选中 + tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + //只允许选择单个 + tableView->setSelectionMode(QAbstractItemView::SingleSelection); + + //表头不可单击 +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + tableView->horizontalHeader()->setSectionsClickable(false); +#else + tableView->horizontalHeader()->setClickable(false); +#endif + + //鼠标按下即进入编辑模式 + if (edit) { + tableView->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked); + } else { + tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + } +} + +void QtHelper::openFile(const QString &fileName, const QString &msg) +{ +#ifdef __arm__ + return; +#endif + //文件不存在则不用处理 + if (!QFile(fileName).exists()) { + return; + } + if (QtHelper::showMessageBoxQuestion(msg + "成功, 确定现在就打开吗?") == QMessageBox::Yes) { + QString url = QString("file:///%1").arg(fileName); + QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); + } +} + +bool QtHelper::checkIniFile(const QString &iniFile) +{ + //如果配置文件大小为0,则以初始值继续运行,并生成配置文件 + QFile file(iniFile); + if (file.size() == 0) { + return false; + } + + //如果配置文件不完整,则以初始值继续运行,并生成配置文件 + if (file.open(QFile::ReadOnly)) { + bool ok = true; + while (!file.atEnd()) { + QString line = file.readLine(); + line.replace("\r", ""); + line.replace("\n", ""); + QStringList list = line.split("="); + + if (list.count() == 2) { + QString key = list.at(0); + QString value = list.at(1); + if (value.isEmpty()) { + qDebug() << TIMEMS << "ini node no value" << key; + ok = false; + break; + } + } + } + + if (!ok) { + return false; + } + } else { + return false; + } + + return true; +} + +QString QtHelper::cutString(const QString &text, int len, int left, int right, bool file, const QString &mid) +{ + //如果指定了字符串分割则表示是文件名需要去掉拓展名 + QString result = text; + if (file && result.contains(".")) { + int index = result.lastIndexOf("."); + result = result.mid(0, index); + } + + //最终字符串格式为 前缀字符...后缀字符 + if (result.length() > len) { + result = QString("%1%2%3").arg(result.left(left)).arg(mid).arg(result.right(right)); + } + + return result; +} + +QRect QtHelper::getCenterRect(const QSize &imageSize, const QRect &widgetRect, int borderWidth, int scaleMode) +{ + QSize newSize = imageSize; + QSize widgetSize = widgetRect.size() - QSize(borderWidth * 1, borderWidth * 1); + + if (scaleMode == 0) { + if (newSize.width() > widgetSize.width() || newSize.height() > widgetSize.height()) { + newSize.scale(widgetSize, Qt::KeepAspectRatio); + } + } else if (scaleMode == 1) { + newSize.scale(widgetSize, Qt::KeepAspectRatio); + } else { + newSize = widgetSize; + } + + int x = widgetRect.center().x() - newSize.width() / 2; + int y = widgetRect.center().y() - newSize.height() / 2; + //不是2的倍数需要偏移1像素 + x += (x % 2 == 0 ? 1 : 0); + y += (y % 2 == 0 ? 1 : 0); + return QRect(x, y, newSize.width(), newSize.height()); +} + +void QtHelper::getScaledImage(QImage &image, const QSize &widgetSize, int scaleMode, bool fast) +{ + Qt::TransformationMode mode = fast ? Qt::FastTransformation : Qt::SmoothTransformation; + if (scaleMode == 0) { + if (image.width() > widgetSize.width() || image.height() > widgetSize.height()) { + image = image.scaled(widgetSize, Qt::KeepAspectRatio, mode); + } + } else if (scaleMode == 1) { + image = image.scaled(widgetSize, Qt::KeepAspectRatio, mode); + } else { + image = image.scaled(widgetSize, Qt::IgnoreAspectRatio, mode); + } +} + +QString QtHelper::getTimeString(qint64 time) +{ + time = time / 1000; + QString min = QString("%1").arg(time / 60, 2, 10, QChar('0')); + QString sec = QString("%2").arg(time % 60, 2, 10, QChar('0')); + return QString("%1:%2").arg(min).arg(sec); +} + +QString QtHelper::getTimeString(QElapsedTimer timer) +{ + return QString::number((float)timer.elapsed() / 1000, 'f', 3); +} + +QString QtHelper::getSizeString(quint64 size) +{ + float num = size; + QStringList list; + list << "KB" << "MB" << "GB" << "TB"; + + QString unit("bytes"); + QStringListIterator i(list); + while (num >= 1024.0 && i.hasNext()) { + unit = i.next(); + num /= 1024.0; + } + + return QString("%1 %2").arg(QString::number(num, 'f', 2)).arg(unit); +} + +//setSystemDateTime("2022", "07", "01", "12", "22", "55"); +void QtHelper::setSystemDateTime(const QString &year, const QString &month, const QString &day, const QString &hour, const QString &min, const QString &sec) +{ +#ifdef Q_OS_WIN + QProcess p(0); + //先设置日期 + p.start("cmd"); + p.waitForStarted(); + p.write(QString("date %1-%2-%3\n").arg(year).arg(month).arg(day).toLatin1()); + p.closeWriteChannel(); + p.waitForFinished(1000); + p.close(); + //再设置时间 + p.start("cmd"); + p.waitForStarted(); + p.write(QString("time %1:%2:%3.00\n").arg(hour).arg(min).arg(sec).toLatin1()); + p.closeWriteChannel(); + p.waitForFinished(1000); + p.close(); +#else + QString cmd = QString("date %1%2%3%4%5.%6").arg(month).arg(day).arg(hour).arg(min).arg(year).arg(sec); + //设置日期时间 + system(cmd.toLatin1()); + //硬件时钟同步 + system("hwclock -w"); +#endif +} + +void QtHelper::runWithSystem(bool autoRun) +{ + QtHelper::runWithSystem(qApp->applicationName(), qApp->applicationFilePath(), autoRun); +} + +void QtHelper::runWithSystem(const QString &fileName, const QString &filePath, bool autoRun) +{ +#ifdef Q_OS_WIN + //要转换成本地文件路径(不启动则文件路径为空即可) + QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat); + reg.setValue(fileName, autoRun ? QDir::toNativeSeparators(filePath) : ""); +#endif +} + +void QtHelper::runBin(const QString &path, const QString &name) +{ +#ifdef Q_OS_WIN + QString cmd1 = "tasklist"; + QString cmd2 = QString("%1/%2.exe").arg(path).arg(name); +#else + QString cmd1 = "ps -aux"; + QString cmd2 = QString("%1/%2").arg(path).arg(name); +#endif + +#ifndef Q_OS_WASM + QProcess p; + p.start(cmd1); + if (p.waitForFinished()) { + QString result = p.readAll(); + if (result.contains(name)) { + return; + } + } + + //加上引号可以兼容打开带空格的目录(Program Files) + if (cmd2.contains(" ")) { + cmd2 = "\"" + cmd2 + "\""; + } + + //QProcess::execute(cmd2); + QProcess::startDetached(cmd2); +#endif +} diff --git a/tool/comtool/api/qthelper.h b/tool/comtool/api/qthelper.h new file mode 100644 index 0000000..6562b43 --- /dev/null +++ b/tool/comtool/api/qthelper.h @@ -0,0 +1,180 @@ +#ifndef QTHELPER_H +#define QTHELPER_H + +#include "head.h" + +class QtHelper +{ +public: + //获取所有屏幕区域/当前鼠标所在屏幕索引/区域尺寸/缩放系数 + static QList getScreenRects(bool available = true); + static int getScreenIndex(); + static QRect getScreenRect(bool available = true); + static qreal getScreenRatio(bool devicePixel = false); + + //矫正当前鼠标所在屏幕居中尺寸 + static QRect checkCenterRect(QRect &rect, bool available = true); + + //获取桌面宽度高度+居中显示 + static int deskWidth(); + static int deskHeight(); + static QSize deskSize(); + + //居中显示窗体 + //定义标志位指定是以桌面为参照还是主程序界面为参照 + static QWidget *centerBaseForm; + static void setFormInCenter(QWidget *form); + static void showForm(QWidget *form); + + //程序文件名称和当前所在路径 + static QString appName(); + static QString appPath(); + + //程序最前面获取应用程序路径和名称 + static void getCurrentInfo(char *argv[], QString &path, QString &name); + //程序最前面读取配置文件节点的值 + static QString getIniValue(const QString &fileName, const QString &key); + static QString getIniValue(char *argv[], const QString &key, const QString &dir = QString()); + + //获取本地网卡IP集合 + static QStringList getLocalIPs(); + + //获取内置颜色集合 + static QList colors; + static QList getColorList(); + static QStringList getColorNames(); + //随机获取颜色集合中的颜色 + static QColor getRandColor(); + + //初始化随机数种子 + static void initRand(); + //获取随机小数 + static float getRandFloat(float min, float max); + //获取随机数,指定最小值和最大值 + static double getRandValue(int min, int max, bool contansMin = false, bool contansMax = false); + //获取范围值随机经纬度集合 + static QStringList getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat); + //根据旧的范围值和值计算新的范围值对应的值 + static int getRangeValue(int oldMin, int oldMax, int oldValue, int newMin, int newMax); + + //获取uuid + static QString getUuid(); + //校验目录 + static void checkPath(const QString &dirName); + //通用延时函数(支持Qt4 Qt5 Qt6) + static void sleep(int msec, bool exec = true); + //检查程序是否已经运行 + static void checkRun(); + + //设置Qt自带样式 + static void setStyle(); + //设置字体 + static QFont addFont(const QString &fontFile, const QString &fontName); + static void setFont(int fontSize = 12); + //设置编码 + static void setCode(bool utf8 = true); + //设置翻译文件 + static void setTranslator(const QString &qmFile); + + //动态设置权限 + static bool checkPermission(const QString &permission); + //申请安卓权限 + static void initAndroidPermission(); + + //一次性设置所有包括编码样式字体等 + static void initAll(bool utf8 = true, bool style = true, int fontSize = 13); + //初始化main函数最前面执行的一段代码 + static void initMain(bool desktopSettingsAware = false, bool use96Dpi = true, bool logCritical = true); + //初始化opengl类型(1=AA_UseDesktopOpenGL 2=AA_UseOpenGLES 3=AA_UseSoftwareOpenGL) + static void initOpenGL(quint8 type = 0, bool checkCardEnable = false, bool checkVirtualSystem = false); + + //执行命令行返回执行结果 + static QString doCmd(const QString &program, const QStringList &arguments, int timeout = 1000); + //获取显卡是否被禁用 + static bool isVideoCardEnable(); + //获取是否在虚拟机环境 + static bool isVirtualSystem(); + + //插入消息 + static QVector msgTypes; + static QVector msgKeys; + static QVector msgColors; + static QString appendMsg(QTextEdit *textEdit, int type, const QString &data, + int maxCount, int ¤tCount, + bool clear = false, bool pause = false); + + //设置无边框 + static void setFramelessForm(QWidget *widgetMain, bool tool = false, bool top = false, bool menu = true); + + //弹出框 + static int showMessageBox(const QString &text, int type = 0, int closeSec = 0, bool exec = false); + //弹出消息框 + static void showMessageBoxInfo(const QString &text, int closeSec = 0, bool exec = false); + //弹出错误框 + static void showMessageBoxError(const QString &text, int closeSec = 0, bool exec = false); + //弹出询问框 + static int showMessageBoxQuestion(const QString &text); + + //为什么还要自定义对话框因为可控宽高和汉化对应文本等 + //初始化对话框文本 + static void initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName, + const QString &dirName, bool native, int width, int height); + //拿到对话框结果 + static QString getDialogResult(QFileDialog *dialog); + //选择文件对话框 + static QString getOpenFileName(const QString &filter = QString(), + const QString &dirName = QString(), + const QString &fileName = QString(), + bool native = false, int width = 900, int height = 600); + //保存文件对话框 + static QString getSaveFileName(const QString &filter = QString(), + const QString &dirName = QString(), + const QString &fileName = QString(), + bool native = false, int width = 900, int height = 600); + //选择目录对话框 + static QString getExistingDirectory(const QString &dirName = QString(), + bool native = false, int width = 900, int height = 600); + + //异或加密-只支持字符,如果是中文需要将其转换base64编码 + static QString getXorEncryptDecrypt(const QString &value, char key); + //异或校验 + static quint8 getOrCode(const QByteArray &data); + //计算校验码 + static quint8 getCheckCode(const QByteArray &data); + + //初始化表格 + static void initTableView(QTableView *tableView, int rowHeight = 25, + bool headVisible = false, bool edit = false, + bool stretchLast = true); + //打开文件带提示框 + static void openFile(const QString &fileName, const QString &msg); + + //检查ini配置文件 + static bool checkIniFile(const QString &iniFile); + + //首尾截断字符串显示 + static QString cutString(const QString &text, int len, int left, int right, bool file, const QString &mid = "..."); + + //传入图片尺寸和窗体区域及边框大小返回居中区域(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充) + static QRect getCenterRect(const QSize &imageSize, const QRect &widgetRect, int borderWidth = 2, int scaleMode = 0); + //传入图片尺寸和窗体尺寸及缩放策略返回合适尺寸(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充) + static void getScaledImage(QImage &image, const QSize &widgetSize, int scaleMode = 0, bool fast = true); + + //毫秒数转时间 00:00 + static QString getTimeString(qint64 time); + //用时时间转秒数 + static QString getTimeString(QElapsedTimer timer); + //文件大小转 KB MB GB TB + static QString getSizeString(quint64 size); + + //设置系统时间 + static void setSystemDateTime(const QString &year, const QString &month, const QString &day, + const QString &hour, const QString &min, const QString &sec); + //设置开机自启动 + static void runWithSystem(bool autoRun = true); + static void runWithSystem(const QString &fileName, const QString &filePath, bool autoRun = true); + //启动运行程序(已经在运行则不启动) + static void runBin(const QString &path, const QString &name); +}; + +#endif // QTHELPER_H diff --git a/tool/comtool/api/qthelperdata.cpp b/tool/comtool/api/qthelperdata.cpp new file mode 100644 index 0000000..5f26ee5 --- /dev/null +++ b/tool/comtool/api/qthelperdata.cpp @@ -0,0 +1,473 @@ +#include "qthelperdata.h" +#include "qthelper.h" + +int QtHelperData::strHexToDecimal(const QString &strHex) +{ + bool ok; + return strHex.toInt(&ok, 16); +} + +int QtHelperData::strDecimalToDecimal(const QString &strDecimal) +{ + bool ok; + return strDecimal.toInt(&ok, 10); +} + +int QtHelperData::strBinToDecimal(const QString &strBin) +{ + bool ok; + return strBin.toInt(&ok, 2); +} + +QString QtHelperData::strHexToStrBin(const QString &strHex) +{ + quint8 decimal = strHexToDecimal(strHex); + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + + if (len < 8) { + for (int i = 0; i < 8 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrBin1(int decimal) +{ + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + if (len <= 8) { + for (int i = 0; i < 8 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrBin2(int decimal) +{ + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + if (len <= 16) { + for (int i = 0; i < 16 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrHex(int decimal) +{ + QString temp = QString::number(decimal, 16); + if (temp.length() == 1) { + temp = "0" + temp; + } + + return temp; +} + +QByteArray QtHelperData::intToByte(int data, bool reverse) +{ + quint8 data1 = (quint8)(0x000000ff & data); + quint8 data2 = (quint8)((0x0000ff00 & data) >> 8); + quint8 data3 = (quint8)((0x00ff0000 & data) >> 16); + quint8 data4 = (quint8)((0xff000000 & data) >> 24); + + QByteArray result; + result.resize(4); + if (reverse) { + result[0] = data1; + result[1] = data2; + result[2] = data3; + result[3] = data4; + } else { + result[0] = data4; + result[1] = data3; + result[2] = data2; + result[3] = data1; + } + return result; +} + +int QtHelperData::byteToInt(const QByteArray &data, bool reverse) +{ + int result = 0; + if (reverse) { + result = data.at(0) & 0x000000ff; + result |= ((data.at(1) << 8) & 0x0000ff00); + result |= ((data.at(2) << 16) & 0x00ff0000); + result |= ((data.at(3) << 24) & 0xff000000); + } else { + result = data.at(3) & 0x000000ff; + result |= ((data.at(2) << 8) & 0x0000ff00); + result |= ((data.at(1) << 16) & 0x00ff0000); + result |= ((data.at(0) << 24) & 0xff000000); + } + return result; +} + +QByteArray QtHelperData::ushortToByte(int data, bool reverse) +{ + quint8 data1 = (quint8)(0x000000ff & data); + quint8 data2 = (quint8)((0x0000ff00 & data) >> 8); + + QByteArray result; + result.resize(2); + if (reverse) { + result[0] = data1; + result[1] = data2; + } else { + result[0] = data2; + result[1] = data1; + } + return result; +} + +int QtHelperData::byteToShort(const QByteArray &data, bool reverse) +{ + int result = 0; + if (reverse) { + result = data.at(0) & 0x000000ff; + result |= ((data.at(1) << 8) & 0x0000ff00); + } else { + result = data.at(1) & 0x000000ff; + result |= ((data.at(0) << 8) & 0x0000ff00); + } + if (result >= 32768) { + result = result - 65536; + } + return result; +} + +QString QtHelperData::getValue(quint8 value) +{ + QString result = QString::number(value); + if (result.length() <= 1) { + result = QString("0%1").arg(result); + } + return result; +} + +QString QtHelperData::trimmed(const QString &text, int type) +{ + QString temp = text; + QString pattern; + if (type == -1) { + pattern = "^ +\\s*"; + } else if (type == 0) { + pattern = "\\s"; + //temp.replace(" ", ""); + } else if (type == 1) { + pattern = "\\s* +$"; + } else if (type == 2) { + temp = temp.trimmed(); + } else if (type == 3) { + temp = temp.simplified(); + } + + //调用正则表达式移除空格 + if (!pattern.isEmpty()) { +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + temp.remove(QRegularExpression(pattern)); +#else + temp.remove(QRegExp(pattern)); +#endif + } + + return temp; +} + +QString QtHelperData::getXorEncryptDecrypt(const QString &value, char key) +{ + //矫正范围外的数据 + if (key < 0 || key >= 127) { + key = 127; + } + + //大概从5.9版本输出的加密密码字符串前面会加上 @String 字符 + QString result = value; + if (result.startsWith("@String")) { + result = result.mid(8, result.length() - 9); + } + + for (int i = 0; i < result.length(); ++i) { + result[i] = QChar(result.at(i).toLatin1() ^ key); + } + return result; +} + +quint8 QtHelperData::getOrCode(const QByteArray &data) +{ + int len = data.length(); + quint8 result = 0; + for (int i = 0; i < len; ++i) { + result ^= data.at(i); + } + + return result; +} + +quint8 QtHelperData::getCheckCode(const QByteArray &data) +{ + int len = data.length(); + quint8 temp = 0; + for (int i = 0; i < len; ++i) { + temp += data.at(i); + } + + return temp % 256; +} + +void QtHelperData::getFullData(QByteArray &buffer) +{ + //计算校验码 + quint8 checkCode = getCheckCode(buffer); + //尾部插入校验码 + buffer.append(checkCode); + //头部插入固定帧头 + buffer.insert(0, 0x16); +} + +//函数功能:计算CRC16 +//参数1:*data 16位CRC校验数据, +//参数2:len 数据流长度 +//参数3:init 初始化值 +//参数4:table 16位CRC查找表 + +//正序CRC计算 +quint16 QtHelperData::getCrc16(quint8 *data, int len, quint16 init, const quint16 *table) +{ + quint16 crc_16 = init; + quint8 temp; + while (len-- > 0) { + temp = crc_16 & 0xff; + crc_16 = (crc_16 >> 8) ^ table[(temp ^ *data++) & 0xff]; + } + + return crc_16; +} + +//逆序CRC计算 +quint16 QtHelperData::getCrc16Rec(quint8 *data, int len, quint16 init, const quint16 *table) +{ + quint16 crc_16 = init; + quint8 temp; + while (len-- > 0) { + temp = crc_16 >> 8; + crc_16 = (crc_16 << 8) ^ table[(temp ^ *data++) & 0xff]; + } + + return crc_16; +} + +//Modbus CRC16校验 +quint16 QtHelperData::getModbus16(quint8 *data, int len) +{ + //MODBUS CRC-16表 8005 逆序 + const quint16 table_16[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 + }; + + return getCrc16(data, len, 0xFFFF, table_16); +} + +//CRC16校验 +QByteArray QtHelperData::getCrcCode(const QByteArray &data) +{ + quint16 result = getModbus16((quint8 *)data.data(), data.length()); + return QtHelperData::ushortToByte(result, true); +} + +static QMap listChar; +void QtHelperData::initAscii() +{ + //0x20为空格,空格以下都是不可见字符 + if (listChar.count() == 0) { + listChar.insert(0, "\\NUL"); + listChar.insert(1, "\\SOH"); + listChar.insert(2, "\\STX"); + listChar.insert(3, "\\ETX"); + listChar.insert(4, "\\EOT"); + listChar.insert(5, "\\ENQ"); + listChar.insert(6, "\\ACK"); + listChar.insert(7, "\\BEL"); + listChar.insert(8, "\\BS"); + listChar.insert(9, "\\HT"); + listChar.insert(10, "\\LF"); + listChar.insert(11, "\\VT"); + listChar.insert(12, "\\FF"); + listChar.insert(13, "\\CR"); + listChar.insert(14, "\\SO"); + listChar.insert(15, "\\SI"); + listChar.insert(16, "\\DLE"); + listChar.insert(17, "\\DC1"); + listChar.insert(18, "\\DC2"); + listChar.insert(19, "\\DC3"); + listChar.insert(20, "\\DC4"); + listChar.insert(21, "\\NAK"); + listChar.insert(22, "\\SYN"); + listChar.insert(23, "\\ETB"); + listChar.insert(24, "\\CAN"); + listChar.insert(25, "\\EM"); + listChar.insert(26, "\\SUB"); + listChar.insert(27, "\\ESC"); + listChar.insert(28, "\\FS"); + listChar.insert(29, "\\GS"); + listChar.insert(30, "\\RS"); + listChar.insert(31, "\\US"); + listChar.insert(0x5C, "\\"); + listChar.insert(0x7F, "\\DEL"); + } +} + +QString QtHelperData::byteArrayToAsciiStr(const QByteArray &data) +{ + //先初始化字符表 + initAscii(); + + QString temp; + int len = data.length(); + for (int i = 0; i < len; ++i) { + char byte = data.at(i); + QString value = listChar.value(byte); + if (!value.isEmpty()) { + } else if (byte >= 0 && byte <= 0x7F) { + value = QString("%1").arg(byte); + } else { + value = decimalToStrHex((quint8)byte); + value = QString("\\x%1").arg(value.toUpper()); + } + + temp += value; + } + + return temp.trimmed(); +} + +QByteArray QtHelperData::asciiStrToByteArray(const QString &data) +{ + //先初始化字符表 + initAscii(); + + QByteArray buffer; + QStringList list = data.split("\\"); + + int count = list.count(); + for (int i = 1; i < count; ++i) { + QString str = list.at(i); + int key = 0; + if (str.contains("x")) { + key = strHexToDecimal(str.mid(1, 2)); + } else { + key = listChar.key("\\" + str); + } + + buffer.append(key); + } + + //可能是纯字符串不带控制字符 + if (buffer.length() == 0) { + buffer = data.toUtf8(); + } + + return buffer; +} + +char QtHelperData::hexStrToChar(char data) +{ + if ((data >= '0') && (data <= '9')) { + return data - 0x30; + } else if ((data >= 'A') && (data <= 'F')) { + return data - 'A' + 10; + } else if ((data >= 'a') && (data <= 'f')) { + return data - 'a' + 10; + } else { + return (-1); + } +} + +QByteArray QtHelperData::hexStrToByteArray(const QString &data) +{ + QByteArray senddata; + int hexdata, lowhexdata; + int hexdatalen = 0; + int len = data.length(); + senddata.resize(len / 2); + char lstr, hstr; + + for (int i = 0; i < len;) { + hstr = data.at(i).toLatin1(); + if (hstr == ' ') { + i++; + continue; + } + + i++; + if (i >= len) { + break; + } + + lstr = data.at(i).toLatin1(); + hexdata = hexStrToChar(hstr); + lowhexdata = hexStrToChar(lstr); + + if ((hexdata == 16) || (lowhexdata == 16)) { + break; + } else { + hexdata = hexdata * 16 + lowhexdata; + } + + i++; + senddata[hexdatalen] = (char)hexdata; + hexdatalen++; + } + + senddata.resize(hexdatalen); + return senddata; +} + +QString QtHelperData::byteArrayToHexStr(const QByteArray &data) +{ + QString temp = ""; + QString hex = data.toHex(); + for (int i = 0; i < hex.length(); i = i + 2) { + temp += hex.mid(i, 2) + " "; + } + + return temp.trimmed().toUpper(); +} diff --git a/tool/comtool/api/qthelperdata.h b/tool/comtool/api/qthelperdata.h new file mode 100644 index 0000000..0f649c3 --- /dev/null +++ b/tool/comtool/api/qthelperdata.h @@ -0,0 +1,65 @@ +#ifndef QTHELPERDATA_H +#define QTHELPERDATA_H + +#include + +class QtHelperData +{ +public: + //16进制字符串转10进制 + static int strHexToDecimal(const QString &strHex); + //10进制字符串转10进制 + static int strDecimalToDecimal(const QString &strDecimal); + //2进制字符串转10进制 + static int strBinToDecimal(const QString &strBin); + + //16进制字符串转2进制字符串 + static QString strHexToStrBin(const QString &strHex); + //10进制转2进制字符串一个字节 + static QString decimalToStrBin1(int decimal); + //10进制转2进制字符串两个字节 + static QString decimalToStrBin2(int decimal); + //10进制转16进制字符串,补零. + static QString decimalToStrHex(int decimal); + + //int和字节数组互转 + static QByteArray intToByte(int data, bool reverse = false); + static int byteToInt(const QByteArray &data, bool reverse = false); + + //ushort和字节数组互转 + static QByteArray ushortToByte(int data, bool reverse = false); + static int byteToShort(const QByteArray &data, bool reverse = false); + + //字符串补全 + static QString getValue(quint8 value); + //字符串去空格 -1=移除左侧空格 0=移除所有空格 1=移除右侧空格 2=移除首尾空格 3=首尾清除中间留一个空格 + static QString trimmed(const QString &text, int type); + + //异或加密-只支持字符,如果是中文需要将其转换base64编码 + static QString getXorEncryptDecrypt(const QString &value, char key); + //异或校验 + static quint8 getOrCode(const QByteArray &data); + + //公司专用-计算校验码 + static quint8 getCheckCode(const QByteArray &data); + //公司专用-加上桢头和校验码完整数据 + static void getFullData(QByteArray &buffer); + + //CRC校验 + static quint16 getCrc16Rec(quint8 *data, int len, quint16 init, const quint16 *table); + static quint16 getCrc16(quint8 *data, int len, quint16 init, const quint16 *table); + static quint16 getModbus16(quint8 *data, int len); + static QByteArray getCrcCode(const QByteArray &data); + + //字节数组与Ascii字符串互转 + static void initAscii(); + static QString byteArrayToAsciiStr(const QByteArray &data); + static QByteArray asciiStrToByteArray(const QString &data); + + //16进制字符串与字节数组互转 + static char hexStrToChar(char data); + static QByteArray hexStrToByteArray(const QString &data); + static QString byteArrayToHexStr(const QByteArray &data); +}; + +#endif // QTHELPERDATA_H diff --git a/tool/comtool/comtool.pro b/tool/comtool/comtool.pro new file mode 100644 index 0000000..07074ef --- /dev/null +++ b/tool/comtool/comtool.pro @@ -0,0 +1,23 @@ +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = comtool +TEMPLATE = app +DESTDIR = $$PWD/../bin +RC_FILE = qrc/main.rc + +HEADERS += head.h +SOURCES += main.cpp +RESOURCES += qrc/main.qrc +CONFIG += warn_off + +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD/api +INCLUDEPATH += $$PWD/form + +include ($$PWD/api/api.pri) +include ($$PWD/form/form.pri) + +INCLUDEPATH += $$PWD/../3rd_qextserialport +include ($$PWD/../3rd_qextserialport/3rd_qextserialport.pri) diff --git a/tool/comtool/file/device.txt b/tool/comtool/file/device.txt new file mode 100644 index 0000000..bb54788 --- /dev/null +++ b/tool/comtool/file/device.txt @@ -0,0 +1 @@ +01 03 00 00 00 06 C5 C8;01 03 0C 00 01 00 01 00 00 00 01 00 01 00 01 37 DC \ No newline at end of file diff --git a/tool/comtool/file/send.txt b/tool/comtool/file/send.txt new file mode 100644 index 0000000..51b3944 --- /dev/null +++ b/tool/comtool/file/send.txt @@ -0,0 +1,17 @@ +16 FF 01 01 E0 E1 +16 FF 01 01 E1 E2 +16 01 02 DF BC 16 01 02 DF BC 16 01 02 DF BC 12 13 14 15 +16 00 00 04 D0 F0 F1 65 C4 +16 00 00 04 D0 05 AB 5A C4 +16 01 10 02 F0 03 06 16 01 11 02 F0 03 06 16 01 12 02 F0 03 06 16 01 13 02 F0 03 06 16 01 +14 02 F0 03 06 16 01 15 02 F0 03 06 16 01 16 02 F0 03 06 +16 11 01 03 E8 01 10 0E +16 11 01 03 E8 01 12 10 +16 11 01 03 E8 01 14 12 +16 11 01 03 E8 01 15 13 +DISARMEDALL +BURGLARY 012 +BYPASS 012 +DISARMED 012 +16 00 01 01 D1 D3 +16 01 11 11 \ No newline at end of file diff --git a/tool/comtool/form/form.pri b/tool/comtool/form/form.pri new file mode 100644 index 0000000..c4b3563 --- /dev/null +++ b/tool/comtool/form/form.pri @@ -0,0 +1,8 @@ +FORMS += \ + $$PWD/frmcomtool.ui + +HEADERS += \ + $$PWD/frmcomtool.h + +SOURCES += \ + $$PWD/frmcomtool.cpp diff --git a/tool/comtool/form/frmcomtool.cpp b/tool/comtool/form/frmcomtool.cpp new file mode 100644 index 0000000..86f88ee --- /dev/null +++ b/tool/comtool/form/frmcomtool.cpp @@ -0,0 +1,587 @@ +#include "frmcomtool.h" +#include "ui_frmcomtool.h" +#include "qthelper.h" +#include "qthelperdata.h" + +frmComTool::frmComTool(QWidget *parent) : QWidget(parent), ui(new Ui::frmComTool) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); + QtHelper::setFormInCenter(this); +} + +frmComTool::~frmComTool() +{ + delete ui; +} + +void frmComTool::initForm() +{ + comOk = false; + com = 0; + sleepTime = 10; + receiveCount = 0; + sendCount = 0; + isShow = true; + + ui->cboxSendInterval->addItems(AppData::Intervals); + ui->cboxData->addItems(AppData::Datas); + + //读取数据 + timerRead = new QTimer(this); + timerRead->setInterval(100); + connect(timerRead, SIGNAL(timeout()), this, SLOT(readData())); + + //发送数据 + timerSend = new QTimer(this); + connect(timerSend, SIGNAL(timeout()), this, SLOT(sendData())); + connect(ui->btnSend, SIGNAL(clicked()), this, SLOT(sendData())); + + //保存数据 + timerSave = new QTimer(this); + connect(timerSave, SIGNAL(timeout()), this, SLOT(saveData())); + connect(ui->btnSave, SIGNAL(clicked()), this, SLOT(saveData())); + + ui->tabWidget->setCurrentIndex(0); + changeEnable(false); + + tcpOk = false; + socket = new QTcpSocket(this); + socket->abort(); + connect(socket, SIGNAL(readyRead()), this, SLOT(readDataNet())); +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(readErrorNet())); +#else + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(readErrorNet())); +#endif + + timerConnect = new QTimer(this); + connect(timerConnect, SIGNAL(timeout()), this, SLOT(connectNet())); + timerConnect->setInterval(3000); + timerConnect->start(); + +#ifdef __arm__ + ui->widgetRight->setFixedWidth(280); +#endif +} + +void frmComTool::initConfig() +{ + QStringList comList; + for (int i = 1; i <= 20; i++) { + comList << QString("COM%1").arg(i); + } + + comList << "ttyUSB0" << "ttyS0" << "ttyS1" << "ttyS2" << "ttyS3" << "ttyS4"; + comList << "ttymxc1" << "ttymxc2" << "ttymxc3" << "ttymxc4"; + comList << "ttySAC1" << "ttySAC2" << "ttySAC3" << "ttySAC4"; + ui->cboxPortName->addItems(comList); + ui->cboxPortName->setCurrentIndex(ui->cboxPortName->findText(AppConfig::PortName)); + connect(ui->cboxPortName, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + QStringList baudList; + baudList << "50" << "75" << "100" << "134" << "150" << "200" << "300" << "600" << "1200" + << "1800" << "2400" << "4800" << "9600" << "14400" << "19200" << "38400" + << "56000" << "57600" << "76800" << "115200" << "128000" << "256000"; + + ui->cboxBaudRate->addItems(baudList); + ui->cboxBaudRate->setCurrentIndex(ui->cboxBaudRate->findText(QString::number(AppConfig::BaudRate))); + connect(ui->cboxBaudRate, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + QStringList dataBitsList; + dataBitsList << "5" << "6" << "7" << "8"; + + ui->cboxDataBit->addItems(dataBitsList); + ui->cboxDataBit->setCurrentIndex(ui->cboxDataBit->findText(QString::number(AppConfig::DataBit))); + connect(ui->cboxDataBit, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + QStringList parityList; + parityList << "无" << "奇" << "偶"; +#ifdef Q_OS_WIN + parityList << "标志"; +#endif + parityList << "空格"; + + ui->cboxParity->addItems(parityList); + ui->cboxParity->setCurrentIndex(ui->cboxParity->findText(AppConfig::Parity)); + connect(ui->cboxParity, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + QStringList stopBitsList; + stopBitsList << "1"; +#ifdef Q_OS_WIN + stopBitsList << "1.5"; +#endif + stopBitsList << "2"; + + ui->cboxStopBit->addItems(stopBitsList); + ui->cboxStopBit->setCurrentIndex(ui->cboxStopBit->findText(QString::number(AppConfig::StopBit))); + connect(ui->cboxStopBit, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexSend->setChecked(AppConfig::HexSend); + connect(ui->ckHexSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexReceive->setChecked(AppConfig::HexReceive); + connect(ui->ckHexReceive, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckDebug->setChecked(AppConfig::Debug); + connect(ui->ckDebug, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoClear->setChecked(AppConfig::AutoClear); + connect(ui->ckAutoClear, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSend->setChecked(AppConfig::AutoSend); + connect(ui->ckAutoSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSave->setChecked(AppConfig::AutoSave); + connect(ui->ckAutoSave, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + QStringList sendInterval; + QStringList saveInterval; + sendInterval << "100" << "300" << "500"; + + for (int i = 1000; i <= 10000; i = i + 1000) { + sendInterval << QString::number(i); + saveInterval << QString::number(i); + } + + ui->cboxSendInterval->addItems(sendInterval); + ui->cboxSaveInterval->addItems(saveInterval); + + ui->cboxSendInterval->setCurrentIndex(ui->cboxSendInterval->findText(QString::number(AppConfig::SendInterval))); + connect(ui->cboxSendInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + ui->cboxSaveInterval->setCurrentIndex(ui->cboxSaveInterval->findText(QString::number(AppConfig::SaveInterval))); + connect(ui->cboxSaveInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + timerSend->setInterval(AppConfig::SendInterval); + timerSave->setInterval(AppConfig::SaveInterval); + + if (AppConfig::AutoSend) { + timerSend->start(); + } + + if (AppConfig::AutoSave) { + timerSave->start(); + } + + //串口转网络部分 + ui->cboxMode->setCurrentIndex(ui->cboxMode->findText(AppConfig::Mode)); + connect(ui->cboxMode, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->txtServerIP->setText(AppConfig::ServerIP); + connect(ui->txtServerIP, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtServerPort->setText(QString::number(AppConfig::ServerPort)); + connect(ui->txtServerPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtListenPort->setText(QString::number(AppConfig::ListenPort)); + connect(ui->txtListenPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + QStringList values; + values << "0" << "10" << "50"; + + for (int i = 100; i < 1000; i = i + 100) { + values << QString("%1").arg(i); + } + + ui->cboxSleepTime->addItems(values); + + ui->cboxSleepTime->setCurrentIndex(ui->cboxSleepTime->findText(QString::number(AppConfig::SleepTime))); + connect(ui->cboxSleepTime, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoConnect->setChecked(AppConfig::AutoConnect); + connect(ui->ckAutoConnect, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); +} + +void frmComTool::saveConfig() +{ + AppConfig::PortName = ui->cboxPortName->currentText(); + AppConfig::BaudRate = ui->cboxBaudRate->currentText().toInt(); + AppConfig::DataBit = ui->cboxDataBit->currentText().toInt(); + AppConfig::Parity = ui->cboxParity->currentText(); + AppConfig::StopBit = ui->cboxStopBit->currentText().toDouble(); + + AppConfig::HexSend = ui->ckHexSend->isChecked(); + AppConfig::HexReceive = ui->ckHexReceive->isChecked(); + AppConfig::Debug = ui->ckDebug->isChecked(); + AppConfig::AutoClear = ui->ckAutoClear->isChecked(); + + AppConfig::AutoSend = ui->ckAutoSend->isChecked(); + AppConfig::AutoSave = ui->ckAutoSave->isChecked(); + + int sendInterval = ui->cboxSendInterval->currentText().toInt(); + if (sendInterval != AppConfig::SendInterval) { + AppConfig::SendInterval = sendInterval; + timerSend->setInterval(AppConfig::SendInterval); + } + + int saveInterval = ui->cboxSaveInterval->currentText().toInt(); + if (saveInterval != AppConfig::SaveInterval) { + AppConfig::SaveInterval = saveInterval; + timerSave->setInterval(AppConfig::SaveInterval); + } + + AppConfig::Mode = ui->cboxMode->currentText(); + AppConfig::ServerIP = ui->txtServerIP->text().trimmed(); + AppConfig::ServerPort = ui->txtServerPort->text().toInt(); + AppConfig::ListenPort = ui->txtListenPort->text().toInt(); + AppConfig::SleepTime = ui->cboxSleepTime->currentText().toInt(); + AppConfig::AutoConnect = ui->ckAutoConnect->isChecked(); + + AppConfig::writeConfig(); +} + +void frmComTool::changeEnable(bool b) +{ + ui->cboxBaudRate->setEnabled(!b); + ui->cboxDataBit->setEnabled(!b); + ui->cboxParity->setEnabled(!b); + ui->cboxPortName->setEnabled(!b); + ui->cboxStopBit->setEnabled(!b); + ui->btnSend->setEnabled(b); + ui->ckAutoSend->setEnabled(b); + ui->ckAutoSave->setEnabled(b); +} + +void frmComTool::append(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + + if (clear) { + ui->txtMain->clear(); + currentCount = 0; + return; + } + + if (currentCount >= maxCount) { + ui->txtMain->clear(); + currentCount = 0; + } + + if (!isShow) { + return; + } + + //过滤回车换行符 + QString strData = data; + strData = strData.replace("\r", ""); + strData = strData.replace("\n", ""); + + //不同类型不同颜色显示 + QString strType; + if (type == 0) { + strType = "串口发送 >>"; + ui->txtMain->setTextColor(QColor("dodgerblue")); + } else if (type == 1) { + strType = "串口接收 <<"; + ui->txtMain->setTextColor(QColor("red")); + } else if (type == 2) { + strType = "处理延时 >>"; + ui->txtMain->setTextColor(QColor("gray")); + } else if (type == 3) { + strType = "正在校验 >>"; + ui->txtMain->setTextColor(QColor("green")); + } else if (type == 4) { + strType = "网络发送 >>"; + ui->txtMain->setTextColor(QColor(24, 189, 155)); + } else if (type == 5) { + strType = "网络接收 <<"; + ui->txtMain->setTextColor(QColor(255, 107, 107)); + } else if (type == 6) { + strType = "提示信息 >>"; + ui->txtMain->setTextColor(QColor(100, 184, 255)); + } + + strData = QString("时间[%1] %2 %3").arg(TIMEMS).arg(strType).arg(strData); + ui->txtMain->append(strData); + currentCount++; +} + +void frmComTool::readData() +{ + if (com->bytesAvailable() <= 0) { + return; + } + + QtHelper::sleep(sleepTime); + QByteArray data = com->readAll(); + int dataLen = data.length(); + if (dataLen <= 0) { + return; + } + + if (isShow) { + QString buffer; + if (ui->ckHexReceive->isChecked()) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else { + //buffer = QtHelperData::byteArrayToAsciiStr(data); + buffer = QString::fromLocal8Bit(data); + } + + //启用调试则模拟调试数据 + if (ui->ckDebug->isChecked()) { + int count = AppData::Keys.count(); + for (int i = 0; i < count; i++) { + if (buffer.startsWith(AppData::Keys.at(i))) { + sendData(AppData::Values.at(i)); + break; + } + } + } + + append(1, buffer); + receiveCount = receiveCount + data.size(); + ui->btnReceiveCount->setText(QString("接收 : %1 字节").arg(receiveCount)); + + //启用网络转发则调用网络发送数据 + if (tcpOk) { + socket->write(data); + append(4, QString(buffer)); + } + } +} + +void frmComTool::sendData() +{ + QString str = ui->cboxData->currentText(); + if (str.isEmpty()) { + ui->cboxData->setFocus(); + return; + } + + sendData(str); + + if (ui->ckAutoClear->isChecked()) { + ui->cboxData->setCurrentIndex(-1); + ui->cboxData->setFocus(); + } +} + +void frmComTool::sendData(QString data) +{ + if (com == 0 || !com->isOpen()) { + return; + } + + //短信猫调试 + if (data.startsWith("AT")) { + data += "\r"; + } + + QByteArray buffer; + if (ui->ckHexSend->isChecked()) { + buffer = QtHelperData::hexStrToByteArray(data); + } else { + buffer = QtHelperData::asciiStrToByteArray(data); + } + + com->write(buffer); + append(0, data); + sendCount = sendCount + buffer.size(); + ui->btnSendCount->setText(QString("发送 : %1 字节").arg(sendCount)); +} + +void frmComTool::saveData() +{ + QString tempData = ui->txtMain->toPlainText(); + if (tempData.isEmpty()) { + return; + } + + QDateTime now = QDateTime::currentDateTime(); + QString name = now.toString("yyyy-MM-dd-HH-mm-ss"); + QString fileName = QString("%1/%2.txt").arg(QtHelper::appPath()).arg(name); + + QFile file(fileName); + file.open(QFile::WriteOnly | QIODevice::Text); + QTextStream out(&file); + out << tempData; + file.close(); + + on_btnClear_clicked(); +} + +void frmComTool::on_btnOpen_clicked() +{ + if (ui->btnOpen->text() == "打开串口") { + com = new QextSerialPort(ui->cboxPortName->currentText(), QextSerialPort::Polling); + comOk = com->open(QIODevice::ReadWrite); + + if (comOk) { + //清空缓冲区 + com->flush(); + //设置波特率 + com->setBaudRate((BaudRateType)ui->cboxBaudRate->currentText().toInt()); + //设置数据位 + com->setDataBits((DataBitsType)ui->cboxDataBit->currentText().toInt()); + //设置校验位 + com->setParity((ParityType)ui->cboxParity->currentIndex()); + //设置停止位 + com->setStopBits((StopBitsType)ui->cboxStopBit->currentIndex()); + com->setFlowControl(FLOW_OFF); + com->setTimeout(10); + + changeEnable(true); + ui->btnOpen->setText("关闭串口"); + timerRead->start(); + } + } else { + timerRead->stop(); + com->close(); + com->deleteLater(); + + changeEnable(false); + ui->btnOpen->setText("打开串口"); + on_btnClear_clicked(); + comOk = false; + } +} + +void frmComTool::on_btnSendCount_clicked() +{ + sendCount = 0; + ui->btnSendCount->setText("发送 : 0 字节"); +} + +void frmComTool::on_btnReceiveCount_clicked() +{ + receiveCount = 0; + ui->btnReceiveCount->setText("接收 : 0 字节"); +} + +void frmComTool::on_btnStopShow_clicked() +{ + if (ui->btnStopShow->text() == "停止显示") { + isShow = false; + ui->btnStopShow->setText("开始显示"); + } else { + isShow = true; + ui->btnStopShow->setText("停止显示"); + } +} + +void frmComTool::on_btnData_clicked() +{ + QString fileName = QString("%1/%2").arg(QtHelper::appPath()).arg("send.txt"); + QFile file(fileName); + if (!file.exists()) { + return; + } + + if (ui->btnData->text() == "管理数据") { + ui->txtMain->setReadOnly(false); + ui->txtMain->clear(); + file.open(QFile::ReadOnly | QIODevice::Text); + QTextStream in(&file); + ui->txtMain->setText(in.readAll()); + file.close(); + ui->btnData->setText("保存数据"); + } else { + ui->txtMain->setReadOnly(true); + file.open(QFile::WriteOnly | QIODevice::Text); + QTextStream out(&file); + out << ui->txtMain->toPlainText(); + file.close(); + ui->txtMain->clear(); + ui->btnData->setText("管理数据"); + AppData::readSendData(); + } +} + +void frmComTool::on_btnClear_clicked() +{ + append(0, "", true); +} + +void frmComTool::on_btnStart_clicked() +{ + if (ui->btnStart->text() == "启动") { + if (AppConfig::ServerIP == "" || AppConfig::ServerPort == 0) { + append(6, "IP地址和远程端口不能为空"); + return; + } + + socket->connectToHost(AppConfig::ServerIP, AppConfig::ServerPort); + if (socket->waitForConnected(100)) { + ui->btnStart->setText("停止"); + append(6, "连接服务器成功"); + tcpOk = true; + } + } else { + socket->disconnectFromHost(); + if (socket->state() == QAbstractSocket::UnconnectedState || socket->waitForDisconnected(100)) { + ui->btnStart->setText("启动"); + append(6, "断开服务器成功"); + tcpOk = false; + } + } +} + +void frmComTool::on_ckAutoSend_stateChanged(int arg1) +{ + if (arg1 == 0) { + ui->cboxSendInterval->setEnabled(false); + timerSend->stop(); + } else { + ui->cboxSendInterval->setEnabled(true); + timerSend->start(); + } +} + +void frmComTool::on_ckAutoSave_stateChanged(int arg1) +{ + if (arg1 == 0) { + ui->cboxSaveInterval->setEnabled(false); + timerSave->stop(); + } else { + ui->cboxSaveInterval->setEnabled(true); + timerSave->start(); + } +} + +void frmComTool::connectNet() +{ + if (!tcpOk && AppConfig::AutoConnect && ui->btnStart->text() == "启动") { + if (AppConfig::ServerIP != "" && AppConfig::ServerPort != 0) { + socket->connectToHost(AppConfig::ServerIP, AppConfig::ServerPort); + if (socket->waitForConnected(100)) { + ui->btnStart->setText("停止"); + append(6, "连接服务器成功"); + tcpOk = true; + } + } + } +} + +void frmComTool::readDataNet() +{ + if (socket->bytesAvailable() > 0) { + QtHelper::sleep(AppConfig::SleepTime); + QByteArray data = socket->readAll(); + + QString buffer; + if (ui->ckHexReceive->isChecked()) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else { + buffer = QtHelperData::byteArrayToAsciiStr(data); + } + + append(5, buffer); + + //将收到的网络数据转发给串口 + if (comOk) { + com->write(data); + append(0, buffer); + } + } +} + +void frmComTool::readErrorNet() +{ + ui->btnStart->setText("启动"); + append(6, QString("连接服务器失败,%1").arg(socket->errorString())); + socket->disconnectFromHost(); + tcpOk = false; +} diff --git a/tool/comtool/form/frmcomtool.h b/tool/comtool/form/frmcomtool.h new file mode 100644 index 0000000..e25f0cb --- /dev/null +++ b/tool/comtool/form/frmcomtool.h @@ -0,0 +1,70 @@ +#ifndef FRMCOMTOOL_H +#define FRMCOMTOOL_H + +#include +#include "qtcpsocket.h" +#include "qextserialport.h" + +namespace Ui +{ +class frmComTool; +} + +class frmComTool : public QWidget +{ + Q_OBJECT + +public: + explicit frmComTool(QWidget *parent = 0); + ~frmComTool(); + +private: + Ui::frmComTool *ui; + + bool comOk; //串口是否打开 + QextSerialPort *com; //串口通信对象 + QTimer *timerRead; //定时读取串口数据 + QTimer *timerSend; //定时发送串口数据 + QTimer *timerSave; //定时保存串口数据 + + int sleepTime; //接收延时时间 + int sendCount; //发送数据计数 + int receiveCount; //接收数据计数 + bool isShow; //是否显示数据 + + bool tcpOk; //网络是否正常 + QTcpSocket *socket; //网络连接对象 + QTimer *timerConnect; //定时器重连 + +private slots: + void initForm(); //初始化窗体数据 + void initConfig(); //初始化配置文件 + void saveConfig(); //保存配置文件 + void readData(); //读取串口数据 + void sendData(); //发送串口数据 + void sendData(QString data);//发送串口数据带参数 + void saveData(); //保存串口数据 + + void changeEnable(bool b); //改变状态 + void append(int type, const QString &data, bool clear = false); + +private slots: + void connectNet(); + void readDataNet(); + void readErrorNet(); + +private slots: + void on_btnOpen_clicked(); + void on_btnStopShow_clicked(); + void on_btnSendCount_clicked(); + void on_btnReceiveCount_clicked(); + + void on_btnClear_clicked(); + void on_btnData_clicked(); + void on_btnStart_clicked(); + + void on_ckAutoSend_stateChanged(int arg1); + void on_ckAutoSave_stateChanged(int arg1); +}; + +#endif // FRMCOMTOOL_H diff --git a/tool/comtool/form/frmcomtool.ui b/tool/comtool/form/frmcomtool.ui new file mode 100644 index 0000000..49d3621 --- /dev/null +++ b/tool/comtool/form/frmcomtool.ui @@ -0,0 +1,533 @@ + + + frmComTool + + + + 0 + 0 + 800 + 600 + + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + QFrame::StyledPanel + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAsNeeded + + + true + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Box + + + QFrame::Sunken + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 串口号 + + + + + + + + 1 + 0 + + + + true + + + + + + + 波特率 + + + + + + + + 1 + 0 + + + + true + + + + + + + 数据位 + + + + + + + + 1 + 0 + + + + + + + + 校验位 + + + + + + + + 1 + 0 + + + + + + + + 停止位 + + + + + + + + 1 + 0 + + + + + + + + 打开串口 + + + + + + + + + + QTabWidget::South + + + 0 + + + + 串口配置 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Hex发送 + + + + + + + Hex接收 + + + + + + + 模拟设备 + + + + + + + 自动清空 + + + + + + + + + 自动发送 + + + + + + + + 0 + 0 + + + + + + + + 自动保存 + + + + + + + + 0 + 0 + + + + + + + + + + 发送 : 0 字节 + + + + + + + 接收 : 0 字节 + + + + + + + 停止显示 + + + + + + + 保存数据 + + + + + + + 管理数据 + + + + + + + 清空数据 + + + + + + + Qt::Vertical + + + + 20 + 2 + + + + + + + + + 网络配置 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + + 监听端口 + + + + + + + 远程地址 + + + + + + + + + + + + + + + + + 远程端口 + + + + + + + + + + + + + + 延时时间 + + + + + + + + + + 转换模式 + + + + + + + + Tcp_Client + + + + + Tcp_Server + + + + + Udp_Client + + + + + Udp_Server + + + + + + + + + + 启动 + + + + + + + Qt::Vertical + + + + 20 + 59 + + + + + + + + 自动重连网络 + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + false + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 发送 + + + + + + + + + + + diff --git a/tool/comtool/head.h b/tool/comtool/head.h new file mode 100644 index 0000000..2f5ee75 --- /dev/null +++ b/tool/comtool/head.h @@ -0,0 +1,18 @@ +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) +#include +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +#include +#endif + +#pragma execution_character_set("utf-8") +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) +#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")) + +#include "appconfig.h" +#include "appdata.h" diff --git a/tool/comtool/main.cpp b/tool/comtool/main.cpp new file mode 100644 index 0000000..42259f0 --- /dev/null +++ b/tool/comtool/main.cpp @@ -0,0 +1,33 @@ +#include "frmcomtool.h" +#include "qthelper.h" + +int main(int argc, char *argv[]) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + QApplication::setAttribute(Qt::AA_Use96Dpi); +#endif +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor); +#endif + + QApplication a(argc, argv); + a.setWindowIcon(QIcon(":/main.ico")); + + //设置编码以及加载中文翻译文件 + QtHelper::initAll(); + //读取配置文件 + AppConfig::ConfigFile = QString("%1/%2.ini").arg(QtHelper::appPath()).arg(QtHelper::appName()); + AppConfig::readConfig(); + + AppData::Intervals << "1" << "10" << "20" << "50" << "100" << "200" << "300" << "500" << "1000" << "1500" << "2000" << "3000" << "5000" << "10000"; + AppData::readSendData(); + AppData::readDeviceData(); + + frmComTool w; + w.setWindowTitle("串口调试助手 V2023 (QQ: 517216493 WX: feiyangqingyun)"); + w.resize(900, 650); + QtHelper::setFormInCenter(&w); + w.show(); + + return a.exec(); +} diff --git a/tool/comtool/qrc/main.ico b/tool/comtool/qrc/main.ico new file mode 100644 index 0000000..3a69f0a Binary files /dev/null and b/tool/comtool/qrc/main.ico differ diff --git a/tool/comtool/qrc/main.qrc b/tool/comtool/qrc/main.qrc new file mode 100644 index 0000000..8bd6284 --- /dev/null +++ b/tool/comtool/qrc/main.qrc @@ -0,0 +1,7 @@ + + + main.ico + qm/qt_zh_CN.qm + qm/widgets.qm + + diff --git a/tool/comtool/qrc/main.rc b/tool/comtool/qrc/main.rc new file mode 100644 index 0000000..fc0d770 --- /dev/null +++ b/tool/comtool/qrc/main.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "main.ico" \ No newline at end of file diff --git a/tool/comtool/qrc/qm/qt_zh_CN.qm b/tool/comtool/qrc/qm/qt_zh_CN.qm new file mode 100644 index 0000000..623b8e3 Binary files /dev/null and b/tool/comtool/qrc/qm/qt_zh_CN.qm differ diff --git a/tool/comtool/qrc/qm/widgets.qm b/tool/comtool/qrc/qm/widgets.qm new file mode 100644 index 0000000..244bf0d Binary files /dev/null and b/tool/comtool/qrc/qm/widgets.qm differ diff --git a/tool/comtool/readme.md b/tool/comtool/readme.md new file mode 100644 index 0000000..03eb0ed --- /dev/null +++ b/tool/comtool/readme.md @@ -0,0 +1,18 @@ +**** +1. ֧16ݷա +2. ֧windowsCOM9ϵĴͨš +3. ʵʱʾշֽڴСԼ״̬ +4. ֧qt汾ײ4.7.0 6.1 +5. ִ֧תշ + +**߼** +1. ɹҪ͵ݣÿֻҪѡݼɣݡ +2. ģ豸ظݣҪ濪ģ豸ظݡյúõָʱظõĻظָָյ0x16 0x00 0xFF 0x01Ҫظ0x16 0x00 0xFE 0x01ֻҪSendData.txtһ16 00 FF 01:16 00 FE 01ɡ +3. ɶʱݺͱݵıļ:Ĭϼ5ӣɸļʱ䡣 +4. ڲϽյʱͣʾ鿴ݣ̨Ȼݵرմ鿴ѽյݡ +5. ÿյݶһݣѽڵģʱ +6. һԴ洦룬Ĵͨ࣬XP/WIN7/UBUNTU/ARMLINUXϵͳ³ɹ벢С + +**˵** +1. 뽫ԴµfileĿ¼еļƵִļͬһĿ¼ +2. иõĽԣлл \ No newline at end of file diff --git a/tool/countcode/countcode.pro b/tool/countcode/countcode.pro new file mode 100644 index 0000000..e1d8f74 --- /dev/null +++ b/tool/countcode/countcode.pro @@ -0,0 +1,14 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = countcode +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmcountcode.cpp +HEADERS += frmcountcode.h +FORMS += frmcountcode.ui + diff --git a/tool/countcode/frmcountcode.cpp b/tool/countcode/frmcountcode.cpp new file mode 100644 index 0000000..f850aaa --- /dev/null +++ b/tool/countcode/frmcountcode.cpp @@ -0,0 +1,279 @@ +#pragma execution_character_set("utf-8") + +#include "frmcountcode.h" +#include "ui_frmcountcode.h" +#include "qfile.h" +#include "qtextstream.h" +#include "qfiledialog.h" +#include "qfileinfo.h" +#include "qdebug.h" + +frmCountCode::frmCountCode(QWidget *parent) : QWidget(parent), ui(new Ui::frmCountCode) +{ + ui->setupUi(this); + this->initForm(); + on_btnClear_clicked(); +} + +frmCountCode::~frmCountCode() +{ + delete ui; +} + +void frmCountCode::initForm() +{ + QStringList headText; + headText << "文件名" << "类型" << "大小" << "总行数" << "代码行数" << "注释行数" << "空白行数" << "路径"; + QList columnWidth; + columnWidth << 130 << 50 << 70 << 80 << 70 << 70 << 70 << 150; + + int columnCount = headText.count(); + ui->tableWidget->setColumnCount(columnCount); + ui->tableWidget->setHorizontalHeaderLabels(headText); + ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); + ui->tableWidget->verticalHeader()->setVisible(false); + ui->tableWidget->horizontalHeader()->setStretchLastSection(true); + ui->tableWidget->horizontalHeader()->setHighlightSections(false); + ui->tableWidget->verticalHeader()->setDefaultSectionSize(20); + ui->tableWidget->verticalHeader()->setHighlightSections(false); + + for (int i = 0; i < columnCount; i++) { + ui->tableWidget->setColumnWidth(i, columnWidth.at(i)); + } + + //设置前景色 + ui->txtCount->setStyleSheet("color:#17A086;"); + ui->txtSize->setStyleSheet("color:#CA5AA6;"); + ui->txtRow->setStyleSheet("color:#CD1B19;"); + ui->txtCode->setStyleSheet("color:#22A3A9;"); + ui->txtNote->setStyleSheet("color:#D64D54;"); + ui->txtBlank->setStyleSheet("color:#A279C5;"); + + //设置字体加粗 + QFont font; + font.setBold(true); + if (font.pointSize() > 0) { + font.setPointSize(font.pointSize() + 1); + } else { + font.setPixelSize(font.pixelSize() + 2); + } + + ui->txtCount->setFont(font); + ui->txtSize->setFont(font); + ui->txtRow->setFont(font); + ui->txtCode->setFont(font); + ui->txtNote->setFont(font); + ui->txtBlank->setFont(font); + +#if (QT_VERSION > QT_VERSION_CHECK(4,7,0)) + ui->txtFilter->setPlaceholderText("中间空格隔开,例如 *.h *.cpp *.c"); +#endif +} + +bool frmCountCode::checkFile(const QString &fileName) +{ + if (fileName.startsWith("moc_") || fileName.startsWith("ui_") || fileName.startsWith("qrc_")) { + return false; + } + + QFileInfo file(fileName); + QString suffix = "*." + file.suffix(); + QString filter = ui->txtFilter->text().trimmed(); + QStringList filters = filter.split(" "); + return filters.contains(suffix); +} + +void frmCountCode::countCode(const QString &filePath) +{ + QDir dir(filePath); + QFileInfoList fileInfos = dir.entryInfoList(); + foreach (QFileInfo fileInfo, fileInfos) { + QString fileName = fileInfo.fileName(); + if (fileInfo.isFile()) { + if (checkFile(fileName)) { + listFile << fileInfo.filePath(); + } + } else { + if (fileName == "." || fileName == "..") { + continue; + } + + //递归找出文件 + countCode(fileInfo.absoluteFilePath()); + } + } +} + +void frmCountCode::countCode(const QStringList &files) +{ + int lineCode; + int lineBlank; + int lineNotes; + int count = files.count(); + on_btnClear_clicked(); + ui->tableWidget->setRowCount(count); + + quint32 totalLines = 0; + quint32 totalBytes = 0; + quint32 totalCodes = 0; + quint32 totalNotes = 0; + quint32 totalBlanks = 0; + + for (int i = 0; i < count; i++) { + QFileInfo fileInfo(files.at(i)); + countCode(fileInfo.filePath(), lineCode, lineBlank, lineNotes); + int lineAll = lineCode + lineBlank + lineNotes; + + QTableWidgetItem *itemName = new QTableWidgetItem; + itemName->setText(fileInfo.fileName()); + + QTableWidgetItem *itemSuffix = new QTableWidgetItem; + itemSuffix->setText(fileInfo.suffix()); + + QTableWidgetItem *itemSize = new QTableWidgetItem; + itemSize->setText(QString::number(fileInfo.size())); + + QTableWidgetItem *itemLine = new QTableWidgetItem; + itemLine->setText(QString::number(lineAll)); + + QTableWidgetItem *itemCode = new QTableWidgetItem; + itemCode->setText(QString::number(lineCode)); + + QTableWidgetItem *itemNote = new QTableWidgetItem; + itemNote->setText(QString::number(lineNotes)); + + QTableWidgetItem *itemBlank = new QTableWidgetItem; + itemBlank->setText(QString::number(lineBlank)); + + QTableWidgetItem *itemPath = new QTableWidgetItem; + itemPath->setText(fileInfo.filePath()); + + itemSuffix->setTextAlignment(Qt::AlignCenter); + itemSize->setTextAlignment(Qt::AlignCenter); + itemLine->setTextAlignment(Qt::AlignCenter); + itemCode->setTextAlignment(Qt::AlignCenter); + itemNote->setTextAlignment(Qt::AlignCenter); + itemBlank->setTextAlignment(Qt::AlignCenter); + + ui->tableWidget->setItem(i, 0, itemName); + ui->tableWidget->setItem(i, 1, itemSuffix); + ui->tableWidget->setItem(i, 2, itemSize); + ui->tableWidget->setItem(i, 3, itemLine); + ui->tableWidget->setItem(i, 4, itemCode); + ui->tableWidget->setItem(i, 5, itemNote); + ui->tableWidget->setItem(i, 6, itemBlank); + ui->tableWidget->setItem(i, 7, itemPath); + + totalBytes += fileInfo.size(); + totalLines += lineAll; + totalCodes += lineCode; + totalNotes += lineNotes; + totalBlanks += lineBlank; + + if (i % 100 == 0) { + qApp->processEvents(); + } + } + + //显示统计结果 + listFile.clear(); + ui->txtCount->setText(QString::number(count)); + ui->txtSize->setText(QString::number(totalBytes)); + ui->txtRow->setText(QString::number(totalLines)); + ui->txtCode->setText(QString::number(totalCodes)); + ui->txtNote->setText(QString::number(totalNotes)); + ui->txtBlank->setText(QString::number(totalBlanks)); + + //计算百分比 + double percent = 0.0; + //代码行所占百分比 + percent = ((double)totalCodes / totalLines) * 100; + ui->labPercentCode->setText(QString("%1%").arg(percent, 5, 'f', 2, QChar(' '))); + //注释行所占百分比 + percent = ((double)totalNotes / totalLines) * 100; + ui->labPercentNote->setText(QString("%1%").arg(percent, 5, 'f', 2, QChar(' '))); + //空行所占百分比 + percent = ((double)totalBlanks / totalLines) * 100; + ui->labPercentBlank->setText(QString("%1%").arg(percent, 5, 'f', 2, QChar(' '))); +} + +void frmCountCode::countCode(const QString &fileName, int &lineCode, int &lineBlank, int &lineNotes) +{ + lineCode = lineBlank = lineNotes = 0; + QFile file(fileName); + if (file.open(QFile::ReadOnly)) { + QTextStream out(&file); + QString line; + bool isNote = false; + while (!out.atEnd()) { + line = out.readLine(); + + //移除前面的空行 + if (line.startsWith(" ")) { + line.remove(" "); + } + + //判断当前行是否是注释 + if (line.startsWith("/*")) { + isNote = true; + } + + //注释部分 + if (isNote) { + lineNotes++; + } else { + if (line.startsWith("//")) { //注释行 + lineNotes++; + } else if (line.isEmpty()) { //空白行 + lineBlank++; + } else { //代码行 + lineCode++; + } + } + + //注释结束 + if (line.endsWith("*/")) { + isNote = false; + } + } + } +} + +void frmCountCode::on_btnOpenFile_clicked() +{ + QString filter = QString("代码文件(%1)").arg(ui->txtFilter->text().trimmed()); + QStringList files = QFileDialog::getOpenFileNames(this, "选择文件", "./", filter); + if (files.size() > 0) { + ui->txtFile->setText(files.join("|")); + countCode(files); + } +} + +void frmCountCode::on_btnOpenPath_clicked() +{ + QString path = QFileDialog::getExistingDirectory(this, "选择目录", "./", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (!path.isEmpty()) { + ui->txtPath->setText(path); + listFile.clear(); + countCode(path); + countCode(listFile); + } +} + +void frmCountCode::on_btnClear_clicked() +{ + ui->txtCount->setText("0"); + ui->txtSize->setText("0"); + ui->txtRow->setText("0"); + + ui->txtCode->setText("0"); + ui->txtNote->setText("0"); + ui->txtBlank->setText("0"); + + ui->labPercentCode->setText("0%"); + ui->labPercentNote->setText("0%"); + ui->labPercentBlank->setText("0%"); + ui->tableWidget->setRowCount(0); +} diff --git a/tool/countcode/frmcountcode.h b/tool/countcode/frmcountcode.h new file mode 100644 index 0000000..f35f45b --- /dev/null +++ b/tool/countcode/frmcountcode.h @@ -0,0 +1,35 @@ +#ifndef FRMCOUNTCODE_H +#define FRMCOUNTCODE_H + +#include + +namespace Ui { +class frmCountCode; +} + +class frmCountCode : public QWidget +{ + Q_OBJECT + +public: + explicit frmCountCode(QWidget *parent = 0); + ~frmCountCode(); + +private: + Ui::frmCountCode *ui; + QStringList listFile; + +private: + void initForm(); + bool checkFile(const QString &fileName); + void countCode(const QString &filePath); + void countCode(const QStringList &files); + void countCode(const QString &fileName, int &lineCode, int &lineBlank, int &lineNotes); + +private slots: + void on_btnOpenFile_clicked(); + void on_btnOpenPath_clicked(); + void on_btnClear_clicked(); +}; + +#endif // FRMCOUNTCODE_H diff --git a/tool/countcode/frmcountcode.ui b/tool/countcode/frmcountcode.ui new file mode 100644 index 0000000..3913afa --- /dev/null +++ b/tool/countcode/frmcountcode.ui @@ -0,0 +1,411 @@ + + + frmCountCode + + + + 0 + 0 + 800 + 600 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 80 + 16777215 + + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + Qt::AlignCenter + + + true + + + + + + + + 80 + 16777215 + + + + Qt::AlignCenter + + + true + + + + + + + + 60 + 0 + + + + QFrame::Box + + + QFrame::Sunken + + + + + + Qt::AlignCenter + + + + + + + 空白行数 + + + + + + + + 0 + 0 + + + + Qt::AlignCenter + + + true + + + + + + + 过滤 + + + + + + + 文件 + + + + + + + true + + + + + + + true + + + + + + + 目录 + + + + + + + *.h *.cpp *.c *.cs *.java *.js + + + + + + + QFrame::Box + + + QFrame::Sunken + + + + + + Qt::AlignCenter + + + + + + + QFrame::Box + + + QFrame::Sunken + + + + + + Qt::AlignCenter + + + + + + + 文件数 + + + + + + + 代码行数 + + + + + + + 注释行数 + + + + + + + 字节数 + + + + + + + 总行数 + + + + + + + + + 打开文件 + + + + + + + 打开目录 + + + + + + + 清空结果 + + + + + + + + + + + :/images/toolbar/ic_files.png:/images/toolbar/ic_files.png + + + 选择文件 + + + Ctrl+O + + + + + + :/images/toolbar/ic_folder.png:/images/toolbar/ic_folder.png + + + 选择目录 + + + Ctrl+Shift+O + + + + + + :/images/toolbar/ic_about.png:/images/toolbar/ic_about.png + + + 关于 + + + + + + :/images/toolbar/ic_clean.png:/images/toolbar/ic_clean.png + + + 清空列表 + + + + + + :/images/toolbar/ic_delete.png:/images/toolbar/ic_delete.png + + + 删除选中行 + + + + + true + + + true + + + 中文 + + + + + true + + + English + + + + + true + + + true + + + UTF8 + + + + + true + + + GB18030 + + + + + 退出 + + + Ctrl+Q + + + + + + btnOpenFile + btnOpenPath + btnClear + tableWidget + txtCount + txtSize + txtRow + txtCode + txtNote + txtBlank + txtFile + txtPath + txtFilter + + + + diff --git a/tool/countcode/main.cpp b/tool/countcode/main.cpp new file mode 100644 index 0000000..e98ee15 --- /dev/null +++ b/tool/countcode/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") + +#include "frmcountcode.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmCountCode w; + w.setWindowTitle("代码行数统计 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/emailtool/emailtool.pro b/tool/emailtool/emailtool.pro new file mode 100644 index 0000000..c93d19f --- /dev/null +++ b/tool/emailtool/emailtool.pro @@ -0,0 +1,17 @@ +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = emailtool +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmemailtool.cpp sendemailthread.cpp +HEADERS += frmemailtool.h sendemailthread.h +FORMS += frmemailtool.ui + +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD/../3rd_smtpclient +include ($$PWD/../3rd_smtpclient/3rd_smtpclient.pri) diff --git a/tool/emailtool/frmemailtool.cpp b/tool/emailtool/frmemailtool.cpp new file mode 100644 index 0000000..195dccc --- /dev/null +++ b/tool/emailtool/frmemailtool.cpp @@ -0,0 +1,104 @@ +#pragma execution_character_set("utf-8") + +#include "frmemailtool.h" +#include "ui_frmemailtool.h" +#include "qfiledialog.h" +#include "qmessagebox.h" +#include "sendemailthread.h" + +frmEmailTool::frmEmailTool(QWidget *parent) : QWidget(parent), ui(new Ui::frmEmailTool) +{ + ui->setupUi(this); + this->initForm(); +} + +frmEmailTool::~frmEmailTool() +{ + delete ui; +} + +void frmEmailTool::initForm() +{ + ui->cboxServer->setCurrentIndex(1); + connect(SendEmailThread::Instance(), SIGNAL(receiveEmailResult(QString)), + this, SLOT(receiveEmailResult(QString))); + SendEmailThread::Instance()->start(); +} + +void frmEmailTool::on_btnSend_clicked() +{ + if (!check()) { + return; + } + + SendEmailThread::Instance()->setEmailTitle(ui->txtTitle->text()); + SendEmailThread::Instance()->setSendEmailAddr(ui->txtSenderAddr->text()); + SendEmailThread::Instance()->setSendEmailPwd(ui->txtSenderPwd->text()); + SendEmailThread::Instance()->setReceiveEmailAddr(ui->txtReceiverAddr->text()); + + //设置好上述配置后,以后只要调用Append方法即可发送邮件 + SendEmailThread::Instance()->append(ui->txtContent->toHtml(), ui->txtFileName->text()); +} + +void frmEmailTool::on_btnSelect_clicked() +{ + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFiles); + + if (dialog.exec()) { + ui->txtFileName->clear(); + QStringList files = dialog.selectedFiles(); + ui->txtFileName->setText(files.join(";")); + } +} + +bool frmEmailTool::check() +{ + if (ui->txtSenderAddr->text() == "") { + QMessageBox::critical(this, "错误", "用户名不能为空!"); + ui->txtSenderAddr->setFocus(); + return false; + } + + if (ui->txtSenderPwd->text() == "") { + QMessageBox::critical(this, "错误", "用户密码不能为空!"); + ui->txtSenderPwd->setFocus(); + return false; + } + + if (ui->txtSenderAddr->text() == "") { + QMessageBox::critical(this, "错误", "发件人不能为空!"); + ui->txtSenderAddr->setFocus(); + return false; + } + + if (ui->txtReceiverAddr->text() == "") { + QMessageBox::critical(this, "错误", "收件人不能为空!"); + ui->txtReceiverAddr->setFocus(); + return false; + } + + if (ui->txtTitle->text() == "") { + QMessageBox::critical(this, "错误", "邮件标题不能为空!"); + ui->txtTitle->setFocus(); + return false; + } + + return true; +} + +void frmEmailTool::on_cboxServer_currentIndexChanged(int index) +{ + if (index == 2) { + ui->cboxPort->setCurrentIndex(1); + ui->ckSSL->setChecked(true); + } else { + ui->cboxPort->setCurrentIndex(0); + ui->ckSSL->setChecked(false); + } +} + +void frmEmailTool::receiveEmailResult(QString result) +{ + QMessageBox::information(this, "提示", result); +} diff --git a/tool/emailtool/frmemailtool.h b/tool/emailtool/frmemailtool.h new file mode 100644 index 0000000..0d0916f --- /dev/null +++ b/tool/emailtool/frmemailtool.h @@ -0,0 +1,35 @@ +#ifndef FRMEMAILTOOL_H +#define FRMEMAILTOOL_H + +#include + +namespace Ui +{ +class frmEmailTool; +} + +class frmEmailTool : public QWidget +{ + Q_OBJECT + +public: + explicit frmEmailTool(QWidget *parent = 0); + ~frmEmailTool(); + +private: + Ui::frmEmailTool *ui; + +private: + bool check(); + +private slots: + void initForm(); + void receiveEmailResult(QString result); + +private slots: + void on_btnSend_clicked(); + void on_btnSelect_clicked(); + void on_cboxServer_currentIndexChanged(int index); +}; + +#endif // FRMEMAILTOOL_H diff --git a/tool/emailtool/frmemailtool.ui b/tool/emailtool/frmemailtool.ui new file mode 100644 index 0000000..6c5083d --- /dev/null +++ b/tool/emailtool/frmemailtool.ui @@ -0,0 +1,221 @@ + + + frmEmailTool + + + + 0 + 0 + 764 + 578 + + + + Form + + + + + + + + PointingHandCursor + + + 发送 + + + + + + + + 25 + + + + + 465 + + + + + 587 + + + + + + + + SSL + + + + + + + 服务端口 + + + + + + + PointingHandCursor + + + 浏览 + + + + + + + feiyangqingyun@163.com;517216493@qq.com + + + + + + + + + + 邮件标题 + + + + + + + 测试邮件 + + + + + + + + smtp.163.com + + + + + smtp.126.com + + + + + smtp.qq.com + + + + + smt.sina.com + + + + + smtp.sohu.com + + + + + smtp.139.com + + + + + smtp.189.com + + + + + + + + 收件地址 + + + + + + + 选择附件 + + + + + + + 服务地址 + + + + + + + 用户名称 + + + + + + + feiyangqingyun@126.com + + + + + + + 用户密码 + + + + + + + + + + QLineEdit::Password + + + + + + + + + false + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'SimSun'; font-size:9.07563pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'宋体'; font-size:11pt;">1</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、最短的爱情哲理小说:“</span><span style=" font-family:'宋体'; font-size:11pt;">你应该嫁给我啦?</span><span style=" font-family:'Times New Roman'; font-size:11pt;">” “ </span><span style=" font-family:'宋体'; font-size:11pt;">不</span><span style=" font-family:'Times New Roman'; font-size:11pt;">” </span><span style=" font-family:'宋体'; font-size:11pt;">于是他俩又继续幸福地生活在一起</span><span style=" font-family:'Times New Roman'; font-size:11pt;">!<br /></span><span style=" font-family:'宋体'; font-size:11pt;">2</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、近年来中国最精彩的写实小说,全文八个字:</span><span style=" font-family:'Times New Roman'; font-size:16pt; font-weight:600; font-style:italic; color:#ff007f;">此地钱多人傻速来</span><span style=" font-family:'Times New Roman'; font-size:11pt;">  据说是发自杭州市宝石山下一出租房的汇款单上的简短附言,是该按摩女给家乡妹妹汇 款时随手涂鸦的,令无数专业作家汗颜!<br /></span><span style=" font-family:'宋体'; font-size:11pt;">3</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、最短的幽默小说 《夜》 男:疼么?女:恩!男:算了?女:别!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'宋体'; font-size:11pt;">4</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、最短的荒诞小说:有一个面包走在街上,它觉得自己很饿,就把自己吃了。<br /></span><span style=" font-family:'宋体'; font-size:11pt;">5</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短言情小说:他死的那天,孩子出生了。<br /></span><span style=" font-family:'宋体'; font-size:11pt;">6</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短武侠小说:</span><span style=" font-family:'Times New Roman'; font-size:11pt; font-weight:600; color:#00aa00;">高手被豆腐砸死了</span><span style=" font-family:'Times New Roman'; font-size:11pt;">。<br /></span><span style=" font-family:'宋体'; font-size:11pt;">7</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短科幻小说:最后一个地球人坐在家里,突然响起了敲门声。<br /></span><span style=" font-family:'宋体'; font-size:11pt;">8</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短悬疑小说:生,死,生。<br /></span><span style=" font-family:'宋体'; font-size:11pt;">9</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短推理小说:他死了,一定曾经活过。 <br />1</span><span style=" font-family:'宋体'; font-size:11pt;">0</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短恐怖小说:惊醒,身边躺着自己的尸体。</span></p></body></html> + + + + + + + txtSenderAddr + txtSenderPwd + cboxServer + cboxPort + ckSSL + txtTitle + txtReceiverAddr + btnSend + txtFileName + btnSelect + txtContent + + + + diff --git a/tool/emailtool/main.cpp b/tool/emailtool/main.cpp new file mode 100644 index 0000000..0e6c45f --- /dev/null +++ b/tool/emailtool/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") + +#include "frmemailtool.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmEmailTool w; + w.setWindowTitle("邮件发送工具 V2021 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/emailtool/readme.txt b/tool/emailtool/readme.txt new file mode 100644 index 0000000..661525d --- /dev/null +++ b/tool/emailtool/readme.txt @@ -0,0 +1 @@ +˵163126䣬Ͷ˿ڶ25ʹSSLЭ飬QQʹSSLЭ飬˿Ϊ465QQ䷢͵ĻǰҪQQнsmtpЭ鿪ͨͲɹҾСʱյQQ䷢һʼðĬQQûпSMTP \ No newline at end of file diff --git a/tool/emailtool/sendemailthread.cpp b/tool/emailtool/sendemailthread.cpp new file mode 100644 index 0000000..e8a1993 --- /dev/null +++ b/tool/emailtool/sendemailthread.cpp @@ -0,0 +1,150 @@ +#include "sendemailthread.h" +#include "smtpmime.h" + +#pragma execution_character_set("utf-8") +#define TIMEMS qPrintable(QTime::currentTime().toString("hh:mm:ss zzz")) + +QScopedPointer SendEmailThread::self; +SendEmailThread *SendEmailThread::Instance() +{ + if (self.isNull()) { + static QMutex mutex; + QMutexLocker locker(&mutex); + if (self.isNull()) { + self.reset(new SendEmailThread); + } + } + + return self.data(); +} + +SendEmailThread::SendEmailThread(QObject *parent) : QThread(parent) +{ + stopped = false; + emialTitle = "邮件标题"; + sendEmailAddr = "feiyangqingyun@126.com"; + sendEmailPwd = "123456789"; + receiveEmailAddr = "feiyangqingyun@163.com;517216493@qq.com"; + contents.clear(); + fileNames.clear(); +} + +SendEmailThread::~SendEmailThread() +{ + this->stop(); + this->wait(1000); +} + +void SendEmailThread::run() +{ + while (!stopped) { + int count = contents.count(); + if (count > 0) { + mutex.lock(); + QString content = contents.takeFirst(); + QString fileName = fileNames.takeFirst(); + mutex.unlock(); + + QString result; + QStringList list = sendEmailAddr.split("@"); + QString tempSMTP = list.at(1).split(".").at(0); + int tempPort = 25; + + //QQ邮箱端口号为465,必须启用SSL协议. + if (tempSMTP.toUpper() == "QQ") { + tempPort = 465; + } + + SmtpClient smtp(QString("smtp.%1.com").arg(tempSMTP), tempPort, tempPort == 25 ? SmtpClient::TcpConnection : SmtpClient::SslConnection); + smtp.setUser(sendEmailAddr); + smtp.setPassword(sendEmailPwd); + + //构建邮件主题,包含发件人收件人附件等. + MimeMessage message; + message.setSender(new EmailAddress(sendEmailAddr)); + + //逐个添加收件人 + QStringList receiver = receiveEmailAddr.split(';'); + for (int i = 0; i < receiver.size(); i++) { + message.addRecipient(new EmailAddress(receiver.at(i))); + } + + //构建邮件标题 + message.setSubject(emialTitle); + + //构建邮件正文 + MimeHtml text; + text.setHtml(content); + message.addPart(&text); + + //构建附件-报警图像 + if (fileName.length() > 0) { + QStringList attas = fileName.split(";"); + foreach (QString tempAtta, attas) { + QFile *file = new QFile(tempAtta); + if (file->exists()) { + message.addPart(new MimeAttachment(file)); + } + } + } + + if (!smtp.connectToHost()) { + result = "邮件服务器连接失败"; + } else { + if (!smtp.login()) { + result = "邮件用户登录失败"; + } else { + if (!smtp.sendMail(message)) { + result = "邮件发送失败"; + } else { + result = "邮件发送成功"; + } + } + } + + smtp.quit(); + if (!result.isEmpty()) { + emit receiveEmailResult(result); + } + + msleep(1000); + } + + msleep(100); + } + + stopped = false; +} + +void SendEmailThread::stop() +{ + stopped = true; +} + +void SendEmailThread::setEmailTitle(const QString &emailTitle) +{ + this->emialTitle = emailTitle; +} + +void SendEmailThread::setSendEmailAddr(const QString &sendEmailAddr) +{ + this->sendEmailAddr = sendEmailAddr; +} + +void SendEmailThread::setSendEmailPwd(const QString &sendEmailPwd) +{ + this->sendEmailPwd = sendEmailPwd; +} + +void SendEmailThread::setReceiveEmailAddr(const QString &receiveEmailAddr) +{ + this->receiveEmailAddr = receiveEmailAddr; +} + +void SendEmailThread::append(const QString &content, const QString &fileName) +{ + mutex.lock(); + contents.append(content); + fileNames.append(fileName); + mutex.unlock(); +} diff --git a/tool/emailtool/sendemailthread.h b/tool/emailtool/sendemailthread.h new file mode 100644 index 0000000..e02735f --- /dev/null +++ b/tool/emailtool/sendemailthread.h @@ -0,0 +1,44 @@ +#ifndef SENDEMAILTHREAD_H +#define SENDEMAILTHREAD_H + +#include +#include +#include + +class SendEmailThread : public QThread +{ + Q_OBJECT +public: + static SendEmailThread *Instance(); + explicit SendEmailThread(QObject *parent = 0); + ~SendEmailThread(); + +protected: + void run(); + +private: + static QScopedPointer self; + QMutex mutex; + volatile bool stopped; + + QString emialTitle; //邮件标题 + QString sendEmailAddr; //发件人邮箱 + QString sendEmailPwd; //发件人密码 + QString receiveEmailAddr; //收件人邮箱,可多个中间;隔开 + QStringList contents; //正文内容 + QStringList fileNames; //附件 + +signals: + void receiveEmailResult(const QString &result); + +public slots: + void stop(); + void setEmailTitle(const QString &emailTitle); + void setSendEmailAddr(const QString &sendEmailAddr); + void setSendEmailPwd(const QString &sendEmailPwd); + void setReceiveEmailAddr(const QString &receiveEmailAddr); + void append(const QString &content, const QString &fileName); + +}; + +#endif // SENDEMAILTHREAD_H diff --git a/tool/keydemo/appkey.cpp b/tool/keydemo/appkey.cpp new file mode 100644 index 0000000..db9c24f --- /dev/null +++ b/tool/keydemo/appkey.cpp @@ -0,0 +1,124 @@ +#pragma execution_character_set("utf-8") + +#include "appkey.h" +#include "qmutex.h" +#include "qfile.h" +#include "qtimer.h" +#include "qdatetime.h" +#include "qapplication.h" +#include "qmessagebox.h" + +AppKey *AppKey::self = NULL; +AppKey *AppKey::Instance() +{ + if (!self) { + QMutex mutex; + QMutexLocker locker(&mutex); + if (!self) { + self = new AppKey; + } + } + + return self; +} + +AppKey::AppKey(QObject *parent) : QObject(parent) +{ + keyData = ""; + keyUseDate = false; + keyDate = "2017-01-01"; + keyUseRun = false; + keyRun = 1; + keyUseCount = false; + keyCount = 10; + + timer = new QTimer(this); + timer->setInterval(1000); + connect(timer, SIGNAL(timeout()), this, SLOT(checkTime())); + startTime = QDateTime::currentDateTime(); +} + +void AppKey::start() +{ + //判断密钥文件是否存在,不存在则从资源文件复制出来,同时需要设置文件写权限 + QString keyName = qApp->applicationDirPath() + "/key.db"; + QFile keyFile(keyName); + if (!keyFile.exists() || keyFile.size() == 0) { + QMessageBox::critical(0, "错误", "密钥文件丢失,请联系供应商!"); + exit(0); + } + + //读取密钥文件 + keyFile.open(QFile::ReadOnly); + keyData = keyFile.readLine(); + keyFile.close(); + + //将从注册码文件中的密文解密,与当前时间比较是否到期 + keyData = getXorEncryptDecrypt(keyData, 110); + QStringList data = keyData.split("|"); + + if (data.count() != 6) { + QMessageBox::critical(0, "错误", "注册码文件已损坏,程序将自动关闭!"); + exit(0); + } + + keyUseDate = (data.at(0) == "1"); + keyDate = data.at(1); + keyUseRun = (data.at(2) == "1"); + keyRun = data.at(3).toInt(); + keyUseCount = (data.at(4) == "1"); + keyCount = data.at(5).toInt(); + + //如果启用了时间限制 + if (keyUseDate) { + QString nowDate = QDate::currentDate().toString("yyyy-MM-dd"); + if (nowDate > keyDate) { + QMessageBox::critical(0, "错误", "软件已到期,请联系供应商更新注册码!"); + exit(0); + } + } + + //如果启用了运行时间显示 + if (keyUseRun) { + timer->start(); + } +} + +void AppKey::stop() +{ + timer->stop(); +} + +void AppKey::checkTime() +{ + //找出当前时间与首次启动时间比较 + QDateTime now = QDateTime::currentDateTime(); + if (startTime.secsTo(now) >= (keyRun * 60)) { + QMessageBox::critical(0, "错误", "试运行时间已到,请联系供应商更新注册码!"); + exit(0); + } +} + +QString AppKey::getXorEncryptDecrypt(const QString &data, char key) +{ + //采用异或加密,也可以自行更改算法 + QByteArray buffer = data.toLatin1(); + int size = buffer.size(); + for (int i = 0; i < size; i++) { + buffer[i] = buffer.at(i) ^ key; + } + + return QLatin1String(buffer); +} + +bool AppKey::checkCount(int count) +{ + if (keyUseCount) { + if (count >= keyCount) { + QMessageBox::critical(0, "错误", "设备数量超过限制,请联系供应商更新注册码!"); + return false; + } + } + + return true; +} diff --git a/tool/keydemo/appkey.h b/tool/keydemo/appkey.h new file mode 100644 index 0000000..0f1d300 --- /dev/null +++ b/tool/keydemo/appkey.h @@ -0,0 +1,40 @@ +#ifndef APPKEY_H +#define APPKEY_H + +#include +#include + +class QTimer; + +class AppKey : public QObject +{ + Q_OBJECT +public: + static AppKey *Instance(); + explicit AppKey(QObject *parent = 0); + +private: + static AppKey *self; + + QString keyData; //注册码密文 + bool keyUseDate; //是否启用运行日期时间限制 + QString keyDate; //到期时间字符串 + bool keyUseRun; //是否启用可运行时间限制 + int keyRun; //可运行时间 + bool keyUseCount; //是否启用设备数量限制 + int keyCount; //设备限制数量 + + QTimer *timer; //定时器判断是否运行超时 + QDateTime startTime; //程序启动时间 + +private slots: + void checkTime(); + QString getXorEncryptDecrypt(const QString &data, char key); + +public slots: + void start(); + void stop(); + bool checkCount(int count); +}; + +#endif // APPKEY_H diff --git a/tool/keydemo/frmmain.cpp b/tool/keydemo/frmmain.cpp new file mode 100644 index 0000000..5d7f060 --- /dev/null +++ b/tool/keydemo/frmmain.cpp @@ -0,0 +1,24 @@ +#pragma execution_character_set("utf-8") + +#include "frmmain.h" +#include "ui_frmmain.h" +#include "appkey.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::on_btnAdd_clicked() +{ + QString name = ui->lineEdit->text().trimmed(); + ui->listWidget->addItem(name); + + //计算当前设备数量多少 + AppKey::Instance()->checkCount(ui->listWidget->count()); +} diff --git a/tool/keydemo/frmmain.h b/tool/keydemo/frmmain.h new file mode 100644 index 0000000..f190b7d --- /dev/null +++ b/tool/keydemo/frmmain.h @@ -0,0 +1,25 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +namespace Ui { +class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; + +private slots: + void on_btnAdd_clicked(); +}; + +#endif // FRMMAIN_H diff --git a/tool/keydemo/frmmain.ui b/tool/keydemo/frmmain.ui new file mode 100644 index 0000000..8252d78 --- /dev/null +++ b/tool/keydemo/frmmain.ui @@ -0,0 +1,76 @@ + + + frmMain + + + + 0 + 0 + 800 + 600 + + + + frmMain + + + + + + + + + + 150 + 0 + + + + + 150 + 16777215 + + + + QFrame::Box + + + QFrame::Sunken + + + + + + 测试设备 + + + + + + + 添加 + + + + + + + Qt::Vertical + + + + 20 + 486 + + + + + + + + + + + + + diff --git a/tool/keydemo/keydemo.pro b/tool/keydemo/keydemo.pro new file mode 100644 index 0000000..e677327 --- /dev/null +++ b/tool/keydemo/keydemo.pro @@ -0,0 +1,14 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = keydemo +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmmain.cpp appkey.cpp +HEADERS += frmmain.h appkey.h +FORMS += frmmain.ui + diff --git a/tool/keydemo/main.cpp b/tool/keydemo/main.cpp new file mode 100644 index 0000000..4366476 --- /dev/null +++ b/tool/keydemo/main.cpp @@ -0,0 +1,38 @@ +#pragma execution_character_set("utf-8") + +#include "frmmain.h" +#include "appkey.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + //启动密钥服务类 + AppKey::Instance()->start(); + + frmMain w; + w.setWindowTitle("密钥使用示例 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/keytool/frmmain.cpp b/tool/keytool/frmmain.cpp new file mode 100644 index 0000000..3115fba --- /dev/null +++ b/tool/keytool/frmmain.cpp @@ -0,0 +1,114 @@ +#pragma execution_character_set("utf-8") + +#include "frmmain.h" +#include "ui_frmmain.h" +#include "qmessagebox.h" +#include "qfile.h" +#include "qprocess.h" +#include "qdebug.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); + this->initForm(); + qDebug() << this->getCpuName() << this->getCpuId() << this->getDiskNum(); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::initForm() +{ + QStringList min; + min << "1" << "5" << "10" << "20" << "30"; + for (int i = 1; i <= 24; i++) { + min << QString::number(i * 60); + } + + ui->cboxMin->addItems(min); + ui->cboxMin->setCurrentIndex(1); + ui->dateEdit->setDate(QDate::currentDate()); + + for (int i = 5; i <= 150; i = i + 5) { + ui->cboxCount->addItem(QString("%1").arg(i)); + } +} + +QString frmMain::getWMIC(const QString &cmd) +{ + //获取cpu名称:wmic cpu get Name + //获取cpu核心数:wmic cpu get NumberOfCores + //获取cpu线程数:wmic cpu get NumberOfLogicalProcessors + //查询cpu序列号:wmic cpu get processorid + //查询主板序列号:wmic baseboard get serialnumber + //查询BIOS序列号:wmic bios get serialnumber + //查看硬盘:wmic diskdrive get serialnumber + QProcess p; + p.start(cmd); + p.waitForFinished(); + QString result = QString::fromLocal8Bit(p.readAllStandardOutput()); + QStringList list = cmd.split(" "); + result = result.remove(list.last(), Qt::CaseInsensitive); + result = result.replace("\r", ""); + result = result.replace("\n", ""); + result = result.simplified(); + return result; +} + +QString frmMain::getCpuName() +{ + return getWMIC("wmic cpu get name"); +} + +QString frmMain::getCpuId() +{ + return getWMIC("wmic cpu get processorid"); +} + +QString frmMain::getDiskNum() +{ + return getWMIC("wmic diskdrive where index=0 get serialnumber"); +} + +QString frmMain::getXorEncryptDecrypt(const QString &data, char key) +{ + //采用异或加密,也可以自行更改算法 + QByteArray buffer = data.toLatin1(); + int size = buffer.size(); + for (int i = 0; i < size; i++) { + buffer[i] = buffer.at(i) ^ key; + } + + return QLatin1String(buffer); +} + +void frmMain::on_btnOk_clicked() +{ + bool useDate = ui->ckDate->isChecked(); + bool useRun = ui->ckRun->isChecked(); + bool useCount = ui->ckCount->isChecked(); + + if (!useDate && !useRun && !useCount) { + if (QMessageBox::question(this, "询问", "确定要生成没有任何限制的密钥吗?") != QMessageBox::Yes) { + return; + } + } + + QString strDate = ui->dateEdit->date().toString("yyyy-MM-dd"); + QString strRun = ui->cboxMin->currentText(); + QString strCount = ui->cboxCount->currentText(); + QString key = QString("%1|%2|%3|%4|%5|%6").arg(useDate).arg(strDate).arg(useRun).arg(strRun).arg(useCount).arg(strCount); + + QFile file(QApplication::applicationDirPath() + "/key.db"); + file.open(QFile::WriteOnly | QIODevice::Text); + file.write(getXorEncryptDecrypt(key, 110).toLatin1()); + file.close(); + QMessageBox::information(this, "提示", "生成密钥成功,将 key.db 文件拷贝到对应目录即可!"); +} + +void frmMain::on_btnClose_clicked() +{ + this->close(); +} diff --git a/tool/keytool/frmmain.h b/tool/keytool/frmmain.h new file mode 100644 index 0000000..21c44f2 --- /dev/null +++ b/tool/keytool/frmmain.h @@ -0,0 +1,34 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +namespace Ui { +class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; + +private slots: + void initForm(); + QString getWMIC(const QString &cmd); + QString getCpuName(); + QString getCpuId(); + QString getDiskNum(); + QString getXorEncryptDecrypt(const QString &data, char key); + +private slots: + void on_btnOk_clicked(); + void on_btnClose_clicked(); +}; + +#endif // FRMMAIN_H diff --git a/tool/keytool/frmmain.ui b/tool/keytool/frmmain.ui new file mode 100644 index 0000000..d59b2de --- /dev/null +++ b/tool/keytool/frmmain.ui @@ -0,0 +1,153 @@ + + + frmMain + + + + 0 + 0 + 800 + 600 + + + + + + + Qt::NoFocus + + + yyyy年MM月dd日 + + + true + + + + + + + + 80 + 0 + + + + Qt::NoFocus + + + 生成 + + + + 20 + 20 + + + + + + + + Qt::NoFocus + + + 时间限制 + + + + + + + Qt::NoFocus + + + 数量限制 + + + + + + + true + + + + + + + + 80 + 0 + + + + Qt::NoFocus + + + 关闭 + + + + 20 + 20 + + + + + + + + Qt::NoFocus + + + 运行限制 + + + + + + + true + + + + + + + 分钟自动关闭 + + + + + + + Qt::Vertical + + + + 20 + 24 + + + + + + + + Qt::Horizontal + + + + 1 + 108 + + + + + + + + + + diff --git a/tool/keytool/keytool.pro b/tool/keytool/keytool.pro new file mode 100644 index 0000000..fc3f106 --- /dev/null +++ b/tool/keytool/keytool.pro @@ -0,0 +1,14 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = keytool +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmmain.cpp +HEADERS += frmmain.h +FORMS += frmmain.ui + diff --git a/tool/keytool/main.cpp b/tool/keytool/main.cpp new file mode 100644 index 0000000..2c34b25 --- /dev/null +++ b/tool/keytool/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") + +#include "frmmain.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmMain w; + w.setWindowTitle("密钥生成工具 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/livedemo/applive.cpp b/tool/livedemo/applive.cpp new file mode 100644 index 0000000..71487e5 --- /dev/null +++ b/tool/livedemo/applive.cpp @@ -0,0 +1,68 @@ +#pragma execution_character_set("utf-8") + +#include "applive.h" +#include "qmutex.h" +#include "qudpsocket.h" +#include "qstringlist.h" +#include "qapplication.h" +#include "qdatetime.h" +#include "qdebug.h" + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +QScopedPointer AppLive::self; +AppLive *AppLive::Instance() +{ + if (self.isNull()) { + QMutex mutex; + QMutexLocker locker(&mutex); + if (self.isNull()) { + self.reset(new AppLive); + } + } + + return self.data(); +} + +AppLive::AppLive(QObject *parent) : QObject(parent) +{ + udpServer = new QUdpSocket(this); + + QString name = qApp->applicationFilePath(); + QStringList list = name.split("/"); + appName = list.at(list.count() - 1).split(".").at(0); +} + +void AppLive::readData() +{ + QByteArray tempData; + + do { + tempData.resize(udpServer->pendingDatagramSize()); + QHostAddress sender; + quint16 senderPort; + udpServer->readDatagram(tempData.data(), tempData.size(), &sender, &senderPort); + QString data = QLatin1String(tempData); + + if (data == "hello") { + udpServer->writeDatagram(QString("%1OK").arg(appName).toLatin1(), sender, senderPort); + } + } while (udpServer->hasPendingDatagrams()); +} + +bool AppLive::start(int port) +{ + bool ok = udpServer->bind(port); + if (ok) { + connect(udpServer, SIGNAL(readyRead()), this, SLOT(readData())); + qDebug() << TIMEMS << "Start AppLive Ok"; + } + + return ok; +} + +void AppLive::stop() +{ + udpServer->abort(); + disconnect(udpServer, SIGNAL(readyRead()), this, SLOT(readData())); +} diff --git a/tool/livedemo/applive.h b/tool/livedemo/applive.h new file mode 100644 index 0000000..304c746 --- /dev/null +++ b/tool/livedemo/applive.h @@ -0,0 +1,28 @@ +#ifndef APPLIVE_H +#define APPLIVE_H + +#include + +class QUdpSocket; + +class AppLive : public QObject +{ + Q_OBJECT +public: + static AppLive *Instance(); + explicit AppLive(QObject *parent = 0); + +private: + static QScopedPointer self; + QUdpSocket *udpServer; + QString appName; + +private slots: + void readData(); + +public slots: + bool start(int port); + void stop(); +}; + +#endif // APPLIVE_H diff --git a/tool/livedemo/frmmain.cpp b/tool/livedemo/frmmain.cpp new file mode 100644 index 0000000..4115d9d --- /dev/null +++ b/tool/livedemo/frmmain.cpp @@ -0,0 +1,12 @@ +#include "frmmain.h" +#include "ui_frmmain.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); +} + +frmMain::~frmMain() +{ + delete ui; +} diff --git a/tool/livedemo/frmmain.h b/tool/livedemo/frmmain.h new file mode 100644 index 0000000..ad1efe1 --- /dev/null +++ b/tool/livedemo/frmmain.h @@ -0,0 +1,22 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +namespace Ui { +class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; +}; + +#endif // FRMMAIN_H diff --git a/tool/livedemo/frmmain.ui b/tool/livedemo/frmmain.ui new file mode 100644 index 0000000..0757192 --- /dev/null +++ b/tool/livedemo/frmmain.ui @@ -0,0 +1,21 @@ + + + frmMain + + + + 0 + 0 + 800 + 600 + + + + frmMain + + + + + + + diff --git a/tool/livedemo/livedemo.pro b/tool/livedemo/livedemo.pro new file mode 100644 index 0000000..081090c --- /dev/null +++ b/tool/livedemo/livedemo.pro @@ -0,0 +1,14 @@ +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = livedemo +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmmain.cpp applive.cpp +HEADERS += frmmain.h applive.h +FORMS += frmmain.ui + diff --git a/tool/livedemo/main.cpp b/tool/livedemo/main.cpp new file mode 100644 index 0000000..8755b8d --- /dev/null +++ b/tool/livedemo/main.cpp @@ -0,0 +1,38 @@ +#pragma execution_character_set("utf-8") + +#include "frmmain.h" +#include "applive.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + //启动守护程序服务类 + AppLive::Instance()->start(6666); + + frmMain w; + w.setWindowTitle("守护程序使用示例 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/livetool/app.cpp b/tool/livetool/app.cpp new file mode 100644 index 0000000..80ebdc7 --- /dev/null +++ b/tool/livetool/app.cpp @@ -0,0 +1,79 @@ +#include "app.h" +#include "qsettings.h" +#include "qfile.h" + +QString App::ConfigFile = "config.ini"; +QString App::TargetAppName = "livedemo"; +int App::TargetAppPort = 6666; +bool App::ReStartExplorer = false; +int App::TimeoutCount = 3; +int App::ReStartCount = 0; +QString App::ReStartLastTime = "2019-01-01 00:00:00"; + +void App::readConfig() +{ + if (!checkConfig()) { + return; + } + + QSettings set(App::ConfigFile, QSettings::IniFormat); + set.beginGroup("BaseConfig"); + App::TargetAppName = set.value("TargetAppName", App::TargetAppName).toString(); + App::TargetAppPort = set.value("TargetAppPort", App::TargetAppPort).toInt(); + App::ReStartExplorer = set.value("ReStartExplorer", App::ReStartExplorer).toBool(); + App::TimeoutCount = set.value("TimeoutCount", App::TimeoutCount).toInt(); + App::ReStartCount = set.value("ReStartCount", App::ReStartCount).toInt(); + App::ReStartLastTime = set.value("ReStartLastTime", App::ReStartLastTime).toString(); + set.endGroup(); +} + +void App::writeConfig() +{ + QSettings set(App::ConfigFile, QSettings::IniFormat); + set.beginGroup("BaseConfig"); + set.setValue("TargetAppName", App::TargetAppName); + set.setValue("TargetAppPort", App::TargetAppPort); + set.setValue("ReStartExplorer", App::ReStartExplorer); + set.setValue("TimeoutCount", App::TimeoutCount); + set.setValue("ReStartCount", App::ReStartCount); + set.setValue("ReStartLastTime", App::ReStartLastTime); + set.endGroup(); +} + +bool App::checkConfig() +{ + //如果配置文件大小为0,则以初始值继续运行,并生成配置文件 + QFile file(App::ConfigFile); + if (file.size() == 0) { + writeConfig(); + return false; + } + + //如果配置文件不完整,则以初始值继续运行,并生成配置文件 + if (file.open(QFile::ReadOnly)) { + bool ok = true; + while (!file.atEnd()) { + QString line = file.readLine(); + line = line.replace("\r", ""); + line = line.replace("\n", ""); + QStringList list = line.split("="); + + if (list.count() == 2) { + if (list.at(1) == "") { + ok = false; + break; + } + } + } + + if (!ok) { + writeConfig(); + return false; + } + } else { + writeConfig(); + return false; + } + + return true; +} diff --git a/tool/livetool/app.h b/tool/livetool/app.h new file mode 100644 index 0000000..1ce5daa --- /dev/null +++ b/tool/livetool/app.h @@ -0,0 +1,23 @@ +#ifndef APP_H +#define APP_H + +#include + +class App +{ +public: + static QString ConfigFile; //配置文件文件路径及名称 + static QString TargetAppName; //目标软件程序名称 + static int TargetAppPort; //目标软件通信端口 + static bool ReStartExplorer; //是否需要重启桌面 + static int TimeoutCount; //超时次数 + static int ReStartCount; //已重启次数 + static QString ReStartLastTime; //最后一次重启时间 + + static void readConfig(); //读取配置文件,在main函数最开始加载程序载入 + static void writeConfig(); //写入配置文件,在更改配置文件程序关闭时调用 + static bool checkConfig(); //校验配置文件 + +}; + +#endif // APP_H diff --git a/tool/livetool/frmmain.cpp b/tool/livetool/frmmain.cpp new file mode 100644 index 0000000..e04272b --- /dev/null +++ b/tool/livetool/frmmain.cpp @@ -0,0 +1,207 @@ +#pragma execution_character_set("utf-8") + +#include "frmmain.h" +#include "ui_frmmain.h" +#include "qtimer.h" +#include "qudpsocket.h" +#include "qsharedmemory.h" +#include "qprocess.h" +#include "qdatetime.h" +#include "qapplication.h" +#include "qdesktopservices.h" +#include "qmessagebox.h" +#if (QT_VERSION > QT_VERSION_CHECK(5,0,0)) +#include "qstandardpaths.h" +#endif + +#include "app.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); + this->initForm(); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::changeEvent(QEvent *event) +{ + //隐藏当前界面,最小化到托盘 + if(event->type() == QEvent::WindowStateChange) { + if(windowState() & Qt::WindowMinimized) { + hide(); + } + } + + QWidget::changeEvent(event); +} + +void frmMain::initForm() +{ + count = 0; + ok = false; + + //每秒钟定时询问心跳 + timerHeart = new QTimer(this); + timerHeart->setInterval(2000); + connect(timerHeart, SIGNAL(timeout()), this, SLOT(sendHearData())); + + //从6050端口开始,如果绑定失败则将端口加1,直到绑定成功 + udp = new QUdpSocket(this); + int port = 6050; + while(!udp->bind(port)) { + port++; + } + + connect(udp, SIGNAL(readyRead()), this, SLOT(readData())); + + if (App::TargetAppName.isEmpty()) { + ui->btnStart->setText("启动"); + ui->btnStart->setEnabled(false); + timerHeart->stop(); + } else { + ui->btnStart->setText("暂停"); + ui->btnStart->setEnabled(true); + timerHeart->start(); + } + + ui->txtAppName->setText(App::TargetAppName); + ui->txtAppName->setFocus(); +} + +void frmMain::sendHearData() +{ + udp->writeDatagram("hello", QHostAddress::LocalHost, App::TargetAppPort); + + //判断当前是否没有回复 + if (!ok) { + count++; + } else { + count = 0; + ok = false; + } + + //如果超过规定次数没有收到心跳回复,则超时重启 + if (count >= App::TimeoutCount) { + timerHeart->stop(); + + QSharedMemory mem(App::TargetAppName); + if (!mem.create(1)) { + killApp(); + } + + QTimer::singleShot(1000 , this, SLOT(killOther())); + QTimer::singleShot(3000 , this, SLOT(startApp())); + QTimer::singleShot(4000 , this, SLOT(startExplorer())); + } +} + +void frmMain::killApp() +{ + QProcess *p = new QProcess; + p->start(QString("taskkill /im %1.exe /f").arg(App::TargetAppName)); +} + +void frmMain::killOther() +{ + QProcess *p = new QProcess; + p->start(QString("taskkill /im %1.exe /f").arg("WerFault")); + + //重建缓存,彻底清除托盘图标 + if (App::ReStartExplorer) { + QProcess *p1 = new QProcess; + p1->start("taskkill /f /im explorer.exe"); + } +} + +void frmMain::startApp() +{ + if (ui->btnStart->text() == "开始" || ui->btnStart->text() == "启动") { + count = 0; + return; + } + + QProcess *p = new QProcess; + p->start(QString("\"%1/%2.exe\"").arg(qApp->applicationDirPath()).arg(App::TargetAppName)); + + count = 0; + ok = true; + timerHeart->start(); + + App::ReStartCount++; + App::ReStartLastTime = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); + App::writeConfig(); + + ui->labCount->setText(QString("已重启 %1 次").arg(App::ReStartCount)); + ui->labInfo->setText(QString("最后一次重启在 %1").arg(App::ReStartLastTime)); +} + +void frmMain::startExplorer() +{ + //取得操作系统目录路径,指定操作系统目录下的explorer程序,采用绝对路径,否则在64位操作系统下无效 +#if (QT_VERSION > QT_VERSION_CHECK(5,0,0)) + QString str = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); +#else + QString str = QDesktopServices::storageLocation(QDesktopServices::ApplicationsLocation); +#endif + + if (App::ReStartExplorer) { + str = QString("%1\\Windows\\explorer.exe").arg(str.mid(0, 2)); + QProcess *p = new QProcess(this); + p->start(str); + } +} + +void frmMain::readData() +{ + QByteArray tempData; + do { + tempData.resize(udp->pendingDatagramSize()); + udp->readDatagram(tempData.data(), tempData.size()); + QString data = QLatin1String(tempData); + if (data.right(2) == "OK") { + count = 0; + ok = true; + } + } while (udp->hasPendingDatagrams()); +} + +void frmMain::on_btnOk_clicked() +{ + App::TargetAppName = ui->txtAppName->text(); + if (App::TargetAppName == "") { + QMessageBox::critical(this, "提示", "应用程序名称不能为空!"); + ui->txtAppName->setFocus(); + return; + } + + App::writeConfig(); + ui->btnStart->setEnabled(true); +} + +void frmMain::on_btnStart_clicked() +{ + count = 0; + if (ui->btnStart->text() == "暂停") { + timerHeart->stop(); + ui->btnStart->setText("开始"); + } else { + timerHeart->start(); + ui->btnStart->setText("暂停"); + } +} + +void frmMain::on_btnReset_clicked() +{ + App::ReStartCount = 0; + App::ReStartLastTime = "2019-01-01 12:00:00"; + App::writeConfig(); + + ui->txtAppName->setText(App::TargetAppName); + ui->labCount->setText(QString("已重启 %1 次").arg(App::ReStartCount)); + ui->labInfo->setText(QString("最后一次重启在 %1").arg(App::ReStartLastTime)); + QMessageBox::information(this, "提示", "重置配置文件成功!"); +} diff --git a/tool/livetool/frmmain.h b/tool/livetool/frmmain.h new file mode 100644 index 0000000..f7a306d --- /dev/null +++ b/tool/livetool/frmmain.h @@ -0,0 +1,46 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +class QUdpSocket; + +namespace Ui +{ + class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +protected: + void changeEvent(QEvent *event); + +private: + Ui::frmMain *ui; + QTimer *timerHeart; //心跳定时器 + QUdpSocket *udp; //UDP通信对象 + int count; //计数 + bool ok; //是否正常 + +private slots: + void initForm(); + void sendHearData(); + void readData(); + void killApp(); + void killOther(); + void startApp(); + void startExplorer(); + +private slots: + void on_btnOk_clicked(); + void on_btnStart_clicked(); + void on_btnReset_clicked(); +}; + +#endif // FRMMAIN_H diff --git a/tool/livetool/frmmain.ui b/tool/livetool/frmmain.ui new file mode 100644 index 0000000..39df60c --- /dev/null +++ b/tool/livetool/frmmain.ui @@ -0,0 +1,102 @@ + + + frmMain + + + + 0 + 0 + 288 + 125 + + + + false + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + QFrame::Box + + + QFrame::Sunken + + + + + + + 70 + 0 + + + + 应用 + + + + + + + + 70 + 0 + + + + 暂停 + + + + + + + 重置 + + + + + + + + + + 最后一次重启在 + + + + + + + 已重启 0 次 + + + + + + + + + + + txtAppName + btnOk + btnStart + btnReset + + + + diff --git a/tool/livetool/livetool.pro b/tool/livetool/livetool.pro new file mode 100644 index 0000000..2c67078 --- /dev/null +++ b/tool/livetool/livetool.pro @@ -0,0 +1,14 @@ +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = livetool +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp frmmain.cpp trayicon.cpp app.cpp +HEADERS += frmmain.h trayicon.h app.h +FORMS += frmmain.ui +RESOURCES += main.qrc + diff --git a/tool/livetool/main.cpp b/tool/livetool/main.cpp new file mode 100644 index 0000000..5254301 --- /dev/null +++ b/tool/livetool/main.cpp @@ -0,0 +1,44 @@ +#pragma execution_character_set("utf-8") + +#include "frmmain.h" +#include "trayicon.h" +#include "app.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setWindowIcon(QIcon(":/main.ico")); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmMain w; + w.setWindowTitle("程序启动器 (QQ: 517216493 WX: feiyangqingyun)"); + w.setFixedSize(w.sizeHint()); + + //启动托盘类 + TrayIcon::Instance()->setMainWidget(&w); + TrayIcon::Instance()->setIcon(":/main.ico"); + TrayIcon::Instance()->setToolTip(w.windowTitle()); + TrayIcon::Instance()->setVisible(true); + QObject::connect(&w, SIGNAL(destroyed(QObject *)), TrayIcon::Instance(), SLOT(closeAll())); + + App::ConfigFile = qApp->applicationDirPath() + "/config.ini"; + App::readConfig(); + App::TargetAppName.isEmpty() ? w.show() : w.hide(); + + return a.exec(); +} diff --git a/tool/livetool/main.ico b/tool/livetool/main.ico new file mode 100644 index 0000000..100e0dc Binary files /dev/null and b/tool/livetool/main.ico differ diff --git a/tool/livetool/main.qrc b/tool/livetool/main.qrc new file mode 100644 index 0000000..91c2747 --- /dev/null +++ b/tool/livetool/main.qrc @@ -0,0 +1,5 @@ + + + main.ico + + diff --git a/tool/livetool/trayicon.cpp b/tool/livetool/trayicon.cpp new file mode 100644 index 0000000..74b11e4 --- /dev/null +++ b/tool/livetool/trayicon.cpp @@ -0,0 +1,106 @@ +#pragma execution_character_set("utf-8") + +#include "trayicon.h" +#include "qmutex.h" +#include "qmenu.h" +#include "qapplication.h" +#include "qdebug.h" + +QScopedPointer TrayIcon::self; +TrayIcon *TrayIcon::Instance() +{ + if (self.isNull()) { + static QMutex mutex; + QMutexLocker locker(&mutex); + if (self.isNull()) { + self.reset(new TrayIcon); + } + } + + return self.data(); +} + +TrayIcon::TrayIcon(QObject *parent) : QObject(parent) +{ + mainWidget = 0; + trayIcon = new QSystemTrayIcon(this); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(iconIsActived(QSystemTrayIcon::ActivationReason))); + menu = new QMenu; + exitDirect = true; +} + +void TrayIcon::iconIsActived(QSystemTrayIcon::ActivationReason reason) +{ + switch (reason) { + case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::DoubleClick: { + this->showMainWidget(); + break; + } + + default: + break; + } +} + +void TrayIcon::setExitDirect(bool exitDirect) +{ + if (this->exitDirect != exitDirect) { + this->exitDirect = exitDirect; + } +} + +void TrayIcon::setMainWidget(QWidget *mainWidget) +{ + this->mainWidget = mainWidget; + menu->addAction("主界面", this, SLOT(showMainWidget())); + + if (exitDirect) { + menu->addAction("退出", this, SLOT(closeAll())); + } else { + menu->addAction("退出", this, SIGNAL(trayIconExit())); + } + + trayIcon->setContextMenu(menu); +} + +void TrayIcon::showMainWidget() +{ + if (mainWidget) { + mainWidget->showNormal(); + mainWidget->activateWindow(); + } +} + +void TrayIcon::showMessage(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int msecs) +{ + trayIcon->showMessage(title, msg, icon, msecs); +} + +void TrayIcon::setIcon(const QString &strIcon) +{ + trayIcon->setIcon(QIcon(strIcon)); +} + +void TrayIcon::setToolTip(const QString &tip) +{ + trayIcon->setToolTip(tip); +} + +bool TrayIcon::getVisible() const +{ + return trayIcon->isVisible(); +} + +void TrayIcon::setVisible(bool visible) +{ + trayIcon->setVisible(visible); +} + +void TrayIcon::closeAll() +{ + trayIcon->hide(); + trayIcon->deleteLater(); + qApp->exit(); +} diff --git a/tool/livetool/trayicon.h b/tool/livetool/trayicon.h new file mode 100644 index 0000000..e056d12 --- /dev/null +++ b/tool/livetool/trayicon.h @@ -0,0 +1,69 @@ +#ifndef TRAYICON_H +#define TRAYICON_H + +/** + * 托盘图标控件 作者:feiyangqingyun(QQ:517216493) 2017-01-08 + * 1. 可设置托盘图标对应所属主窗体。 + * 2. 可设置托盘图标。 + * 3. 可设置提示信息。 + * 4. 自带右键菜单。 + */ + +#include +#include + +class QMenu; + +#ifdef quc +class Q_DECL_EXPORT TrayIcon : public QObject +#else +class TrayIcon : public QObject +#endif + +{ + Q_OBJECT +public: + static TrayIcon *Instance(); + explicit TrayIcon(QObject *parent = 0); + +private: + static QScopedPointer self; + QWidget *mainWidget; //对应所属主窗体 + QSystemTrayIcon *trayIcon; //托盘对象 + QMenu *menu; //右键菜单 + bool exitDirect; //是否直接退出 + +private slots: + void iconIsActived(QSystemTrayIcon::ActivationReason reason); + +public: + //设置是否直接退出,如果不是直接退出则发送信号给主界面 + void setExitDirect(bool exitDirect); + + //设置所属主窗体 + void setMainWidget(QWidget *mainWidget); + + //显示消息 + void showMessage(const QString &title, const QString &msg, + QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 5000); + + //设置图标 + void setIcon(const QString &strIcon); + //设置提示信息 + void setToolTip(const QString &tip); + + //获取和设置是否可见 + bool getVisible() const; + void setVisible(bool visible); + +public Q_SLOTS: + //退出所有 + void closeAll(); + //显示主窗体 + void showMainWidget(); + +Q_SIGNALS: + void trayIconExit(); +}; + +#endif // TRAYICON_H diff --git a/tool/moneytool/main.cpp b/tool/moneytool/main.cpp new file mode 100644 index 0000000..67dbbe2 --- /dev/null +++ b/tool/moneytool/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") + +#include "widget.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + Widget w; + w.setWindowTitle("存款/贷款 计算器 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/moneytool/moneytool.pro b/tool/moneytool/moneytool.pro new file mode 100644 index 0000000..fb85fcc --- /dev/null +++ b/tool/moneytool/moneytool.pro @@ -0,0 +1,13 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = moneytool +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += widget.cpp +HEADERS += widget.h +FORMS += widget.ui diff --git a/tool/moneytool/widget.cpp b/tool/moneytool/widget.cpp new file mode 100644 index 0000000..b42f9b3 --- /dev/null +++ b/tool/moneytool/widget.cpp @@ -0,0 +1,88 @@ +#pragma execution_character_set("utf-8") + +#include "widget.h" +#include "ui_widget.h" +#include "qmessagebox.h" +#include "qdebug.h" + +Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) +{ + ui->setupUi(this); + this->initForm(); +} + +Widget::~Widget() +{ + delete ui; +} + +void Widget::initForm() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->dateStart->setDate(now.date()); + ui->dateEnd->setDate(now.date().addYears(1)); +} + +void Widget::on_btnCalc_clicked() +{ + //当前多少钱 + int moneyCurrent = ui->txtMoneyCurrent->text().toInt(); + //利息 + float rate = ui->txtRate->text().toFloat(); + //定期期限 + int year = ui->cboxYear->currentText().left(1).toInt(); + //总年份 必须是定期期限的倍数 + int years = ui->txtYears->text().toInt(); + //最终多少钱 + int moneyAll = 0; + + if (years % year != 0) { + ui->txtYears->setFocus(); + QMessageBox::critical(this, "错误", "总年份必须是期限的整数倍数!"); + return; + } + + if (ui->cboxType->currentIndex() == 0) { + //傻瓜场景 直接计算 + moneyAll = moneyCurrent + (moneyCurrent * rate * years); + } else { + //真实场景 复利计算 + int count = years / year; + for (int i = 0; i < count; ++i) { + moneyCurrent = moneyCurrent + (moneyCurrent * rate * year); + } + moneyAll = moneyCurrent; + } + + //计算下来3年期定期存款30年总金额翻2番到最初本金3倍 100W本金3年期自动续期30年=321W + QString value = QString::number(moneyAll); + ui->txtMoneyAll->setText(value); + + //拷贝到其他地方 + if (ui->rbtn1->isChecked()) { + ui->txtValue1->setText(value); + } else { + ui->txtValue2->setText(value); + } + + //计算两种存款方式的差额 比如1年期存3年和3年期存3年 + QString value1 = ui->txtValue1->text().trimmed(); + QString value2 = ui->txtValue2->text().trimmed(); + if (!value1.isEmpty() && !value2.isEmpty()) { + int value = qAbs(value1.toInt() - value2.toInt()); + ui->txtValue->setText(QString::number(value)); + } +} + +void Widget::on_btnCalc2_clicked() +{ + //计算天数 + QDateTime dateStart = ui->dateStart->dateTime(); + QDateTime dateEnd = ui->dateEnd->dateTime(); + int day = dateStart.daysTo(dateEnd); + int money = ui->txtMoney2->text().toInt(); + float rate = ui->txtRate2->text().toFloat(); + int result = money * rate * day; + ui->txtResult2->setText(QString::number(result)); + qDebug() << day; +} diff --git a/tool/moneytool/widget.h b/tool/moneytool/widget.h new file mode 100644 index 0000000..701aeef --- /dev/null +++ b/tool/moneytool/widget.h @@ -0,0 +1,27 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include + +namespace Ui { +class Widget; +} + +class Widget : public QWidget +{ + Q_OBJECT + +public: + explicit Widget(QWidget *parent = 0); + ~Widget(); + +private: + Ui::Widget *ui; + +private slots: + void initForm(); + void on_btnCalc_clicked(); + void on_btnCalc2_clicked(); +}; + +#endif // WIDGET_H diff --git a/tool/moneytool/widget.ui b/tool/moneytool/widget.ui new file mode 100644 index 0000000..91b4655 --- /dev/null +++ b/tool/moneytool/widget.ui @@ -0,0 +1,383 @@ + + + Widget + + + + 0 + 0 + 800 + 600 + + + + 存款计算器 + + + + + + 存款计算 + + + + + + + 600 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 期限 + + + + + + + 利率 + + + + + + + 1 + + + + 单利 + + + + + 复利 + + + + + + + + + + + 1000000 + + + + + + + + 0 + 0 + + + + 计算 + + + + + + + + + + 本金 + + + + + + + 1 + + + + 1年 + + + + + 3年 + + + + + 5年 + + + + + + + + 年限 + + + + + + + 方式 + + + + + + + 总计2 + + + + + + + + + + 0.04125 + + + + + + + 总计1 + + + true + + + + + + + 总计 + + + + + + + 总计差额 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 30 + + + + + + + + + + + + + Qt::Horizontal + + + + 19 + 20 + + + + + + + + + 0 + 200 + + + + 贷款计算 + + + + + + 贷款利率 + + + + + + + 贷款金额 + + + + + + + + 0 + 0 + + + + 计算 + + + + + + + 0.0003 + + + + + + + 到期日期 + + + + + + + 逾期利率 + + + + + + + 0.0003 + + + + + + + + 0 + 0 + + + + yyyy-MM-dd + + + true + + + + + + + yyyy-MM-dd + + + true + + + + + + + 100000 + + + + + + + 0.0003 + + + + + + + 贷款日期 + + + + + + + 复利利率 + + + + + + + 贷款利息 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 489 + + + + + + + + + txtMoneyCurrent + txtRate + cboxYear + txtYears + cboxType + txtMoneyAll + btnCalc + rbtn1 + txtValue1 + rbtn2 + txtValue2 + txtValue + + + + diff --git a/tool/netserver/api/api.pri b/tool/netserver/api/api.pri new file mode 100644 index 0000000..d2cfd12 --- /dev/null +++ b/tool/netserver/api/api.pri @@ -0,0 +1,13 @@ +HEADERS += \ + $$PWD/appconfig.h \ + $$PWD/qthelper.h \ + $$PWD/qthelperdata.h \ + $$PWD/tcpserver1.h \ + $$PWD/tcpserver2.h + +SOURCES += \ + $$PWD/appconfig.cpp \ + $$PWD/qthelper.cpp \ + $$PWD/qthelperdata.cpp \ + $$PWD/tcpserver1.cpp \ + $$PWD/tcpserver2.cpp diff --git a/tool/netserver/api/appconfig.cpp b/tool/netserver/api/appconfig.cpp new file mode 100644 index 0000000..51e749b --- /dev/null +++ b/tool/netserver/api/appconfig.cpp @@ -0,0 +1,58 @@ +#include "appconfig.h" +#include "qthelper.h" + +QString AppConfig::ConfigFile = "config.ini"; + +int AppConfig::ListenPort1 = 6907; +int AppConfig::CmdStart1 = 76; +int AppConfig::CmdLen1 = 12; +bool AppConfig::HexData1 = false; + +int AppConfig::ListenPort2 = 6908; +int AppConfig::CmdStart2 = 76; +int AppConfig::CmdLen2 = 12; +bool AppConfig::HexData2 = false; + +void AppConfig::readConfig() +{ + QSettings set(AppConfig::ConfigFile, QSettings::IniFormat); + + set.beginGroup("AppConfig1"); + AppConfig::ListenPort1 = set.value("ListenPort1", AppConfig::ListenPort1).toInt(); + AppConfig::CmdStart1 = set.value("CmdStart1", AppConfig::CmdStart1).toInt(); + AppConfig::CmdLen1 = set.value("CmdLen1", AppConfig::CmdLen1).toInt(); + AppConfig::HexData1 = set.value("HexData1", AppConfig::HexData1).toBool(); + set.endGroup(); + + set.beginGroup("AppConfig2"); + AppConfig::ListenPort2 = set.value("ListenPort2", AppConfig::ListenPort2).toInt(); + AppConfig::CmdStart2 = set.value("CmdStart2", AppConfig::CmdStart2).toInt(); + AppConfig::CmdLen2 = set.value("CmdLen2", AppConfig::CmdLen2).toInt(); + AppConfig::HexData2 = set.value("HexData2", AppConfig::HexData2).toBool(); + set.endGroup(); + + //配置文件不存在或者不全则重新生成 + if (!QtHelper::checkIniFile(AppConfig::ConfigFile)) { + writeConfig(); + return; + } +} + +void AppConfig::writeConfig() +{ + QSettings set(AppConfig::ConfigFile, QSettings::IniFormat); + + set.beginGroup("AppConfig1"); + set.setValue("ListenPort1", AppConfig::ListenPort1); + set.setValue("CmdStart1", AppConfig::CmdStart1); + set.setValue("CmdLen1", AppConfig::CmdLen1); + set.setValue("HexData1", AppConfig::HexData1); + set.endGroup(); + + set.beginGroup("AppConfig2"); + set.setValue("ListenPort2", AppConfig::ListenPort2); + set.setValue("CmdStart2", AppConfig::CmdStart2); + set.setValue("CmdLen2", AppConfig::CmdLen2); + set.setValue("HexData2", AppConfig::HexData2); + set.endGroup(); +} diff --git a/tool/netserver/api/appconfig.h b/tool/netserver/api/appconfig.h new file mode 100644 index 0000000..0da63d3 --- /dev/null +++ b/tool/netserver/api/appconfig.h @@ -0,0 +1,26 @@ +#ifndef APPCONFIG_H +#define APPCONFIG_H + +#include "head.h" + +class AppConfig +{ +public: + static QString ConfigFile; //配置文件路径 + + static int ListenPort1; //监听端口1 + static int CmdStart1; //标识符1开始 + static int CmdLen1; //标识符1长度 + static bool HexData1; //16进制显示 + + static int ListenPort2; //监听端口2 + static int CmdStart2; //标识符2开始 + static int CmdLen2; //标识符2长度 + static bool HexData2; //16进制显示 + + //读写配置参数及其他操作 + static void readConfig(); //读取配置参数 + static void writeConfig(); //写入配置参数 +}; + +#endif // APPCONFIG_H diff --git a/tool/netserver/api/qthelper.cpp b/tool/netserver/api/qthelper.cpp new file mode 100644 index 0000000..1911055 --- /dev/null +++ b/tool/netserver/api/qthelper.cpp @@ -0,0 +1,1234 @@ +#include "qthelper.h" +#include "qnetworkinterface.h" +#include "qnetworkproxy.h" + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +QList QtHelper::getScreenRects(bool available) +{ + QList rects; +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + int screenCount = qApp->screens().count(); + QList screens = qApp->screens(); + for (int i = 0; i < screenCount; ++i) { + QScreen *screen = screens.at(i); + rects << (available ? screen->availableGeometry() : screen->geometry()); + } +#else + int screenCount = qApp->desktop()->screenCount(); + QDesktopWidget *desk = qApp->desktop(); + for (int i = 0; i < screenCount; ++i) { + rects << (available ? desk->availableGeometry(i) : desk->screenGeometry(i)); + } +#endif + return rects; +} + +int QtHelper::getScreenIndex() +{ + //需要对多个屏幕进行处理 + int screenIndex = 0; + QList rects = getScreenRects(false); + int count = rects.count(); + for (int i = 0; i < count; ++i) { + //找到当前鼠标所在屏幕 + QPoint pos = QCursor::pos(); + if (rects.at(i).contains(pos)) { + screenIndex = i; + break; + } + } + + return screenIndex; +} + +QRect QtHelper::getScreenRect(bool available) +{ + int screenIndex = getScreenIndex(); + QList rects = getScreenRects(available); + return rects.at(screenIndex); +} + +qreal QtHelper::getScreenRatio(bool devicePixel) +{ + qreal ratio = 1.0; + int screenIndex = getScreenIndex(); +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + QScreen *screen = qApp->screens().at(screenIndex); + if (devicePixel) { + //需要开启 AA_EnableHighDpiScaling 属性才能正常获取 + ratio = screen->devicePixelRatio() * 100; + } else { + ratio = screen->logicalDotsPerInch(); + } +#else + //Qt4不能动态识别缩放更改后的值 + ratio = qApp->desktop()->screen(screenIndex)->logicalDpiX(); +#endif + return ratio / 96; +} + +QRect QtHelper::checkCenterRect(QRect &rect, bool available) +{ + QRect deskRect = QtHelper::getScreenRect(available); + int formWidth = rect.width(); + int formHeight = rect.height(); + int deskWidth = deskRect.width(); + int deskHeight = deskRect.height(); + int formX = deskWidth / 2 - formWidth / 2 + deskRect.x(); + int formY = deskHeight / 2 - formHeight / 2; + rect = QRect(formX, formY, formWidth, formHeight); + return deskRect; +} + +int QtHelper::deskWidth() +{ + return getScreenRect().width(); +} + +int QtHelper::deskHeight() +{ + return getScreenRect().height(); +} + +QSize QtHelper::deskSize() +{ + return getScreenRect().size(); +} + +QWidget *QtHelper::centerBaseForm = 0; +void QtHelper::setFormInCenter(QWidget *form) +{ + int formWidth = form->width(); + int formHeight = form->height(); + + //如果=0表示采用系统桌面屏幕为参照 + QRect rect; + if (centerBaseForm == 0) { + rect = getScreenRect(); + } else { + rect = centerBaseForm->geometry(); + } + + int deskWidth = rect.width(); + int deskHeight = rect.height(); + QPoint movePoint(deskWidth / 2 - formWidth / 2 + rect.x(), deskHeight / 2 - formHeight / 2 + rect.y()); + form->move(movePoint); +} + +void QtHelper::showForm(QWidget *form) +{ + setFormInCenter(form); + form->show(); + + //判断宽高是否超过了屏幕分辨率,超过了则最大化显示 + //qDebug() << TIMEMS << form->size() << deskSize(); + if (form->width() + 20 > deskWidth() || form->height() + 50 > deskHeight()) { + QMetaObject::invokeMethod(form, "showMaximized", Qt::QueuedConnection); + } +} + +QString QtHelper::appName() +{ + //没有必要每次都获取,只有当变量为空时才去获取一次 + static QString name; + if (name.isEmpty()) { + name = qApp->applicationFilePath(); + //下面的方法主要为了过滤安卓的路径 lib程序名_armeabi-v7a/lib程序名_arm64-v8a + QStringList list = name.split("/"); + name = list.at(list.count() - 1).split(".").at(0); + name.replace("_armeabi-v7a", ""); + name.replace("_arm64-v8a", ""); + } + + return name; +} + +QString QtHelper::appPath() +{ + static QString path; + if (path.isEmpty()) { +#ifdef Q_OS_ANDROID + //默认安卓根目录 + path = "/storage/emulated/0"; + //带上程序名称作为目录 前面加个0方便排序 + path = path + "/0" + appName(); +#else + path = qApp->applicationDirPath(); +#endif + } + + return path; +} + +void QtHelper::getCurrentInfo(char *argv[], QString &path, QString &name) +{ + //必须用fromLocal8Bit保证中文路径正常 + QString argv0 = QString::fromLocal8Bit(argv[0]); + QFileInfo file(argv0); + path = file.path(); + name = file.baseName(); +} + +QString QtHelper::getIniValue(const QString &fileName, const QString &key) +{ + QString value; + QFile file(fileName); + if (file.open(QFile::ReadOnly | QFile::Text)) { + while (!file.atEnd()) { + QString line = file.readLine(); + if (line.startsWith(key)) { + line = line.replace("\n", ""); + line = line.trimmed(); + value = line.split("=").last(); + break; + } + } + } + return value; +} + +QString QtHelper::getIniValue(char *argv[], const QString &key, const QString &dir) +{ + QString path, name; + QtHelper::getCurrentInfo(argv, path, name); + QString fileName = QString("%1/%2%3.ini").arg(path).arg(dir).arg(name); + return getIniValue(fileName, key); +} + +QStringList QtHelper::getLocalIPs() +{ + static QStringList ips; + if (ips.count() == 0) { +#ifdef Q_OS_WASM + ips << "127.0.0.1"; +#else + QList netInterfaces = QNetworkInterface::allInterfaces(); + foreach (QNetworkInterface netInterface, netInterfaces) { + //移除虚拟机和抓包工具的虚拟网卡 + QString humanReadableName = netInterface.humanReadableName().toLower(); + if (humanReadableName.startsWith("vmware network adapter") || humanReadableName.startsWith("npcap loopback adapter")) { + continue; + } + + //过滤当前网络接口 + bool flag = (netInterface.flags() == (QNetworkInterface::IsUp | QNetworkInterface::IsRunning | QNetworkInterface::CanBroadcast | QNetworkInterface::CanMulticast)); + if (!flag) { + continue; + } + + QList addrs = netInterface.addressEntries(); + foreach (QNetworkAddressEntry addr, addrs) { + //只取出IPV4的地址 + if (addr.ip().protocol() != QAbstractSocket::IPv4Protocol) { + continue; + } + + QString ip4 = addr.ip().toString(); + if (ip4 != "127.0.0.1") { + ips << ip4; + } + } + } +#endif + } + + return ips; +} + +QList QtHelper::colors = QList(); +QList QtHelper::getColorList() +{ + //备用颜色集合 可以自行添加 + if (colors.count() == 0) { + colors << QColor(0, 176, 180) << QColor(0, 113, 193) << QColor(255, 192, 0); + colors << QColor(72, 103, 149) << QColor(185, 87, 86) << QColor(0, 177, 125); + colors << QColor(214, 77, 84) << QColor(71, 164, 233) << QColor(34, 163, 169); + colors << QColor(59, 123, 156) << QColor(162, 121, 197) << QColor(72, 202, 245); + colors << QColor(0, 150, 121) << QColor(111, 9, 176) << QColor(250, 170, 20); + } + + return colors; +} + +QStringList QtHelper::getColorNames() +{ + QList colors = getColorList(); + QStringList colorNames; + foreach (QColor color, colors) { + colorNames << color.name(); + } + return colorNames; +} + +QColor QtHelper::getRandColor() +{ + QList colors = getColorList(); + int index = getRandValue(0, colors.count(), true); + return colors.at(index); +} + +void QtHelper::initRand() +{ + //初始化随机数种子 + QTime t = QTime::currentTime(); + srand(t.msec() + t.second() * 1000); +} + +float QtHelper::getRandFloat(float min, float max) +{ + double diff = fabs(max - min); + double value = (double)(rand() % 100) / 100; + value = min + value * diff; + return value; +} + +double QtHelper::getRandValue(int min, int max, bool contansMin, bool contansMax) +{ + int value; +#if (QT_VERSION <= QT_VERSION_CHECK(5,10,0)) + //通用公式 a是起始值,n是整数的范围 + //int value = a + rand() % n; + if (contansMin) { + if (contansMax) { + value = min + 0 + (rand() % (max - min + 1)); + } else { + value = min + 0 + (rand() % (max - min + 0)); + } + } else { + if (contansMax) { + value = min + 1 + (rand() % (max - min + 0)); + } else { + value = min + 1 + (rand() % (max - min - 1)); + } + } +#else + if (contansMin) { + if (contansMax) { + value = QRandomGenerator::global()->bounded(min + 0, max + 1); + } else { + value = QRandomGenerator::global()->bounded(min + 0, max + 0); + } + } else { + if (contansMax) { + value = QRandomGenerator::global()->bounded(min + 1, max + 1); + } else { + value = QRandomGenerator::global()->bounded(min + 1, max + 0); + } + } +#endif + return value; +} + +QStringList QtHelper::getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat) +{ + //随机生成点坐标 + QStringList points; + for (int i = 0; i < count; ++i) { + //0.00881415 0.000442928 +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) + float lngx = QRandomGenerator::global()->bounded(dotLng); + float latx = QRandomGenerator::global()->bounded(dotLat); +#else + float lngx = getRandFloat(dotLng / 10, dotLng); + float latx = getRandFloat(dotLat / 10, dotLat); +#endif + //需要先用精度转换成字符串 + QString lng2 = QString::number(mainLng + lngx, 'f', 8); + QString lat2 = QString::number(mainLat + latx, 'f', 8); + QString point = QString("%1,%2").arg(lng2).arg(lat2); + points << point; + } + + return points; +} + +int QtHelper::getRangeValue(int oldMin, int oldMax, int oldValue, int newMin, int newMax) +{ + return (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin; +} + +QString QtHelper::getUuid() +{ + QString uuid = QUuid::createUuid().toString(); + uuid.replace("{", ""); + uuid.replace("}", ""); + return uuid; +} + +void QtHelper::checkPath(const QString &dirName) +{ + //相对路径需要补全完整路径 + QString path = dirName; + if (path.startsWith("./")) { + path.replace(".", ""); + path = QtHelper::appPath() + path; + } else if (!path.startsWith("/") && !path.contains(":/")) { + path = QtHelper::appPath() + "/" + path; + } + + //目录不存在则新建 + QDir dir(path); + if (!dir.exists()) { + dir.mkpath(path); + } +} + +void QtHelper::sleep(int msec, bool exec) +{ + if (msec <= 0) { + return; + } + + if (exec) { +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //阻塞方式延时(如果在主线程会卡住主界面) + QThread::msleep(msec); +#else + //非阻塞方式延时(不会卡住主界面/据说可能有问题) + QTime endTime = QTime::currentTime().addMSecs(msec); + while (QTime::currentTime() < endTime) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } +#endif + } else { + //非阻塞方式延时(现在很多人推荐的方法) + QEventLoop loop; + QTimer::singleShot(msec, &loop, SLOT(quit())); + loop.exec(); + } +} + +void QtHelper::checkRun() +{ +#ifdef Q_OS_WIN + //延时1秒钟,等待程序释放完毕 + QtHelper::sleep(1000); + //创建共享内存,判断是否已经运行程序 + static QSharedMemory mem(QtHelper::appName()); + if (!mem.create(1)) { + QtHelper::showMessageBoxError("程序已运行, 软件将自动关闭!", 5, true); + exit(0); + } +#endif +} + +void QtHelper::setStyle() +{ + //打印下所有内置风格的名字 + qDebug() << TIMEMS << "QStyleFactory::keys" << QStyleFactory::keys(); + //设置内置风格 +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + qApp->setStyle("Fusion"); +#else + qApp->setStyle("Cleanlooks"); +#endif + + //设置指定颜色 + QPalette palette; + palette.setBrush(QPalette::Window, QColor("#F0F0F0")); + qApp->setPalette(palette); +} + +QFont QtHelper::addFont(const QString &fontFile, const QString &fontName) +{ + //判断图形字体是否存在,不存在则加入 + QFontDatabase fontDb; + if (!fontDb.families().contains(fontName)) { + int fontId = fontDb.addApplicationFont(fontFile); + QStringList listName = fontDb.applicationFontFamilies(fontId); + if (listName.count() == 0) { + qDebug() << QString("load %1 error").arg(fontName); + } + } + + //再次判断是否包含字体名称防止加载失败 + QFont font; + if (fontDb.families().contains(fontName)) { + font = QFont(fontName); +#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0)) + font.setHintingPreference(QFont::PreferNoHinting); +#endif + } + + return font; +} + +void QtHelper::setFont(int fontSize) +{ + //安卓套件在有些手机上默认字体不好看需要主动设置字体 + //网页套件需要主动加载中文字体才能正常显示中文 +#if (defined Q_OS_ANDROID) || (defined Q_OS_WASM) + QString fontFile = ":/font/DroidSansFallback.ttf"; + QString fontName = "Droid Sans Fallback"; + qApp->setFont(addFont(fontFile, fontName)); + return; +#endif + +#ifdef __arm__ + fontSize = 25; +#endif + + QFont font; + font.setFamily("MicroSoft Yahei"); + font.setPixelSize(fontSize); + qApp->setFont(font); +} + +void QtHelper::setCode(bool utf8) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //如果想要控制台打印信息中文正常就注释掉这个设置 + if (utf8) { + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); + } +#else +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#endif +} + +void QtHelper::setTranslator(const QString &qmFile) +{ + //过滤下不存在的就不用设置了 + if (!QFile(qmFile).exists()) { + return; + } + + QTranslator *translator = new QTranslator(qApp); + if (translator->load(qmFile)) { + qApp->installTranslator(translator); + } +} + +#ifdef Q_OS_ANDROID +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) +#include +#else +//Qt6中将相关类移到了core模块而且名字变了 +#include +#endif +#endif + +bool QtHelper::checkPermission(const QString &permission) +{ +#ifdef Q_OS_ANDROID +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0) && QT_VERSION < QT_VERSION_CHECK(6,0,0)) + QtAndroid::PermissionResult result = QtAndroid::checkPermission(permission); + if (result == QtAndroid::PermissionResult::Denied) { + QtAndroid::requestPermissionsSync(QStringList() << permission); + result = QtAndroid::checkPermission(permission); + if (result == QtAndroid::PermissionResult::Denied) { + return false; + } + } +#else + QFuture result = QtAndroidPrivate::requestPermission(permission); + if (result.resultAt(0) == QtAndroidPrivate::PermissionResult::Denied) { + return false; + } +#endif +#endif + return true; +} + +void QtHelper::initAndroidPermission() +{ + //可以把所有要动态申请的权限都写在这里 + checkPermission("android.permission.CALL_PHONE"); + checkPermission("android.permission.SEND_SMS"); + checkPermission("android.permission.CAMERA"); + checkPermission("android.permission.READ_EXTERNAL_STORAGE"); + checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); + + checkPermission("android.permission.ACCESS_COARSE_LOCATION"); + checkPermission("android.permission.BLUETOOTH"); + checkPermission("android.permission.BLUETOOTH_SCAN"); + checkPermission("android.permission.BLUETOOTH_CONNECT"); + checkPermission("android.permission.BLUETOOTH_ADVERTISE"); +} + +void QtHelper::initAll(bool utf8, bool style, int fontSize) +{ + //初始化安卓权限 + QtHelper::initAndroidPermission(); + //初始化随机数种子 + QtHelper::initRand(); + //设置编码 + QtHelper::setCode(utf8); + //设置字体 + QtHelper::setFont(fontSize); + //设置样式风格 + if (style) { + QtHelper::setStyle(); + } + + //设置翻译文件支持多个 + QtHelper::setTranslator(":/qm/widgets.qm"); + QtHelper::setTranslator(":/qm/qt_zh_CN.qm"); + QtHelper::setTranslator(":/qm/designer_zh_CN.qm"); + + //设置不使用本地系统环境代理配置 + QNetworkProxyFactory::setUseSystemConfiguration(false); + //设置当前目录为程序可执行文件所在目录 + QDir::setCurrent(QtHelper::appPath()); + //Qt4中默认没有程序名称需要主动设置 +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) + qApp->setApplicationName(QtHelper::appName()); +#endif +} + +void QtHelper::initMain(bool desktopSettingsAware, bool use96Dpi, bool logCritical) +{ +#ifdef Q_OS_WIN + //Qt6.5开始默认是ffmpeg后端但是不成熟需要换成系统的 + qputenv("QT_MEDIA_BACKEND", "windows"); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //设置是否应用操作系统设置比如字体 + QApplication::setDesktopSettingsAware(desktopSettingsAware); +#endif + + bool highDpi = !use96Dpi; +#ifdef Q_OS_ANDROID + highDpi = true; +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,6,0)) + //开启高分屏缩放支持 + if (highDpi) { + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + } +#endif + +#ifdef Q_OS_WIN + if (use96Dpi) { + //Qt6中AA_Use96Dpi没效果必须下面方式设置强制指定缩放DPI + qputenv("QT_FONT_DPI", "96"); +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //不应用任何缩放 + QApplication::setAttribute(Qt::AA_Use96Dpi); +#endif + } +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + //高分屏缩放策略 + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //下面这行表示不打印Qt内部类的警告提示信息 + if (!logCritical) { + QLoggingCategory::setFilterRules("*.critical=false\n*.warning=false"); + } +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0)) + //设置opengl共享上下文 + QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); +#endif +} + +void QtHelper::initOpenGL(quint8 type, bool checkCardEnable, bool checkVirtualSystem) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0)) + //设置opengl模式 AA_UseDesktopOpenGL(默认) AA_UseOpenGLES AA_UseSoftwareOpenGL + //在一些很旧的设备上或者对opengl支持很低的设备上需要使用AA_UseOpenGLES表示禁用硬件加速 + //如果开启的是AA_UseOpenGLES则无法使用硬件加速比如ffmpeg的dxva2 + if (type == 1) { + QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); + } else if (type == 2) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } else if (type == 3) { + QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); + } + + //检测显卡是否被禁用 + if (checkCardEnable && !isVideoCardEnable()) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } + + //检测是否是虚拟机系统 + if (checkVirtualSystem && isVirtualSystem()) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } +#endif +} + +QString QtHelper::doCmd(const QString &program, const QStringList &arguments, int timeout) +{ + QString result; +#ifndef Q_OS_WASM + QProcess p; + p.start(program, arguments); + p.waitForFinished(timeout); + result = QString::fromLocal8Bit(p.readAllStandardOutput()); + result.replace("\r", ""); + result.replace("\n", ""); + result = result.simplified(); + result = result.trimmed(); +#endif + return result; +} + +bool QtHelper::isVideoCardEnable() +{ + QString result; + bool videoCardEnable = true; + +#if defined(Q_OS_WIN) + QStringList args; + //wmic path win32_VideoController get name,Status + args << "path" << "win32_VideoController" << "get" << "name,Status"; + result = doCmd("wmic", args); +#endif + + //Name Status Intel(R) UHD Graphics 630 OK + //Name Status Intel(R) UHD Graphics 630 Error + if (result.contains("Error")) { + videoCardEnable = false; + } + + return videoCardEnable; +} + +bool QtHelper::isVirtualSystem() +{ + QString result; + bool virtualSystem = false; + +#if defined(Q_OS_WIN) + QStringList args; + //wmic computersystem get Model + args << "computersystem" << "get" << "Model"; + result = doCmd("wmic", args); +#elif defined(Q_OS_LINUX) + QStringList args; + //还有个命令需要root权限运行 dmidecode -s system-product-name 执行结果和win一样 + result = doCmd("lscpu", args); +#endif + + //Model MS-7C00 + //Model VMWare Virtual Platform + //Model VirtualBox Virtual Platform + //Model Alibaba Cloud ECS + if (result.contains("VMware") || result.contains("VirtualBox") || result.contains("Alibaba")) { + virtualSystem = true; + } + + return virtualSystem; +} + +QVector QtHelper::msgTypes = QVector() << 0 << 1 << 2 << 3 << 4; +QVector QtHelper::msgKeys = QVector() << QString::fromUtf8("发送") << QString::fromUtf8("接收") << QString::fromUtf8("解析") << QString::fromUtf8("错误") << QString::fromUtf8("提示"); +QVector QtHelper::msgColors = QVector() << QColor("#3BA372") << QColor("#EE6668") << QColor("#9861B4") << QColor("#FA8359") << QColor("#22A3A9"); +QString QtHelper::appendMsg(QTextEdit *textEdit, int type, const QString &data, int maxCount, int ¤tCount, bool clear, bool pause) +{ + if (clear) { + textEdit->clear(); + currentCount = 0; + return QString(); + } + + if (pause) { + return QString(); + } + + if (currentCount >= maxCount) { + textEdit->clear(); + currentCount = 0; + } + + //不同类型不同颜色显示 + QString strType; + int index = msgTypes.indexOf(type); + if (index >= 0) { + strType = msgKeys.at(index); + textEdit->setTextColor(msgColors.at(index)); + } + + //过滤回车换行符 + QString strData = data; + strData.replace("\r", ""); + strData.replace("\n", ""); + strData = QString("时间[%1] %2: %3").arg(TIMEMS).arg(strType).arg(strData); + textEdit->append(strData); + currentCount++; + return strData; +} + +void QtHelper::setFramelessForm(QWidget *widgetMain, bool tool, bool top, bool menu) +{ + widgetMain->setProperty("form", true); + widgetMain->setProperty("canMove", true); + + //根据设定逐个追加属性 +#ifdef __arm__ + widgetMain->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); +#else + widgetMain->setWindowFlags(Qt::FramelessWindowHint); +#endif + if (tool) { + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::Tool); + } + if (top) { + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::WindowStaysOnTopHint); + } + if (menu) { + //如果是其他系统比如neokylin会产生系统边框 +#ifdef Q_OS_WIN + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); +#endif + } +} + +int QtHelper::showMessageBox(const QString &text, int type, int closeSec, bool exec) +{ + int result = 0; + if (type == 0) { + showMessageBoxInfo(text, closeSec, exec); + } else if (type == 1) { + showMessageBoxError(text, closeSec, exec); + } else if (type == 2) { + result = showMessageBoxQuestion(text); + } + + return result; +} + +void QtHelper::showMessageBoxInfo(const QString &text, int closeSec, bool exec) +{ + QMessageBox box(QMessageBox::Information, "提示", text); + box.setStandardButtons(QMessageBox::Yes); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.exec(); + //QMessageBox::information(0, "提示", info, QMessageBox::Yes); +} + +void QtHelper::showMessageBoxError(const QString &text, int closeSec, bool exec) +{ + QMessageBox box(QMessageBox::Critical, "错误", text); + box.setStandardButtons(QMessageBox::Yes); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.exec(); + //QMessageBox::critical(0, "错误", info, QMessageBox::Yes); +} + +int QtHelper::showMessageBoxQuestion(const QString &text) +{ + QMessageBox box(QMessageBox::Question, "询问", text); + box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.setButtonText(QMessageBox::No, QString("取 消")); + return box.exec(); + //return QMessageBox::question(0, "询问", info, QMessageBox::Yes | QMessageBox::No); +} + +void QtHelper::initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName, + const QString &dirName, bool native, int width, int height) +{ + //设置标题 + dialog->setWindowTitle(title); + //设置标签文本 + dialog->setLabelText(QFileDialog::Accept, acceptName); + dialog->setLabelText(QFileDialog::Reject, "取消(&C)"); + dialog->setLabelText(QFileDialog::LookIn, "查看"); + dialog->setLabelText(QFileDialog::FileName, "名称"); + dialog->setLabelText(QFileDialog::FileType, "类型"); + + //设置默认显示目录 + if (!dirName.isEmpty()) { + dialog->setDirectory(dirName); + } + + //设置对话框宽高 + if (width > 0 && height > 0) { +#ifdef Q_OS_ANDROID + bool horizontal = (QtHelper::deskWidth() > QtHelper::deskHeight()); + if (horizontal) { + width = QtHelper::deskWidth() / 2; + height = QtHelper::deskHeight() - 50; + } else { + width = QtHelper::deskWidth() - 10; + height = QtHelper::deskHeight() / 2; + } +#endif + dialog->setFixedSize(width, height); + } + + //设置是否采用本地对话框 + dialog->setOption(QFileDialog::DontUseNativeDialog, !native); + //设置只读可以取消右上角的新建按钮 + //dialog->setReadOnly(true); +} + +QString QtHelper::getDialogResult(QFileDialog *dialog) +{ + QString result; + if (dialog->exec() == QFileDialog::Accepted) { + result = dialog->selectedFiles().first(); + if (!result.contains(".")) { + //自动补全拓展名 保存文件(*.txt *.exe) + QString filter = dialog->selectedNameFilter(); + if (filter.contains("*.")) { + filter = filter.split("(").last(); + filter = filter.mid(0, filter.length() - 1); + //取出第一个作为拓展名 + if (!filter.contains("*.*")) { + filter = filter.split(" ").first(); + result = result + filter.mid(1, filter.length()); + } + } + } + } + return result; +} + +QString QtHelper::getOpenFileName(const QString &filter, const QString &dirName, const QString &fileName, + bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "打开文件", "选择(&S)", dirName, native, width, height); + + //设置文件类型 + if (!filter.isEmpty()) { + dialog.setNameFilter(filter); + } + + //设置默认文件名称 + dialog.selectFile(fileName); + return getDialogResult(&dialog); +} + +QString QtHelper::getSaveFileName(const QString &filter, const QString &dirName, const QString &fileName, + bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "保存文件", "保存(&S)", dirName, native, width, height); + + //设置文件类型 + if (!filter.isEmpty()) { + dialog.setNameFilter(filter); + } + + //设置默认文件名称 + dialog.selectFile(fileName); + //设置模态类型允许输入 + dialog.setWindowModality(Qt::WindowModal); + //设置置顶显示 + dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint); + return getDialogResult(&dialog); +} + +QString QtHelper::getExistingDirectory(const QString &dirName, bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "选择目录", "选择(&S)", dirName, native, width, height); + dialog.setOption(QFileDialog::ReadOnly); + //设置只显示目录 +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + dialog.setFileMode(QFileDialog::DirectoryOnly); +#endif + dialog.setOption(QFileDialog::ShowDirsOnly); + return getDialogResult(&dialog); +} + +QString QtHelper::getXorEncryptDecrypt(const QString &value, char key) +{ + //矫正范围外的数据 + if (key < 0 || key >= 127) { + key = 127; + } + + //大概从5.9版本输出的加密密码字符串前面会加上 @String 字符 + QString result = value; + if (result.startsWith("@String")) { + result = result.mid(8, result.length() - 9); + } + + for (int i = 0; i < result.length(); ++i) { + result[i] = QChar(result.at(i).toLatin1() ^ key); + } + return result; +} + +quint8 QtHelper::getOrCode(const QByteArray &data) +{ + int len = data.length(); + quint8 result = 0; + for (int i = 0; i < len; ++i) { + result ^= data.at(i); + } + + return result; +} + +quint8 QtHelper::getCheckCode(const QByteArray &data) +{ + int len = data.length(); + quint8 temp = 0; + for (int i = 0; i < len; ++i) { + temp += data.at(i); + } + + return temp % 256; +} + +void QtHelper::initTableView(QTableView *tableView, int rowHeight, bool headVisible, bool edit, bool stretchLast) +{ + //设置弱属性用于应用qss特殊样式 + tableView->setProperty("model", true); + //取消自动换行 + tableView->setWordWrap(false); + //超出文本不显示省略号 + tableView->setTextElideMode(Qt::ElideNone); + //奇数偶数行颜色交替 + tableView->setAlternatingRowColors(false); + //垂直表头是否可见 + tableView->verticalHeader()->setVisible(headVisible); + //选中一行表头是否加粗 + tableView->horizontalHeader()->setHighlightSections(false); + //最后一行拉伸填充 + tableView->horizontalHeader()->setStretchLastSection(stretchLast); + //行标题最小宽度尺寸 + tableView->horizontalHeader()->setMinimumSectionSize(0); + //行标题最小高度,等同于和默认行高一致 + tableView->horizontalHeader()->setFixedHeight(rowHeight); + //默认行高 + tableView->verticalHeader()->setDefaultSectionSize(rowHeight); + //选中时一行整体选中 + tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + //只允许选择单个 + tableView->setSelectionMode(QAbstractItemView::SingleSelection); + + //表头不可单击 +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + tableView->horizontalHeader()->setSectionsClickable(false); +#else + tableView->horizontalHeader()->setClickable(false); +#endif + + //鼠标按下即进入编辑模式 + if (edit) { + tableView->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked); + } else { + tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + } +} + +void QtHelper::openFile(const QString &fileName, const QString &msg) +{ +#ifdef __arm__ + return; +#endif + //文件不存在则不用处理 + if (!QFile(fileName).exists()) { + return; + } + if (QtHelper::showMessageBoxQuestion(msg + "成功, 确定现在就打开吗?") == QMessageBox::Yes) { + QString url = QString("file:///%1").arg(fileName); + QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); + } +} + +bool QtHelper::checkIniFile(const QString &iniFile) +{ + //如果配置文件大小为0,则以初始值继续运行,并生成配置文件 + QFile file(iniFile); + if (file.size() == 0) { + return false; + } + + //如果配置文件不完整,则以初始值继续运行,并生成配置文件 + if (file.open(QFile::ReadOnly)) { + bool ok = true; + while (!file.atEnd()) { + QString line = file.readLine(); + line.replace("\r", ""); + line.replace("\n", ""); + QStringList list = line.split("="); + + if (list.count() == 2) { + QString key = list.at(0); + QString value = list.at(1); + if (value.isEmpty()) { + qDebug() << TIMEMS << "ini node no value" << key; + ok = false; + break; + } + } + } + + if (!ok) { + return false; + } + } else { + return false; + } + + return true; +} + +QString QtHelper::cutString(const QString &text, int len, int left, int right, bool file, const QString &mid) +{ + //如果指定了字符串分割则表示是文件名需要去掉拓展名 + QString result = text; + if (file && result.contains(".")) { + int index = result.lastIndexOf("."); + result = result.mid(0, index); + } + + //最终字符串格式为 前缀字符...后缀字符 + if (result.length() > len) { + result = QString("%1%2%3").arg(result.left(left)).arg(mid).arg(result.right(right)); + } + + return result; +} + +QRect QtHelper::getCenterRect(const QSize &imageSize, const QRect &widgetRect, int borderWidth, int scaleMode) +{ + QSize newSize = imageSize; + QSize widgetSize = widgetRect.size() - QSize(borderWidth * 1, borderWidth * 1); + + if (scaleMode == 0) { + if (newSize.width() > widgetSize.width() || newSize.height() > widgetSize.height()) { + newSize.scale(widgetSize, Qt::KeepAspectRatio); + } + } else if (scaleMode == 1) { + newSize.scale(widgetSize, Qt::KeepAspectRatio); + } else { + newSize = widgetSize; + } + + int x = widgetRect.center().x() - newSize.width() / 2; + int y = widgetRect.center().y() - newSize.height() / 2; + //不是2的倍数需要偏移1像素 + x += (x % 2 == 0 ? 1 : 0); + y += (y % 2 == 0 ? 1 : 0); + return QRect(x, y, newSize.width(), newSize.height()); +} + +void QtHelper::getScaledImage(QImage &image, const QSize &widgetSize, int scaleMode, bool fast) +{ + Qt::TransformationMode mode = fast ? Qt::FastTransformation : Qt::SmoothTransformation; + if (scaleMode == 0) { + if (image.width() > widgetSize.width() || image.height() > widgetSize.height()) { + image = image.scaled(widgetSize, Qt::KeepAspectRatio, mode); + } + } else if (scaleMode == 1) { + image = image.scaled(widgetSize, Qt::KeepAspectRatio, mode); + } else { + image = image.scaled(widgetSize, Qt::IgnoreAspectRatio, mode); + } +} + +QString QtHelper::getTimeString(qint64 time) +{ + time = time / 1000; + QString min = QString("%1").arg(time / 60, 2, 10, QChar('0')); + QString sec = QString("%2").arg(time % 60, 2, 10, QChar('0')); + return QString("%1:%2").arg(min).arg(sec); +} + +QString QtHelper::getTimeString(QElapsedTimer timer) +{ + return QString::number((float)timer.elapsed() / 1000, 'f', 3); +} + +QString QtHelper::getSizeString(quint64 size) +{ + float num = size; + QStringList list; + list << "KB" << "MB" << "GB" << "TB"; + + QString unit("bytes"); + QStringListIterator i(list); + while (num >= 1024.0 && i.hasNext()) { + unit = i.next(); + num /= 1024.0; + } + + return QString("%1 %2").arg(QString::number(num, 'f', 2)).arg(unit); +} + +//setSystemDateTime("2022", "07", "01", "12", "22", "55"); +void QtHelper::setSystemDateTime(const QString &year, const QString &month, const QString &day, const QString &hour, const QString &min, const QString &sec) +{ +#ifdef Q_OS_WIN + QProcess p(0); + //先设置日期 + p.start("cmd"); + p.waitForStarted(); + p.write(QString("date %1-%2-%3\n").arg(year).arg(month).arg(day).toLatin1()); + p.closeWriteChannel(); + p.waitForFinished(1000); + p.close(); + //再设置时间 + p.start("cmd"); + p.waitForStarted(); + p.write(QString("time %1:%2:%3.00\n").arg(hour).arg(min).arg(sec).toLatin1()); + p.closeWriteChannel(); + p.waitForFinished(1000); + p.close(); +#else + QString cmd = QString("date %1%2%3%4%5.%6").arg(month).arg(day).arg(hour).arg(min).arg(year).arg(sec); + //设置日期时间 + system(cmd.toLatin1()); + //硬件时钟同步 + system("hwclock -w"); +#endif +} + +void QtHelper::runWithSystem(bool autoRun) +{ + QtHelper::runWithSystem(qApp->applicationName(), qApp->applicationFilePath(), autoRun); +} + +void QtHelper::runWithSystem(const QString &fileName, const QString &filePath, bool autoRun) +{ +#ifdef Q_OS_WIN + //要转换成本地文件路径(不启动则文件路径为空即可) + QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat); + reg.setValue(fileName, autoRun ? QDir::toNativeSeparators(filePath) : ""); +#endif +} + +void QtHelper::runBin(const QString &path, const QString &name) +{ +#ifdef Q_OS_WIN + QString cmd1 = "tasklist"; + QString cmd2 = QString("%1/%2.exe").arg(path).arg(name); +#else + QString cmd1 = "ps -aux"; + QString cmd2 = QString("%1/%2").arg(path).arg(name); +#endif + +#ifndef Q_OS_WASM + QProcess p; + p.start(cmd1); + if (p.waitForFinished()) { + QString result = p.readAll(); + if (result.contains(name)) { + return; + } + } + + //加上引号可以兼容打开带空格的目录(Program Files) + if (cmd2.contains(" ")) { + cmd2 = "\"" + cmd2 + "\""; + } + + //QProcess::execute(cmd2); + QProcess::startDetached(cmd2); +#endif +} diff --git a/tool/netserver/api/qthelper.h b/tool/netserver/api/qthelper.h new file mode 100644 index 0000000..6562b43 --- /dev/null +++ b/tool/netserver/api/qthelper.h @@ -0,0 +1,180 @@ +#ifndef QTHELPER_H +#define QTHELPER_H + +#include "head.h" + +class QtHelper +{ +public: + //获取所有屏幕区域/当前鼠标所在屏幕索引/区域尺寸/缩放系数 + static QList getScreenRects(bool available = true); + static int getScreenIndex(); + static QRect getScreenRect(bool available = true); + static qreal getScreenRatio(bool devicePixel = false); + + //矫正当前鼠标所在屏幕居中尺寸 + static QRect checkCenterRect(QRect &rect, bool available = true); + + //获取桌面宽度高度+居中显示 + static int deskWidth(); + static int deskHeight(); + static QSize deskSize(); + + //居中显示窗体 + //定义标志位指定是以桌面为参照还是主程序界面为参照 + static QWidget *centerBaseForm; + static void setFormInCenter(QWidget *form); + static void showForm(QWidget *form); + + //程序文件名称和当前所在路径 + static QString appName(); + static QString appPath(); + + //程序最前面获取应用程序路径和名称 + static void getCurrentInfo(char *argv[], QString &path, QString &name); + //程序最前面读取配置文件节点的值 + static QString getIniValue(const QString &fileName, const QString &key); + static QString getIniValue(char *argv[], const QString &key, const QString &dir = QString()); + + //获取本地网卡IP集合 + static QStringList getLocalIPs(); + + //获取内置颜色集合 + static QList colors; + static QList getColorList(); + static QStringList getColorNames(); + //随机获取颜色集合中的颜色 + static QColor getRandColor(); + + //初始化随机数种子 + static void initRand(); + //获取随机小数 + static float getRandFloat(float min, float max); + //获取随机数,指定最小值和最大值 + static double getRandValue(int min, int max, bool contansMin = false, bool contansMax = false); + //获取范围值随机经纬度集合 + static QStringList getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat); + //根据旧的范围值和值计算新的范围值对应的值 + static int getRangeValue(int oldMin, int oldMax, int oldValue, int newMin, int newMax); + + //获取uuid + static QString getUuid(); + //校验目录 + static void checkPath(const QString &dirName); + //通用延时函数(支持Qt4 Qt5 Qt6) + static void sleep(int msec, bool exec = true); + //检查程序是否已经运行 + static void checkRun(); + + //设置Qt自带样式 + static void setStyle(); + //设置字体 + static QFont addFont(const QString &fontFile, const QString &fontName); + static void setFont(int fontSize = 12); + //设置编码 + static void setCode(bool utf8 = true); + //设置翻译文件 + static void setTranslator(const QString &qmFile); + + //动态设置权限 + static bool checkPermission(const QString &permission); + //申请安卓权限 + static void initAndroidPermission(); + + //一次性设置所有包括编码样式字体等 + static void initAll(bool utf8 = true, bool style = true, int fontSize = 13); + //初始化main函数最前面执行的一段代码 + static void initMain(bool desktopSettingsAware = false, bool use96Dpi = true, bool logCritical = true); + //初始化opengl类型(1=AA_UseDesktopOpenGL 2=AA_UseOpenGLES 3=AA_UseSoftwareOpenGL) + static void initOpenGL(quint8 type = 0, bool checkCardEnable = false, bool checkVirtualSystem = false); + + //执行命令行返回执行结果 + static QString doCmd(const QString &program, const QStringList &arguments, int timeout = 1000); + //获取显卡是否被禁用 + static bool isVideoCardEnable(); + //获取是否在虚拟机环境 + static bool isVirtualSystem(); + + //插入消息 + static QVector msgTypes; + static QVector msgKeys; + static QVector msgColors; + static QString appendMsg(QTextEdit *textEdit, int type, const QString &data, + int maxCount, int ¤tCount, + bool clear = false, bool pause = false); + + //设置无边框 + static void setFramelessForm(QWidget *widgetMain, bool tool = false, bool top = false, bool menu = true); + + //弹出框 + static int showMessageBox(const QString &text, int type = 0, int closeSec = 0, bool exec = false); + //弹出消息框 + static void showMessageBoxInfo(const QString &text, int closeSec = 0, bool exec = false); + //弹出错误框 + static void showMessageBoxError(const QString &text, int closeSec = 0, bool exec = false); + //弹出询问框 + static int showMessageBoxQuestion(const QString &text); + + //为什么还要自定义对话框因为可控宽高和汉化对应文本等 + //初始化对话框文本 + static void initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName, + const QString &dirName, bool native, int width, int height); + //拿到对话框结果 + static QString getDialogResult(QFileDialog *dialog); + //选择文件对话框 + static QString getOpenFileName(const QString &filter = QString(), + const QString &dirName = QString(), + const QString &fileName = QString(), + bool native = false, int width = 900, int height = 600); + //保存文件对话框 + static QString getSaveFileName(const QString &filter = QString(), + const QString &dirName = QString(), + const QString &fileName = QString(), + bool native = false, int width = 900, int height = 600); + //选择目录对话框 + static QString getExistingDirectory(const QString &dirName = QString(), + bool native = false, int width = 900, int height = 600); + + //异或加密-只支持字符,如果是中文需要将其转换base64编码 + static QString getXorEncryptDecrypt(const QString &value, char key); + //异或校验 + static quint8 getOrCode(const QByteArray &data); + //计算校验码 + static quint8 getCheckCode(const QByteArray &data); + + //初始化表格 + static void initTableView(QTableView *tableView, int rowHeight = 25, + bool headVisible = false, bool edit = false, + bool stretchLast = true); + //打开文件带提示框 + static void openFile(const QString &fileName, const QString &msg); + + //检查ini配置文件 + static bool checkIniFile(const QString &iniFile); + + //首尾截断字符串显示 + static QString cutString(const QString &text, int len, int left, int right, bool file, const QString &mid = "..."); + + //传入图片尺寸和窗体区域及边框大小返回居中区域(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充) + static QRect getCenterRect(const QSize &imageSize, const QRect &widgetRect, int borderWidth = 2, int scaleMode = 0); + //传入图片尺寸和窗体尺寸及缩放策略返回合适尺寸(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充) + static void getScaledImage(QImage &image, const QSize &widgetSize, int scaleMode = 0, bool fast = true); + + //毫秒数转时间 00:00 + static QString getTimeString(qint64 time); + //用时时间转秒数 + static QString getTimeString(QElapsedTimer timer); + //文件大小转 KB MB GB TB + static QString getSizeString(quint64 size); + + //设置系统时间 + static void setSystemDateTime(const QString &year, const QString &month, const QString &day, + const QString &hour, const QString &min, const QString &sec); + //设置开机自启动 + static void runWithSystem(bool autoRun = true); + static void runWithSystem(const QString &fileName, const QString &filePath, bool autoRun = true); + //启动运行程序(已经在运行则不启动) + static void runBin(const QString &path, const QString &name); +}; + +#endif // QTHELPER_H diff --git a/tool/netserver/api/qthelperdata.cpp b/tool/netserver/api/qthelperdata.cpp new file mode 100644 index 0000000..5f26ee5 --- /dev/null +++ b/tool/netserver/api/qthelperdata.cpp @@ -0,0 +1,473 @@ +#include "qthelperdata.h" +#include "qthelper.h" + +int QtHelperData::strHexToDecimal(const QString &strHex) +{ + bool ok; + return strHex.toInt(&ok, 16); +} + +int QtHelperData::strDecimalToDecimal(const QString &strDecimal) +{ + bool ok; + return strDecimal.toInt(&ok, 10); +} + +int QtHelperData::strBinToDecimal(const QString &strBin) +{ + bool ok; + return strBin.toInt(&ok, 2); +} + +QString QtHelperData::strHexToStrBin(const QString &strHex) +{ + quint8 decimal = strHexToDecimal(strHex); + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + + if (len < 8) { + for (int i = 0; i < 8 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrBin1(int decimal) +{ + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + if (len <= 8) { + for (int i = 0; i < 8 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrBin2(int decimal) +{ + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + if (len <= 16) { + for (int i = 0; i < 16 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrHex(int decimal) +{ + QString temp = QString::number(decimal, 16); + if (temp.length() == 1) { + temp = "0" + temp; + } + + return temp; +} + +QByteArray QtHelperData::intToByte(int data, bool reverse) +{ + quint8 data1 = (quint8)(0x000000ff & data); + quint8 data2 = (quint8)((0x0000ff00 & data) >> 8); + quint8 data3 = (quint8)((0x00ff0000 & data) >> 16); + quint8 data4 = (quint8)((0xff000000 & data) >> 24); + + QByteArray result; + result.resize(4); + if (reverse) { + result[0] = data1; + result[1] = data2; + result[2] = data3; + result[3] = data4; + } else { + result[0] = data4; + result[1] = data3; + result[2] = data2; + result[3] = data1; + } + return result; +} + +int QtHelperData::byteToInt(const QByteArray &data, bool reverse) +{ + int result = 0; + if (reverse) { + result = data.at(0) & 0x000000ff; + result |= ((data.at(1) << 8) & 0x0000ff00); + result |= ((data.at(2) << 16) & 0x00ff0000); + result |= ((data.at(3) << 24) & 0xff000000); + } else { + result = data.at(3) & 0x000000ff; + result |= ((data.at(2) << 8) & 0x0000ff00); + result |= ((data.at(1) << 16) & 0x00ff0000); + result |= ((data.at(0) << 24) & 0xff000000); + } + return result; +} + +QByteArray QtHelperData::ushortToByte(int data, bool reverse) +{ + quint8 data1 = (quint8)(0x000000ff & data); + quint8 data2 = (quint8)((0x0000ff00 & data) >> 8); + + QByteArray result; + result.resize(2); + if (reverse) { + result[0] = data1; + result[1] = data2; + } else { + result[0] = data2; + result[1] = data1; + } + return result; +} + +int QtHelperData::byteToShort(const QByteArray &data, bool reverse) +{ + int result = 0; + if (reverse) { + result = data.at(0) & 0x000000ff; + result |= ((data.at(1) << 8) & 0x0000ff00); + } else { + result = data.at(1) & 0x000000ff; + result |= ((data.at(0) << 8) & 0x0000ff00); + } + if (result >= 32768) { + result = result - 65536; + } + return result; +} + +QString QtHelperData::getValue(quint8 value) +{ + QString result = QString::number(value); + if (result.length() <= 1) { + result = QString("0%1").arg(result); + } + return result; +} + +QString QtHelperData::trimmed(const QString &text, int type) +{ + QString temp = text; + QString pattern; + if (type == -1) { + pattern = "^ +\\s*"; + } else if (type == 0) { + pattern = "\\s"; + //temp.replace(" ", ""); + } else if (type == 1) { + pattern = "\\s* +$"; + } else if (type == 2) { + temp = temp.trimmed(); + } else if (type == 3) { + temp = temp.simplified(); + } + + //调用正则表达式移除空格 + if (!pattern.isEmpty()) { +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + temp.remove(QRegularExpression(pattern)); +#else + temp.remove(QRegExp(pattern)); +#endif + } + + return temp; +} + +QString QtHelperData::getXorEncryptDecrypt(const QString &value, char key) +{ + //矫正范围外的数据 + if (key < 0 || key >= 127) { + key = 127; + } + + //大概从5.9版本输出的加密密码字符串前面会加上 @String 字符 + QString result = value; + if (result.startsWith("@String")) { + result = result.mid(8, result.length() - 9); + } + + for (int i = 0; i < result.length(); ++i) { + result[i] = QChar(result.at(i).toLatin1() ^ key); + } + return result; +} + +quint8 QtHelperData::getOrCode(const QByteArray &data) +{ + int len = data.length(); + quint8 result = 0; + for (int i = 0; i < len; ++i) { + result ^= data.at(i); + } + + return result; +} + +quint8 QtHelperData::getCheckCode(const QByteArray &data) +{ + int len = data.length(); + quint8 temp = 0; + for (int i = 0; i < len; ++i) { + temp += data.at(i); + } + + return temp % 256; +} + +void QtHelperData::getFullData(QByteArray &buffer) +{ + //计算校验码 + quint8 checkCode = getCheckCode(buffer); + //尾部插入校验码 + buffer.append(checkCode); + //头部插入固定帧头 + buffer.insert(0, 0x16); +} + +//函数功能:计算CRC16 +//参数1:*data 16位CRC校验数据, +//参数2:len 数据流长度 +//参数3:init 初始化值 +//参数4:table 16位CRC查找表 + +//正序CRC计算 +quint16 QtHelperData::getCrc16(quint8 *data, int len, quint16 init, const quint16 *table) +{ + quint16 crc_16 = init; + quint8 temp; + while (len-- > 0) { + temp = crc_16 & 0xff; + crc_16 = (crc_16 >> 8) ^ table[(temp ^ *data++) & 0xff]; + } + + return crc_16; +} + +//逆序CRC计算 +quint16 QtHelperData::getCrc16Rec(quint8 *data, int len, quint16 init, const quint16 *table) +{ + quint16 crc_16 = init; + quint8 temp; + while (len-- > 0) { + temp = crc_16 >> 8; + crc_16 = (crc_16 << 8) ^ table[(temp ^ *data++) & 0xff]; + } + + return crc_16; +} + +//Modbus CRC16校验 +quint16 QtHelperData::getModbus16(quint8 *data, int len) +{ + //MODBUS CRC-16表 8005 逆序 + const quint16 table_16[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 + }; + + return getCrc16(data, len, 0xFFFF, table_16); +} + +//CRC16校验 +QByteArray QtHelperData::getCrcCode(const QByteArray &data) +{ + quint16 result = getModbus16((quint8 *)data.data(), data.length()); + return QtHelperData::ushortToByte(result, true); +} + +static QMap listChar; +void QtHelperData::initAscii() +{ + //0x20为空格,空格以下都是不可见字符 + if (listChar.count() == 0) { + listChar.insert(0, "\\NUL"); + listChar.insert(1, "\\SOH"); + listChar.insert(2, "\\STX"); + listChar.insert(3, "\\ETX"); + listChar.insert(4, "\\EOT"); + listChar.insert(5, "\\ENQ"); + listChar.insert(6, "\\ACK"); + listChar.insert(7, "\\BEL"); + listChar.insert(8, "\\BS"); + listChar.insert(9, "\\HT"); + listChar.insert(10, "\\LF"); + listChar.insert(11, "\\VT"); + listChar.insert(12, "\\FF"); + listChar.insert(13, "\\CR"); + listChar.insert(14, "\\SO"); + listChar.insert(15, "\\SI"); + listChar.insert(16, "\\DLE"); + listChar.insert(17, "\\DC1"); + listChar.insert(18, "\\DC2"); + listChar.insert(19, "\\DC3"); + listChar.insert(20, "\\DC4"); + listChar.insert(21, "\\NAK"); + listChar.insert(22, "\\SYN"); + listChar.insert(23, "\\ETB"); + listChar.insert(24, "\\CAN"); + listChar.insert(25, "\\EM"); + listChar.insert(26, "\\SUB"); + listChar.insert(27, "\\ESC"); + listChar.insert(28, "\\FS"); + listChar.insert(29, "\\GS"); + listChar.insert(30, "\\RS"); + listChar.insert(31, "\\US"); + listChar.insert(0x5C, "\\"); + listChar.insert(0x7F, "\\DEL"); + } +} + +QString QtHelperData::byteArrayToAsciiStr(const QByteArray &data) +{ + //先初始化字符表 + initAscii(); + + QString temp; + int len = data.length(); + for (int i = 0; i < len; ++i) { + char byte = data.at(i); + QString value = listChar.value(byte); + if (!value.isEmpty()) { + } else if (byte >= 0 && byte <= 0x7F) { + value = QString("%1").arg(byte); + } else { + value = decimalToStrHex((quint8)byte); + value = QString("\\x%1").arg(value.toUpper()); + } + + temp += value; + } + + return temp.trimmed(); +} + +QByteArray QtHelperData::asciiStrToByteArray(const QString &data) +{ + //先初始化字符表 + initAscii(); + + QByteArray buffer; + QStringList list = data.split("\\"); + + int count = list.count(); + for (int i = 1; i < count; ++i) { + QString str = list.at(i); + int key = 0; + if (str.contains("x")) { + key = strHexToDecimal(str.mid(1, 2)); + } else { + key = listChar.key("\\" + str); + } + + buffer.append(key); + } + + //可能是纯字符串不带控制字符 + if (buffer.length() == 0) { + buffer = data.toUtf8(); + } + + return buffer; +} + +char QtHelperData::hexStrToChar(char data) +{ + if ((data >= '0') && (data <= '9')) { + return data - 0x30; + } else if ((data >= 'A') && (data <= 'F')) { + return data - 'A' + 10; + } else if ((data >= 'a') && (data <= 'f')) { + return data - 'a' + 10; + } else { + return (-1); + } +} + +QByteArray QtHelperData::hexStrToByteArray(const QString &data) +{ + QByteArray senddata; + int hexdata, lowhexdata; + int hexdatalen = 0; + int len = data.length(); + senddata.resize(len / 2); + char lstr, hstr; + + for (int i = 0; i < len;) { + hstr = data.at(i).toLatin1(); + if (hstr == ' ') { + i++; + continue; + } + + i++; + if (i >= len) { + break; + } + + lstr = data.at(i).toLatin1(); + hexdata = hexStrToChar(hstr); + lowhexdata = hexStrToChar(lstr); + + if ((hexdata == 16) || (lowhexdata == 16)) { + break; + } else { + hexdata = hexdata * 16 + lowhexdata; + } + + i++; + senddata[hexdatalen] = (char)hexdata; + hexdatalen++; + } + + senddata.resize(hexdatalen); + return senddata; +} + +QString QtHelperData::byteArrayToHexStr(const QByteArray &data) +{ + QString temp = ""; + QString hex = data.toHex(); + for (int i = 0; i < hex.length(); i = i + 2) { + temp += hex.mid(i, 2) + " "; + } + + return temp.trimmed().toUpper(); +} diff --git a/tool/netserver/api/qthelperdata.h b/tool/netserver/api/qthelperdata.h new file mode 100644 index 0000000..0f649c3 --- /dev/null +++ b/tool/netserver/api/qthelperdata.h @@ -0,0 +1,65 @@ +#ifndef QTHELPERDATA_H +#define QTHELPERDATA_H + +#include + +class QtHelperData +{ +public: + //16进制字符串转10进制 + static int strHexToDecimal(const QString &strHex); + //10进制字符串转10进制 + static int strDecimalToDecimal(const QString &strDecimal); + //2进制字符串转10进制 + static int strBinToDecimal(const QString &strBin); + + //16进制字符串转2进制字符串 + static QString strHexToStrBin(const QString &strHex); + //10进制转2进制字符串一个字节 + static QString decimalToStrBin1(int decimal); + //10进制转2进制字符串两个字节 + static QString decimalToStrBin2(int decimal); + //10进制转16进制字符串,补零. + static QString decimalToStrHex(int decimal); + + //int和字节数组互转 + static QByteArray intToByte(int data, bool reverse = false); + static int byteToInt(const QByteArray &data, bool reverse = false); + + //ushort和字节数组互转 + static QByteArray ushortToByte(int data, bool reverse = false); + static int byteToShort(const QByteArray &data, bool reverse = false); + + //字符串补全 + static QString getValue(quint8 value); + //字符串去空格 -1=移除左侧空格 0=移除所有空格 1=移除右侧空格 2=移除首尾空格 3=首尾清除中间留一个空格 + static QString trimmed(const QString &text, int type); + + //异或加密-只支持字符,如果是中文需要将其转换base64编码 + static QString getXorEncryptDecrypt(const QString &value, char key); + //异或校验 + static quint8 getOrCode(const QByteArray &data); + + //公司专用-计算校验码 + static quint8 getCheckCode(const QByteArray &data); + //公司专用-加上桢头和校验码完整数据 + static void getFullData(QByteArray &buffer); + + //CRC校验 + static quint16 getCrc16Rec(quint8 *data, int len, quint16 init, const quint16 *table); + static quint16 getCrc16(quint8 *data, int len, quint16 init, const quint16 *table); + static quint16 getModbus16(quint8 *data, int len); + static QByteArray getCrcCode(const QByteArray &data); + + //字节数组与Ascii字符串互转 + static void initAscii(); + static QString byteArrayToAsciiStr(const QByteArray &data); + static QByteArray asciiStrToByteArray(const QString &data); + + //16进制字符串与字节数组互转 + static char hexStrToChar(char data); + static QByteArray hexStrToByteArray(const QString &data); + static QString byteArrayToHexStr(const QByteArray &data); +}; + +#endif // QTHELPERDATA_H diff --git a/tool/netserver/api/tcpserver1.cpp b/tool/netserver/api/tcpserver1.cpp new file mode 100644 index 0000000..67897b6 --- /dev/null +++ b/tool/netserver/api/tcpserver1.cpp @@ -0,0 +1,156 @@ +#include "tcpserver1.h" +#include "qthelper.h" +#include "qthelperdata.h" + +TcpClient1::TcpClient1(QObject *parent) : QTcpSocket(parent) +{ + ip = "127.0.0.1"; + port = 6907; + deviceID = "SSJC00000001"; + + connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); + connect(this, SIGNAL(readyRead()), this, SLOT(readData())); +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + connect(this, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(deleteLater())); +#else + connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(deleteLater())); +#endif +} + +void TcpClient1::setIP(const QString &ip) +{ + this->ip = ip; +} + +QString TcpClient1::getIP() const +{ + return this->ip; +} + +void TcpClient1::setPort(int port) +{ + this->port = port; +} + +int TcpClient1::getPort() const +{ + return this->port; +} + +QString TcpClient1::getDeviceID() +{ + return this->deviceID; +} + +void TcpClient1::readData() +{ + QByteArray data = this->readAll(); + if (data.length() <= 0) { + return; + } + + //取出唯一标识符,并过滤,可自行更改过滤条件 + QByteArray cmd = data.mid(AppConfig::CmdStart1, AppConfig::CmdLen1); + QString id = QString(cmd); + if (id.startsWith("S") && deviceID != id) { + deviceID = id; + //发送信号更新标识符 + emit receiveDeviceID(ip, port, deviceID); + } + + QString buffer; + if (AppConfig::HexData1) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else { + buffer = QString(data); + } + + emit receiveData(ip, port, deviceID, buffer); +} + +void TcpClient1::sendData(const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexData1) { + buffer = QtHelperData::hexStrToByteArray(data); + } else { + buffer = data.toLatin1(); + } + + this->write(buffer); + emit sendData(ip, port, deviceID, data); +} + +TcpServer1::TcpServer1(QObject *parent) : QTcpServer(parent) +{ +} + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) +void TcpServer1::incomingConnection(qintptr handle) +#else +void TcpServer1::incomingConnection(int handle) +#endif +{ + TcpClient1 *client = new TcpClient1(this); + client->setSocketDescriptor(handle); + connect(client, SIGNAL(disconnected()), this, SLOT(disconnected())); + connect(client, SIGNAL(sendData(QString, int, QString, QString)), this, SIGNAL(sendData(QString, int, QString, QString))); + connect(client, SIGNAL(receiveData(QString, int, QString, QString)), this, SIGNAL(receiveData(QString, int, QString, QString))); + connect(client, SIGNAL(receiveDeviceID(QString, int, QString)), this, SIGNAL(receiveDeviceID(QString, int, QString))); + + QString ip = client->peerAddress().toString(); + int port = client->peerPort(); + QString deviceID = client->getDeviceID(); + client->setIP(ip); + client->setPort(port); + emit clientConnected(ip, port, deviceID); + emit sendData(ip, port, deviceID, "客户端上线"); + + //追加到链表中 + clients.append(client); +} + +void TcpServer1::disconnected() +{ + TcpClient1 *client = (TcpClient1 *)sender(); + QString ip = client->getIP(); + int port = client->getPort(); + QString deviceID = client->getDeviceID(); + emit clientDisconnected(ip, port, deviceID); + emit sendData(ip, port, deviceID, "客户端下线"); + + //断开连接后从链表中移除 + clients.removeOne(client); +} + +bool TcpServer1::start() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + bool ok = listen(QHostAddress::AnyIPv4, AppConfig::ListenPort1); +#else + bool ok = listen(QHostAddress::Any, AppConfig::ListenPort1); +#endif + return ok; +} + +void TcpServer1::stop() +{ + foreach (TcpClient1 *client, clients) { + client->disconnectFromHost(); + } + + this->close(); +} + +bool TcpServer1::writeData(const QString &deviceID, const QString &data) +{ + bool ok = false; + foreach (TcpClient1 *client, clients) { + if (client->getDeviceID() == deviceID) { + client->sendData(data); + ok = true; + } + } + + return ok; +} diff --git a/tool/netserver/api/tcpserver1.h b/tool/netserver/api/tcpserver1.h new file mode 100644 index 0000000..71266cf --- /dev/null +++ b/tool/netserver/api/tcpserver1.h @@ -0,0 +1,74 @@ +#ifndef TCPSERVER1_H +#define TCPSERVER1_H + +#include + +class TcpClient1 : public QTcpSocket +{ + Q_OBJECT +public: + explicit TcpClient1(QObject *parent = 0); + +private: + QString ip; + int port; + QString deviceID; + +public: + void setIP(const QString &ip); + QString getIP()const; + void setPort(int port); + int getPort()const; + + QString getDeviceID(); + +private slots: + void readData(); + +signals: + void sendData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveDeviceID(const QString &ip, int port, const QString &deviceID); + +public slots: + void sendData(const QString &data); + +}; + +class TcpServer1 : public QTcpServer +{ + Q_OBJECT +public: + explicit TcpServer1(QObject *parent = 0); + +private: + QList clients; + +protected: +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + void incomingConnection(qintptr handle); +#else + void incomingConnection(int handle); +#endif + +private slots: + void disconnected(); + +signals: + void clientConnected(const QString &ip, int port, const QString &deviceID); + void clientDisconnected(const QString &ip, int port, const QString &deviceID); + void sendData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveDeviceID(const QString &ip, int port, const QString &deviceID); + +public slots: + //启动服务 + bool start(); + //停止服务 + void stop(); + + //对指定连接发送数据 + bool writeData(const QString &deviceID, const QString &data); +}; + +#endif // TCPSERVER1_H diff --git a/tool/netserver/api/tcpserver2.cpp b/tool/netserver/api/tcpserver2.cpp new file mode 100644 index 0000000..89026d7 --- /dev/null +++ b/tool/netserver/api/tcpserver2.cpp @@ -0,0 +1,156 @@ +#include "tcpserver2.h" +#include "qthelper.h" +#include "qthelperdata.h" + +TcpClient2::TcpClient2(QObject *parent) : QTcpSocket(parent) +{ + ip = "127.0.0.1"; + port = 6908; + deviceID = "SSJC00000001"; + + connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); + connect(this, SIGNAL(readyRead()), this, SLOT(readData())); +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + connect(this, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(deleteLater())); +#else + connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(deleteLater())); +#endif +} + +void TcpClient2::setIP(const QString &ip) +{ + this->ip = ip; +} + +QString TcpClient2::getIP() const +{ + return this->ip; +} + +void TcpClient2::setPort(int port) +{ + this->port = port; +} + +int TcpClient2::getPort() const +{ + return this->port; +} + +QString TcpClient2::getDeviceID() +{ + return this->deviceID; +} + +void TcpClient2::readData() +{ + QByteArray data = this->readAll(); + if (data.length() <= 0) { + return; + } + + //取出唯一标识符,并过滤,可自行更改过滤条件 + QByteArray cmd = data.mid(AppConfig::CmdStart2, AppConfig::CmdLen2); + QString id = QString(cmd); + if (id.startsWith("S") && deviceID != id) { + deviceID = id; + //发送信号更新标识符 + emit receiveDeviceID(ip, port, deviceID); + } + + QString buffer; + if (AppConfig::HexData2) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else { + buffer = QString(data); + } + + emit receiveData(ip, port, deviceID, buffer); +} + +void TcpClient2::sendData(const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexData2) { + buffer = QtHelperData::hexStrToByteArray(data); + } else { + buffer = data.toLatin1(); + } + + this->write(buffer); + emit sendData(ip, port, deviceID, data); +} + +TcpServer2::TcpServer2(QObject *parent) : QTcpServer(parent) +{ +} + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) +void TcpServer2::incomingConnection(qintptr handle) +#else +void TcpServer2::incomingConnection(int handle) +#endif +{ + TcpClient2 *client = new TcpClient2(this); + client->setSocketDescriptor(handle); + connect(client, SIGNAL(disconnected()), this, SLOT(disconnected())); + connect(client, SIGNAL(sendData(QString, int, QString, QString)), this, SIGNAL(sendData(QString, int, QString, QString))); + connect(client, SIGNAL(receiveData(QString, int, QString, QString)), this, SIGNAL(receiveData(QString, int, QString, QString))); + connect(client, SIGNAL(receiveDeviceID(QString, int, QString)), this, SIGNAL(receiveDeviceID(QString, int, QString))); + + QString ip = client->peerAddress().toString(); + int port = client->peerPort(); + QString deviceID = client->getDeviceID(); + client->setIP(ip); + client->setPort(port); + emit clientConnected(ip, port, deviceID); + emit sendData(ip, port, deviceID, "客户端上线"); + + //追加到链表中 + clients.append(client); +} + +void TcpServer2::disconnected() +{ + TcpClient2 *client = (TcpClient2 *)sender(); + QString ip = client->getIP(); + int port = client->getPort(); + QString deviceID = client->getDeviceID(); + emit clientDisconnected(ip, port, deviceID); + emit sendData(ip, port, deviceID, "客户端下线"); + + //断开连接后从链表中移除 + clients.removeOne(client); +} + +bool TcpServer2::start() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + bool ok = listen(QHostAddress::AnyIPv4, AppConfig::ListenPort2); +#else + bool ok = listen(QHostAddress::Any, AppConfig::ListenPort2); +#endif + return ok; +} + +void TcpServer2::stop() +{ + foreach (TcpClient2 *client, clients) { + client->disconnectFromHost(); + } + + this->close(); +} + +bool TcpServer2::writeData(const QString &deviceID, const QString &data) +{ + bool ok = false; + foreach (TcpClient2 *client, clients) { + if (client->getDeviceID() == deviceID) { + client->sendData(data); + ok = true; + } + } + + return ok; +} diff --git a/tool/netserver/api/tcpserver2.h b/tool/netserver/api/tcpserver2.h new file mode 100644 index 0000000..e0ccb1d --- /dev/null +++ b/tool/netserver/api/tcpserver2.h @@ -0,0 +1,74 @@ +#ifndef TCPSERVER2_H +#define TCPSERVER2_H + +#include + +class TcpClient2 : public QTcpSocket +{ + Q_OBJECT +public: + explicit TcpClient2(QObject *parent = 0); + +private: + QString ip; + int port; + QString deviceID; + +public: + void setIP(const QString &ip); + QString getIP()const; + void setPort(int port); + int getPort()const; + + QString getDeviceID(); + +private slots: + void readData(); + +signals: + void sendData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveDeviceID(const QString &ip, int port, const QString &deviceID); + +public slots: + void sendData(const QString &data); + +}; + +class TcpServer2 : public QTcpServer +{ + Q_OBJECT +public: + explicit TcpServer2(QObject *parent = 0); + +private: + QList clients; + +protected: +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + void incomingConnection(qintptr handle); +#else + void incomingConnection(int handle); +#endif + +private slots: + void disconnected(); + +signals: + void clientConnected(const QString &ip, int port, const QString &deviceID); + void clientDisconnected(const QString &ip, int port, const QString &deviceID); + void sendData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveData(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveDeviceID(const QString &ip, int port, const QString &deviceID); + +public slots: + //启动服务 + bool start(); + //停止服务 + void stop(); + + //对指定连接发送数据 + bool writeData(const QString &deviceID, const QString &data); +}; + +#endif // TCPSERVER2_H diff --git a/tool/netserver/form/form.pri b/tool/netserver/form/form.pri new file mode 100644 index 0000000..ab07823 --- /dev/null +++ b/tool/netserver/form/form.pri @@ -0,0 +1,8 @@ +FORMS += \ + $$PWD/frmmain.ui + +HEADERS += \ + $$PWD/frmmain.h + +SOURCES += \ + $$PWD/frmmain.cpp diff --git a/tool/netserver/form/frmmain.cpp b/tool/netserver/form/frmmain.cpp new file mode 100644 index 0000000..23f98f5 --- /dev/null +++ b/tool/netserver/form/frmmain.cpp @@ -0,0 +1,206 @@ +#include "frmmain.h" +#include "ui_frmmain.h" +#include "qthelper.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); + on_btnListen1_clicked(); + on_btnListen2_clicked(); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::initForm() +{ + tcpServer1 = new TcpServer1(this); + connect(tcpServer1, SIGNAL(clientConnected(QString, int, QString)), this, SLOT(clientConnected1(QString, int, QString))); + connect(tcpServer1, SIGNAL(clientDisconnected(QString, int, QString)), this, SLOT(clientDisconnected1(QString, int, QString))); + connect(tcpServer1, SIGNAL(sendData(QString, int, QString, QString)), this, SLOT(sendData1(QString, int, QString, QString))); + connect(tcpServer1, SIGNAL(receiveData(QString, int, QString, QString)), this, SLOT(receiveData1(QString, int, QString, QString))); + connect(tcpServer1, SIGNAL(receiveDeviceID(QString, int, QString)), this, SLOT(receiveDeviceID1(QString, int, QString))); + + tcpServer2 = new TcpServer2(this); + connect(tcpServer2, SIGNAL(clientConnected(QString, int, QString)), this, SLOT(clientConnected2(QString, int, QString))); + connect(tcpServer2, SIGNAL(clientDisconnected(QString, int, QString)), this, SLOT(clientDisconnected2(QString, int, QString))); + connect(tcpServer2, SIGNAL(sendData(QString, int, QString, QString)), this, SLOT(sendData2(QString, int, QString, QString))); + connect(tcpServer2, SIGNAL(receiveData(QString, int, QString, QString)), this, SLOT(receiveData2(QString, int, QString, QString))); + connect(tcpServer2, SIGNAL(receiveDeviceID(QString, int, QString)), this, SLOT(receiveDeviceID2(QString, int, QString))); +} + +void frmMain::initConfig() +{ + ui->txtListenPort1->setText(QString::number(AppConfig::ListenPort1)); + connect(ui->txtListenPort1, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtListenPort2->setText(QString::number(AppConfig::ListenPort2)); + connect(ui->txtListenPort2, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); +} + +void frmMain::saveConfig() +{ + AppConfig::ListenPort1 = ui->txtListenPort1->text().trimmed().toInt(); + AppConfig::ListenPort2 = ui->txtListenPort2->text().trimmed().toInt(); + AppConfig::writeConfig(); +} + +void frmMain::append1(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain1, type, data.left(500), maxCount, currentCount, clear); +} + +void frmMain::append2(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain2, type, data.left(500), maxCount, currentCount, clear); +} + +void frmMain::clientConnected1(const QString &ip, int port, const QString &deviceID) +{ + QString str = QString("%1 %2:%3").arg(deviceID).arg(ip).arg(port); + ui->listWidget1->addItem(str); + ui->labCount1->setText(QString("共 %1 个连接").arg(ui->listWidget1->count())); +} + +void frmMain::clientDisconnected1(const QString &ip, int port, const QString &deviceID) +{ + int row = -1; + QString str = QString("%1 %2:%3").arg(deviceID).arg(ip).arg(port); + for (int i = 0; i < ui->listWidget1->count(); i++) { + if (ui->listWidget1->item(i)->text() == str) { + row = i; + break; + } + } + + ui->listWidget1->takeItem(row); + ui->labCount1->setText(QString("共 %1 个连接").arg(ui->listWidget1->count())); +} + +void frmMain::sendData1(const QString &ip, int port, const QString &deviceID, const QString &data) +{ + QString str = QString("%1 [%2:%3] %4").arg(deviceID).arg(ip).arg(port).arg(data); + bool error = (data.contains("下线") || data.contains("离线")); + append1(error ? 1 : 0, str); +} + +void frmMain::receiveData1(const QString &ip, int port, const QString &deviceID, const QString &data) +{ + QString str = QString("%1 [%2:%3] %4").arg(deviceID).arg(ip).arg(port).arg(data); + append1(1, str); + + //将收到的数据转发到另一路网络 + bool ok = tcpServer2->writeData(deviceID, data); + sendData2(ip, port, deviceID, ok ? "转发成功" : "对方离线"); + if (!ok) { + tcpServer1->writeData(deviceID, "deviceError"); + } +} + +void frmMain::receiveDeviceID1(const QString &ip, int port, const QString &deviceID) +{ + QString temp = QString("%1:%2").arg(ip).arg(port); + QString str = QString("%1 %2:%3").arg(deviceID).arg(ip).arg(port); + for (int i = 0; i < ui->listWidget1->count(); i++) { + if (ui->listWidget1->item(i)->text().endsWith(temp)) { + ui->listWidget1->item(i)->setText(str); + break; + } + } +} + +void frmMain::clientConnected2(const QString &ip, int port, const QString &deviceID) +{ + QString str = QString("%1 %2:%3").arg(deviceID).arg(ip).arg(port); + ui->listWidget2->addItem(str); + ui->labCount2->setText(QString("共 %1 个连接").arg(ui->listWidget2->count())); +} + +void frmMain::clientDisconnected2(const QString &ip, int port, const QString &deviceID) +{ + int row = -1; + QString str = QString("%1 %2:%3").arg(deviceID).arg(ip).arg(port); + for (int i = 0; i < ui->listWidget2->count(); i++) { + if (ui->listWidget2->item(i)->text() == str) { + row = i; + break; + } + } + + ui->listWidget2->takeItem(row); + ui->labCount2->setText(QString("共 %1 个连接").arg(ui->listWidget2->count())); +} + +void frmMain::sendData2(const QString &ip, int port, const QString &deviceID, const QString &data) +{ + QString str = QString("%1 [%2:%3] %4").arg(deviceID).arg(ip).arg(port).arg(data); + bool error = (data.contains("下线") || data.contains("离线")); + append2(error ? 1 : 0, str); +} + +void frmMain::receiveData2(const QString &ip, int port, const QString &deviceID, const QString &data) +{ + QString str = QString("%1 [%2:%3] %4").arg(deviceID).arg(ip).arg(port).arg(data); + append2(1, str); + + //将收到的数据转发到另一路网络 + bool ok = tcpServer1->writeData(deviceID, data); + sendData1(ip, port, deviceID, ok ? "转发成功" : "对方离线"); + if (!ok) { + tcpServer2->writeData(deviceID, "deviceError"); + } +} + +void frmMain::receiveDeviceID2(const QString &ip, int port, const QString &deviceID) +{ + QString temp = QString("%1:%2").arg(ip).arg(port); + QString str = QString("%1 %2:%3").arg(deviceID).arg(ip).arg(port); + for (int i = 0; i < ui->listWidget2->count(); i++) { + if (ui->listWidget2->item(i)->text().endsWith(temp)) { + ui->listWidget2->item(i)->setText(str); + break; + } + } +} + +void frmMain::on_btnListen1_clicked() +{ + if (ui->btnListen1->text() == "监听") { + if (tcpServer1->start()) { + ui->btnListen1->setText("关闭"); + } + } else { + tcpServer1->stop(); + ui->btnListen1->setText("监听"); + } +} + +void frmMain::on_btnClear1_clicked() +{ + append1(0, "", true); +} + +void frmMain::on_btnListen2_clicked() +{ + if (ui->btnListen2->text() == "监听") { + if (tcpServer2->start()) { + ui->btnListen2->setText("关闭"); + } + } else { + tcpServer2->stop(); + ui->btnListen2->setText("监听"); + } +} + +void frmMain::on_btnClear2_clicked() +{ + append2(0, "", true); +} diff --git a/tool/netserver/form/frmmain.h b/tool/netserver/form/frmmain.h new file mode 100644 index 0000000..be3e64e --- /dev/null +++ b/tool/netserver/form/frmmain.h @@ -0,0 +1,53 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include +#include "tcpserver1.h" +#include "tcpserver2.h" + +namespace Ui +{ + class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; + TcpServer1 *tcpServer1; + TcpServer2 *tcpServer2; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); + void append1(int type, const QString &data, bool clear = false); + void append2(int type, const QString &data, bool clear = false); + +private slots: + void clientConnected1(const QString &ip, int port, const QString &deviceID); + void clientDisconnected1(const QString &ip, int port, const QString &deviceID); + void sendData1(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveData1(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveDeviceID1(const QString &ip, int port, const QString &deviceID); + + void clientConnected2(const QString &ip, int port, const QString &deviceID); + void clientDisconnected2(const QString &ip, int port, const QString &deviceID); + void sendData2(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveData2(const QString &ip, int port, const QString &deviceID, const QString &data); + void receiveDeviceID2(const QString &ip, int port, const QString &deviceID); + +private slots: + void on_btnListen1_clicked(); + void on_btnClear1_clicked(); + void on_btnListen2_clicked(); + void on_btnClear2_clicked(); +}; + +#endif // FRMMAIN_H diff --git a/tool/netserver/form/frmmain.ui b/tool/netserver/form/frmmain.ui new file mode 100644 index 0000000..83504ed --- /dev/null +++ b/tool/netserver/form/frmmain.ui @@ -0,0 +1,246 @@ + + + frmMain + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + + 服务器1 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 230 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + 监听端口 + + + + + + + + + + + + 监听 + + + + + + + 清空 + + + + + + + + 0 + 25 + + + + QFrame::Box + + + QFrame::Sunken + + + 共 0 个连接 + + + Qt::AlignCenter + + + + + + + + + + + + + + 服务器2 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 230 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + 监听端口 + + + + + + + + + + + + 监听 + + + + + + + 清空 + + + + + + + + 0 + 25 + + + + QFrame::Box + + + QFrame::Sunken + + + 共 0 个连接 + + + Qt::AlignCenter + + + + + + + + + + + + + + + + + + diff --git a/tool/netserver/head.h b/tool/netserver/head.h new file mode 100644 index 0000000..9646601 --- /dev/null +++ b/tool/netserver/head.h @@ -0,0 +1,17 @@ +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) +#include +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +#include +#endif + +#pragma execution_character_set("utf-8") +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) +#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")) + +#include "appconfig.h" diff --git a/tool/netserver/main.cpp b/tool/netserver/main.cpp new file mode 100644 index 0000000..8b36062 --- /dev/null +++ b/tool/netserver/main.cpp @@ -0,0 +1,30 @@ +#include "frmmain.h" +#include "qthelper.h" + +int main(int argc, char *argv[]) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + QApplication::setAttribute(Qt::AA_Use96Dpi); +#endif +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor); +#endif + + QApplication a(argc, argv); + a.setWindowIcon(QIcon(":/main.ico")); + + //设置编码以及加载中文翻译文件 + QtHelper::initAll(); + + //读取配置文件 + AppConfig::ConfigFile = QString("%1/%2.ini").arg(QtHelper::appPath()).arg(QtHelper::appName()); + AppConfig::readConfig(); + + frmMain w; + w.setWindowTitle("网络中转服务器 V2023 (QQ: 517216493 WX: feiyangqingyun)"); + w.resize(900, 650); + QtHelper::setFormInCenter(&w); + w.show(); + + return a.exec(); +} diff --git a/tool/netserver/netserver.pro b/tool/netserver/netserver.pro new file mode 100644 index 0000000..f963869 --- /dev/null +++ b/tool/netserver/netserver.pro @@ -0,0 +1,20 @@ +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = netserver +TEMPLATE = app +DESTDIR = $$PWD/../bin +RC_FILE = qrc/main.rc + +HEADERS += head.h +SOURCES += main.cpp +RESOURCES += qrc/main.qrc +CONFIG += warn_off + +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD/api +INCLUDEPATH += $$PWD/form + +include ($$PWD/api/api.pri) +include ($$PWD/form/form.pri) diff --git a/tool/netserver/qrc/main.ico b/tool/netserver/qrc/main.ico new file mode 100644 index 0000000..920d393 Binary files /dev/null and b/tool/netserver/qrc/main.ico differ diff --git a/tool/netserver/qrc/main.qrc b/tool/netserver/qrc/main.qrc new file mode 100644 index 0000000..8bd6284 --- /dev/null +++ b/tool/netserver/qrc/main.qrc @@ -0,0 +1,7 @@ + + + main.ico + qm/qt_zh_CN.qm + qm/widgets.qm + + diff --git a/tool/netserver/qrc/main.rc b/tool/netserver/qrc/main.rc new file mode 100644 index 0000000..fc0d770 --- /dev/null +++ b/tool/netserver/qrc/main.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "main.ico" \ No newline at end of file diff --git a/tool/netserver/qrc/qm/qt_zh_CN.qm b/tool/netserver/qrc/qm/qt_zh_CN.qm new file mode 100644 index 0000000..623b8e3 Binary files /dev/null and b/tool/netserver/qrc/qm/qt_zh_CN.qm differ diff --git a/tool/netserver/qrc/qm/widgets.qm b/tool/netserver/qrc/qm/widgets.qm new file mode 100644 index 0000000..244bf0d Binary files /dev/null and b/tool/netserver/qrc/qm/widgets.qm differ diff --git a/tool/netserver/readme.md b/tool/netserver/readme.md new file mode 100644 index 0000000..5e85535 --- /dev/null +++ b/tool/netserver/readme.md @@ -0,0 +1,9 @@ +**场景需求** +1. 手机端或者其他端可以对设备进行回控,并查看设备各种运行状态,接收报警推送等。 +2. 同时支持在局域网、广域网、互联网访问,尤其是互联网访问。 +3. 权限控制,给定账号控制授权的设备,并自动拉取设备信息。 +4. 设备不在线要给出反馈信息提示以便分析。 +5. 每个连接都有自己的唯一编号作为标识符。 + + +查看端口号连接 netstat -aon|findstr "6907" \ No newline at end of file diff --git a/tool/nettool/api/api.pri b/tool/nettool/api/api.pri new file mode 100644 index 0000000..13454c7 --- /dev/null +++ b/tool/nettool/api/api.pri @@ -0,0 +1,23 @@ +contains(DEFINES, websocket) { +HEADERS += $$PWD/webclient.h +HEADERS += $$PWD/webserver.h + +SOURCES += $$PWD/webclient.cpp +SOURCES += $$PWD/webserver.cpp +} + +HEADERS += \ + $$PWD/appconfig.h \ + $$PWD/appdata.h \ + $$PWD/qthelper.h \ + $$PWD/qthelperdata.h \ + $$PWD/tcpclient.h \ + $$PWD/tcpserver.h + +SOURCES += \ + $$PWD/appconfig.cpp \ + $$PWD/appdata.cpp \ + $$PWD/qthelper.cpp \ + $$PWD/qthelperdata.cpp \ + $$PWD/tcpclient.cpp \ + $$PWD/tcpserver.cpp diff --git a/tool/nettool/api/appconfig.cpp b/tool/nettool/api/appconfig.cpp new file mode 100644 index 0000000..c0b8151 --- /dev/null +++ b/tool/nettool/api/appconfig.cpp @@ -0,0 +1,230 @@ +#include "appconfig.h" +#include "qthelper.h" + +QString AppConfig::ConfigFile = "config.ini"; +int AppConfig::CurrentIndex = 0; + +bool AppConfig::HexSendTcpClient = false; +bool AppConfig::HexReceiveTcpClient = false; +bool AppConfig::AsciiTcpClient = false; +bool AppConfig::DebugTcpClient = false; +bool AppConfig::AutoSendTcpClient = false; +int AppConfig::IntervalTcpClient = 1000; +QString AppConfig::TcpBindIP = "127.0.0.1"; +int AppConfig::TcpBindPort = 6001; +QString AppConfig::TcpServerIP = "127.0.0.1"; +int AppConfig::TcpServerPort = 6000; + +bool AppConfig::HexSendTcpServer = false; +bool AppConfig::HexReceiveTcpServer = false; +bool AppConfig::AsciiTcpServer = false; +bool AppConfig::DebugTcpServer = false; +bool AppConfig::AutoSendTcpServer = false; +int AppConfig::IntervalTcpServer = 1000; +QString AppConfig::TcpListenIP = "127.0.0.1"; +int AppConfig::TcpListenPort = 6000; +bool AppConfig::SelectAllTcpServer = true; + +bool AppConfig::HexSendUdpClient = false; +bool AppConfig::HexReceiveUdpClient = false; +bool AppConfig::AsciiUdpClient = false; +bool AppConfig::DebugUdpClient = false; +bool AppConfig::AutoSendUdpClient = false; +int AppConfig::IntervalUdpClient = 1000; +QString AppConfig::UdpBindIP = "127.0.0.1"; +int AppConfig::UdpBindPort = 6001; +QString AppConfig::UdpServerIP = "127.0.0.1"; +int AppConfig::UdpServerPort = 6000; + +bool AppConfig::HexSendUdpServer = false; +bool AppConfig::HexReceiveUdpServer = false; +bool AppConfig::AsciiUdpServer = false; +bool AppConfig::DebugUdpServer = false; +bool AppConfig::AutoSendUdpServer = false; +int AppConfig::IntervalUdpServer = 1000; +QString AppConfig::UdpListenIP = "127.0.0.1"; +int AppConfig::UdpListenPort = 6000; +bool AppConfig::SelectAllUdpServer = true; + +bool AppConfig::HexSendWebClient = false; +bool AppConfig::HexReceiveWebClient = false; +bool AppConfig::AsciiWebClient = true; +bool AppConfig::DebugWebClient = false; +bool AppConfig::AutoSendWebClient = false; +int AppConfig::IntervalWebClient = 1000; +QString AppConfig::WebServerIP = "ws://127.0.0.1"; +int AppConfig::WebServerPort = 6001; + +bool AppConfig::HexSendWebServer = false; +bool AppConfig::HexReceiveWebServer = false; +bool AppConfig::AsciiWebServer = true; +bool AppConfig::DebugWebServer = false; +bool AppConfig::AutoSendWebServer = false; +int AppConfig::IntervalWebServer = 1000; +QString AppConfig::WebListenIP = "127.0.0.1"; +int AppConfig::WebListenPort = 6001; +bool AppConfig::SelectAllWebServer = true; + +void AppConfig::readConfig() +{ + QSettings set(AppConfig::ConfigFile, QSettings::IniFormat); + + set.beginGroup("AppConfig"); + AppConfig::CurrentIndex = set.value("CurrentIndex").toInt(); + set.endGroup(); + + set.beginGroup("TcpClientConfig"); + AppConfig::HexSendTcpClient = set.value("HexSendTcpClient", AppConfig::HexSendTcpClient).toBool(); + AppConfig::HexReceiveTcpClient = set.value("HexReceiveTcpClient", AppConfig::HexReceiveTcpClient).toBool(); + AppConfig::AsciiTcpClient = set.value("AsciiTcpClient", AppConfig::AsciiTcpClient).toBool(); + AppConfig::DebugTcpClient = set.value("DebugTcpClient", AppConfig::DebugTcpClient).toBool(); + AppConfig::AutoSendTcpClient = set.value("AutoSendTcpClient", AppConfig::AutoSendTcpClient).toBool(); + AppConfig::IntervalTcpClient = set.value("IntervalTcpClient", AppConfig::IntervalTcpClient).toInt(); + AppConfig::TcpBindIP = set.value("TcpBindIP", AppConfig::TcpBindIP).toString(); + AppConfig::TcpBindPort = set.value("TcpBindPort", AppConfig::TcpBindPort).toInt(); + AppConfig::TcpServerIP = set.value("TcpServerIP", AppConfig::TcpServerIP).toString(); + AppConfig::TcpServerPort = set.value("TcpServerPort", AppConfig::TcpServerPort).toInt(); + set.endGroup(); + + set.beginGroup("TcpServerConfig"); + AppConfig::HexSendTcpServer = set.value("HexSendTcpServer", AppConfig::HexSendTcpServer).toBool(); + AppConfig::HexReceiveTcpServer = set.value("HexReceiveTcpServer", AppConfig::HexReceiveTcpServer).toBool(); + AppConfig::AsciiTcpServer = set.value("AsciiTcpServer", AppConfig::AsciiTcpServer).toBool(); + AppConfig::DebugTcpServer = set.value("DebugTcpServer", AppConfig::DebugTcpServer).toBool(); + AppConfig::AutoSendTcpServer = set.value("AutoSendTcpServer", AppConfig::AutoSendTcpServer).toBool(); + AppConfig::IntervalTcpServer = set.value("IntervalTcpServer", AppConfig::IntervalTcpServer).toInt(); + AppConfig::TcpListenIP = set.value("TcpListenIP", AppConfig::TcpListenIP).toString(); + AppConfig::TcpListenPort = set.value("TcpListenPort", AppConfig::TcpListenPort).toInt(); + AppConfig::SelectAllTcpServer = set.value("SelectAllTcpServer", AppConfig::SelectAllTcpServer).toBool(); + set.endGroup(); + + set.beginGroup("UdpClientConfig"); + AppConfig::HexSendUdpClient = set.value("HexSendUdpClient", AppConfig::HexSendUdpClient).toBool(); + AppConfig::HexReceiveUdpClient = set.value("HexReceiveUdpClient", AppConfig::HexReceiveUdpClient).toBool(); + AppConfig::AsciiUdpClient = set.value("AsciiUdpClient", AppConfig::AsciiUdpClient).toBool(); + AppConfig::DebugUdpClient = set.value("DebugUdpClient", AppConfig::DebugUdpClient).toBool(); + AppConfig::AutoSendUdpClient = set.value("AutoSendUdpClient", AppConfig::AutoSendUdpClient).toBool(); + AppConfig::IntervalUdpClient = set.value("IntervalUdpClient", AppConfig::IntervalUdpClient).toInt(); + AppConfig::UdpBindIP = set.value("UdpBindIP", AppConfig::UdpBindIP).toString(); + AppConfig::UdpBindPort = set.value("UdpBindPort", AppConfig::UdpBindPort).toInt(); + AppConfig::UdpServerIP = set.value("UdpServerIP", AppConfig::UdpServerIP).toString(); + AppConfig::UdpServerPort = set.value("UdpServerPort", AppConfig::UdpServerPort).toInt(); + set.endGroup(); + + set.beginGroup("UdpServerConfig"); + AppConfig::HexSendUdpServer = set.value("HexSendUdpServer", AppConfig::HexSendUdpServer).toBool(); + AppConfig::HexReceiveUdpServer = set.value("HexReceiveUdpServer", AppConfig::HexReceiveUdpServer).toBool(); + AppConfig::AsciiUdpServer = set.value("AsciiUdpServer", AppConfig::AsciiUdpServer).toBool(); + AppConfig::DebugUdpServer = set.value("DebugUdpServer", AppConfig::DebugUdpServer).toBool(); + AppConfig::AutoSendUdpServer = set.value("AutoSendUdpServer", AppConfig::AutoSendUdpServer).toBool(); + AppConfig::IntervalUdpServer = set.value("IntervalUdpServer", AppConfig::IntervalUdpServer).toInt(); + AppConfig::UdpListenIP = set.value("UdpListenIP", AppConfig::UdpListenIP).toString(); + AppConfig::UdpListenPort = set.value("UdpListenPort", AppConfig::UdpListenPort).toInt(); + AppConfig::SelectAllUdpServer = set.value("SelectAllUdpServer", AppConfig::SelectAllUdpServer).toBool(); + set.endGroup(); + + set.beginGroup("WebClientConfig"); + AppConfig::HexSendWebClient = set.value("HexSendWebClient", AppConfig::HexSendWebClient).toBool(); + AppConfig::HexReceiveWebClient = set.value("HexReceiveWebClient", AppConfig::HexReceiveWebClient).toBool(); + AppConfig::AsciiWebClient = set.value("AsciiWebClient", AppConfig::AsciiWebClient).toBool(); + AppConfig::DebugWebClient = set.value("DebugWebClient", AppConfig::DebugWebClient).toBool(); + AppConfig::AutoSendWebClient = set.value("AutoSendWebClient", AppConfig::AutoSendWebClient).toBool(); + AppConfig::IntervalWebClient = set.value("IntervalWebClient", AppConfig::IntervalWebClient).toInt(); + AppConfig::WebServerIP = set.value("WebServerIP", AppConfig::WebServerIP).toString(); + AppConfig::WebServerPort = set.value("WebServerPort", AppConfig::WebServerPort).toInt(); + set.endGroup(); + + set.beginGroup("WebServerConfig"); + AppConfig::HexSendWebServer = set.value("HexSendWebServer", AppConfig::HexSendWebServer).toBool(); + AppConfig::HexReceiveWebServer = set.value("HexReceiveWebServer", AppConfig::HexReceiveWebServer).toBool(); + AppConfig::AsciiWebServer = set.value("AsciiWebServer", AppConfig::AsciiWebServer).toBool(); + AppConfig::DebugWebServer = set.value("DebugWebServer", AppConfig::DebugWebServer).toBool(); + AppConfig::AutoSendWebServer = set.value("AutoSendWebServer", AppConfig::AutoSendWebServer).toBool(); + AppConfig::IntervalWebServer = set.value("IntervalWebServer", AppConfig::IntervalWebServer).toInt(); + AppConfig::WebListenIP = set.value("WebListenIP", AppConfig::WebListenIP).toString(); + AppConfig::WebListenPort = set.value("WebListenPort", AppConfig::WebListenPort).toInt(); + AppConfig::SelectAllWebServer = set.value("SelectAllWebServer", AppConfig::SelectAllWebServer).toBool(); + set.endGroup(); + + //配置文件不存在或者不全则重新生成 + if (!QtHelper::checkIniFile(AppConfig::ConfigFile)) { + writeConfig(); + return; + } +} + +void AppConfig::writeConfig() +{ + QSettings set(AppConfig::ConfigFile, QSettings::IniFormat); + + set.beginGroup("AppConfig"); + set.setValue("CurrentIndex", AppConfig::CurrentIndex); + set.endGroup(); + + set.beginGroup("TcpClientConfig"); + set.setValue("HexSendTcpClient", AppConfig::HexSendTcpClient); + set.setValue("HexReceiveTcpClient", AppConfig::HexReceiveTcpClient); + set.setValue("DebugTcpClient", AppConfig::DebugTcpClient); + set.setValue("AutoSendTcpClient", AppConfig::AutoSendTcpClient); + set.setValue("IntervalTcpClient", AppConfig::IntervalTcpClient); + set.setValue("TcpBindIP", AppConfig::TcpBindIP); + set.setValue("TcpBindPort", AppConfig::TcpBindPort); + set.setValue("TcpServerIP", AppConfig::TcpServerIP); + set.setValue("TcpServerPort", AppConfig::TcpServerPort); + set.endGroup(); + + set.beginGroup("TcpServerConfig"); + set.setValue("HexSendTcpServer", AppConfig::HexSendTcpServer); + set.setValue("HexReceiveTcpServer", AppConfig::HexReceiveTcpServer); + set.setValue("DebugTcpServer", AppConfig::DebugTcpServer); + set.setValue("AutoSendTcpServer", AppConfig::AutoSendTcpServer); + set.setValue("IntervalTcpServer", AppConfig::IntervalTcpServer); + set.setValue("TcpListenIP", AppConfig::TcpListenIP); + set.setValue("TcpListenPort", AppConfig::TcpListenPort); + set.setValue("SelectAllTcpServer", AppConfig::SelectAllTcpServer); + set.endGroup(); + + set.beginGroup("UdpClientConfig"); + set.setValue("HexSendUdpClient", AppConfig::HexSendUdpClient); + set.setValue("HexReceiveUdpClient", AppConfig::HexReceiveUdpClient); + set.setValue("DebugUdpClient", AppConfig::DebugUdpClient); + set.setValue("AutoSendUdpClient", AppConfig::AutoSendUdpClient); + set.setValue("IntervalUdpClient", AppConfig::IntervalUdpClient); + set.setValue("UdpBindIP", AppConfig::UdpBindIP); + set.setValue("UdpBindPort", AppConfig::UdpBindPort); + set.setValue("UdpServerIP", AppConfig::UdpServerIP); + set.setValue("UdpServerPort", AppConfig::UdpServerPort); + set.endGroup(); + + set.beginGroup("UdpServerConfig"); + set.setValue("HexSendUdpServer", AppConfig::HexSendUdpServer); + set.setValue("HexReceiveUdpServer", AppConfig::HexReceiveUdpServer); + set.setValue("DebugUdpServer", AppConfig::DebugUdpServer); + set.setValue("AutoSendUdpServer", AppConfig::AutoSendUdpServer); + set.setValue("IntervalUdpServer", AppConfig::IntervalUdpServer); + set.setValue("UdpListenIP", AppConfig::UdpListenIP); + set.setValue("UdpListenPort", AppConfig::UdpListenPort); + set.setValue("SelectAllUdpServer", AppConfig::SelectAllUdpServer); + set.endGroup(); + + set.beginGroup("WebClientConfig"); + set.setValue("HexSendWebClient", AppConfig::HexSendWebClient); + set.setValue("HexReceiveWebClient", AppConfig::HexReceiveWebClient); + set.setValue("DebugWebClient", AppConfig::DebugWebClient); + set.setValue("AutoSendWebClient", AppConfig::AutoSendWebClient); + set.setValue("IntervalWebClient", AppConfig::IntervalWebClient); + set.setValue("WebServerIP", AppConfig::WebServerIP); + set.setValue("WebServerPort", AppConfig::WebServerPort); + set.endGroup(); + + set.beginGroup("WebServerConfig"); + set.setValue("HexSendWebServer", AppConfig::HexSendWebServer); + set.setValue("HexReceiveWebServer", AppConfig::HexReceiveWebServer); + set.setValue("DebugWebServer", AppConfig::DebugWebServer); + set.setValue("AutoSendWebServer", AppConfig::AutoSendWebServer); + set.setValue("IntervalWebServer", AppConfig::IntervalWebServer); + set.setValue("WebListenIP", AppConfig::WebListenIP); + set.setValue("WebListenPort", AppConfig::WebListenPort); + set.setValue("SelectAllWebServer", AppConfig::SelectAllWebServer); + set.endGroup(); +} diff --git a/tool/nettool/api/appconfig.h b/tool/nettool/api/appconfig.h new file mode 100644 index 0000000..663c205 --- /dev/null +++ b/tool/nettool/api/appconfig.h @@ -0,0 +1,84 @@ +#ifndef APPCONFIG_H +#define APPCONFIG_H + +#include "head.h" + +class AppConfig +{ +public: + static QString ConfigFile; //配置文件路径 + static int CurrentIndex; //当前索引 + + //TCP客户端配置参数 + static bool HexSendTcpClient; //16进制发送 + static bool HexReceiveTcpClient; //16进制接收 + static bool AsciiTcpClient; //ASCII模式 + static bool DebugTcpClient; //启用数据调试 + static bool AutoSendTcpClient; //自动发送数据 + static int IntervalTcpClient; //发送数据间隔 + static QString TcpBindIP; //绑定地址 + static int TcpBindPort; //绑定端口 + static QString TcpServerIP; //服务器地址 + static int TcpServerPort; //服务器端口 + + //TCP服务器配置参数 + static bool HexSendTcpServer; //16进制发送 + static bool HexReceiveTcpServer; //16进制接收 + static bool AsciiTcpServer; //ASCII模式 + static bool DebugTcpServer; //启用数据调试 + static bool AutoSendTcpServer; //自动发送数据 + static int IntervalTcpServer; //发送数据间隔 + static QString TcpListenIP; //监听地址 + static int TcpListenPort; //监听端口 + static bool SelectAllTcpServer; //选中所有 + + //UDP客户端配置参数 + static bool HexSendUdpClient; //16进制发送 + static bool HexReceiveUdpClient; //16进制接收 + static bool AsciiUdpClient; //ASCII模式 + static bool DebugUdpClient; //启用数据调试 + static bool AutoSendUdpClient; //自动发送数据 + static int IntervalUdpClient; //发送数据间隔 + static QString UdpBindIP; //绑定地址 + static int UdpBindPort; //绑定端口 + static QString UdpServerIP; //服务器地址 + static int UdpServerPort; //服务器端口 + + //UDP服务器配置参数 + static bool HexSendUdpServer; //16进制发送 + static bool HexReceiveUdpServer; //16进制接收 + static bool AsciiUdpServer; //ASCII模式 + static bool DebugUdpServer; //启用数据调试 + static bool AutoSendUdpServer; //自动发送数据 + static int IntervalUdpServer; //发送数据间隔 + static QString UdpListenIP; //监听地址 + static int UdpListenPort; //监听端口 + static bool SelectAllUdpServer; //选中所有 + + //WEB客户端配置参数 + static bool HexSendWebClient; //16进制发送 + static bool HexReceiveWebClient; //16进制接收 + static bool AsciiWebClient; //ASCII模式 + static bool DebugWebClient; //启用数据调试 + static bool AutoSendWebClient; //自动发送数据 + static int IntervalWebClient; //发送数据间隔 + static QString WebServerIP; //服务器地址 + static int WebServerPort; //服务器端口 + + //WEB服务器配置参数 + static bool HexSendWebServer; //16进制发送 + static bool HexReceiveWebServer; //16进制接收 + static bool AsciiWebServer; //ASCII模式 + static bool DebugWebServer; //启用数据调试 + static bool AutoSendWebServer; //自动发送数据 + static int IntervalWebServer; //发送数据间隔 + static QString WebListenIP; //监听地址 + static int WebListenPort; //监听端口 + static bool SelectAllWebServer; //选中所有 + + //读写配置参数 + static void readConfig(); //读取配置参数 + static void writeConfig(); //写入配置参数 +}; + +#endif // APPCONFIG_H diff --git a/tool/nettool/api/appdata.cpp b/tool/nettool/api/appdata.cpp new file mode 100644 index 0000000..5376711 --- /dev/null +++ b/tool/nettool/api/appdata.cpp @@ -0,0 +1,122 @@ +#include "appdata.h" +#include "qthelper.h" + +QStringList AppData::Intervals = QStringList(); +QStringList AppData::Datas = QStringList(); +QStringList AppData::Keys = QStringList(); +QStringList AppData::Values = QStringList(); + +QString AppData::SendFileName = "send.txt"; +void AppData::readSendData() +{ + //读取发送数据列表 + AppData::Datas.clear(); + QString fileName = QString("%1/%2").arg(QtHelper::appPath()).arg(AppData::SendFileName); + QFile file(fileName); + if (file.size() > 0 && file.open(QFile::ReadOnly | QIODevice::Text)) { + while (!file.atEnd()) { + QString line = file.readLine(); + line = line.trimmed(); + line = line.replace("\r", ""); + line = line.replace("\n", ""); + if (!line.isEmpty()) { + AppData::Datas.append(line); + } + } + + file.close(); + } + + //没有的时候主动添加点免得太空 + if (AppData::Datas.count() == 0) { + AppData::Datas << "16 FF 01 01 E0 E1" << "16 FF 01 01 E1 E2"; + } +} + +QString AppData::DeviceFileName = "device.txt"; +void AppData::readDeviceData() +{ + //读取转发数据列表 + AppData::Keys.clear(); + AppData::Values.clear(); + QString fileName = QString("%1/%2").arg(QtHelper::appPath()).arg(AppData::DeviceFileName); + QFile file(fileName); + if (file.size() > 0 && file.open(QFile::ReadOnly | QIODevice::Text)) { + while (!file.atEnd()) { + QString line = file.readLine(); + line = line.trimmed(); + line = line.replace("\r", ""); + line = line.replace("\n", ""); + if (!line.isEmpty()) { + QStringList list = line.split(";"); + QString key = list.at(0); + QString value; + for (int i = 1; i < list.count(); i++) { + value += QString("%1;").arg(list.at(i)); + } + + //去掉末尾分号 + value = value.mid(0, value.length() - 1); + AppData::Keys.append(key); + AppData::Values.append(value); + } + } + + file.close(); + } +} + +void AppData::saveData(const QString &data) +{ + if (data.length() <= 0) { + return; + } + + QString fileName = QString("%1/%2.txt").arg(QtHelper::appPath()).arg(STRDATETIME); + QFile file(fileName); + if (file.open(QFile::WriteOnly | QFile::Text)) { + file.write(data.toUtf8()); + file.close(); + } +} + +void AppData::loadIP(QComboBox *cbox) +{ + //获取本机所有IP + static QStringList ips; + if (ips.count() == 0) { +#ifdef Q_OS_WASM + ips << "127.0.0.1"; +#else + QList netInterfaces = QNetworkInterface::allInterfaces(); + foreach (const QNetworkInterface &netInterface, netInterfaces) { + //移除虚拟机和抓包工具的虚拟网卡 + QString humanReadableName = netInterface.humanReadableName().toLower(); + if (humanReadableName.startsWith("vmware network adapter") || humanReadableName.startsWith("npcap loopback adapter")) { + continue; + } + + //过滤当前网络接口 + bool flag = (netInterface.flags() == (QNetworkInterface::IsUp | QNetworkInterface::IsRunning | QNetworkInterface::CanBroadcast | QNetworkInterface::CanMulticast)); + if (flag) { + QList addrs = netInterface.addressEntries(); + foreach (QNetworkAddressEntry addr, addrs) { + //只取出IPV4的地址 + if (addr.ip().protocol() == QAbstractSocket::IPv4Protocol) { + QString ip4 = addr.ip().toString(); + if (ip4 != "127.0.0.1") { + ips << ip4; + } + } + } + } + } +#endif + } + + cbox->clear(); + cbox->addItems(ips); + if (!ips.contains("127.0.0.1")) { + cbox->addItem("127.0.0.1"); + } +} diff --git a/tool/nettool/api/appdata.h b/tool/nettool/api/appdata.h new file mode 100644 index 0000000..13091c7 --- /dev/null +++ b/tool/nettool/api/appdata.h @@ -0,0 +1,30 @@ +#ifndef APPDATA_H +#define APPDATA_H + +#include "head.h" + +class AppData +{ +public: + //全局变量 + static QStringList Intervals; + static QStringList Datas; + static QStringList Keys; + static QStringList Values; + + //读取发送数据列表 + static QString SendFileName; + static void readSendData(); + + //读取转发数据列表 + static QString DeviceFileName; + static void readDeviceData(); + + //保存数据到文件 + static void saveData(const QString &data); + + //添加网卡IP地址到下拉框 + static void loadIP(QComboBox *cbox); +}; + +#endif // APPDATA_H diff --git a/tool/nettool/api/qthelper.cpp b/tool/nettool/api/qthelper.cpp new file mode 100644 index 0000000..1911055 --- /dev/null +++ b/tool/nettool/api/qthelper.cpp @@ -0,0 +1,1234 @@ +#include "qthelper.h" +#include "qnetworkinterface.h" +#include "qnetworkproxy.h" + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +QList QtHelper::getScreenRects(bool available) +{ + QList rects; +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + int screenCount = qApp->screens().count(); + QList screens = qApp->screens(); + for (int i = 0; i < screenCount; ++i) { + QScreen *screen = screens.at(i); + rects << (available ? screen->availableGeometry() : screen->geometry()); + } +#else + int screenCount = qApp->desktop()->screenCount(); + QDesktopWidget *desk = qApp->desktop(); + for (int i = 0; i < screenCount; ++i) { + rects << (available ? desk->availableGeometry(i) : desk->screenGeometry(i)); + } +#endif + return rects; +} + +int QtHelper::getScreenIndex() +{ + //需要对多个屏幕进行处理 + int screenIndex = 0; + QList rects = getScreenRects(false); + int count = rects.count(); + for (int i = 0; i < count; ++i) { + //找到当前鼠标所在屏幕 + QPoint pos = QCursor::pos(); + if (rects.at(i).contains(pos)) { + screenIndex = i; + break; + } + } + + return screenIndex; +} + +QRect QtHelper::getScreenRect(bool available) +{ + int screenIndex = getScreenIndex(); + QList rects = getScreenRects(available); + return rects.at(screenIndex); +} + +qreal QtHelper::getScreenRatio(bool devicePixel) +{ + qreal ratio = 1.0; + int screenIndex = getScreenIndex(); +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + QScreen *screen = qApp->screens().at(screenIndex); + if (devicePixel) { + //需要开启 AA_EnableHighDpiScaling 属性才能正常获取 + ratio = screen->devicePixelRatio() * 100; + } else { + ratio = screen->logicalDotsPerInch(); + } +#else + //Qt4不能动态识别缩放更改后的值 + ratio = qApp->desktop()->screen(screenIndex)->logicalDpiX(); +#endif + return ratio / 96; +} + +QRect QtHelper::checkCenterRect(QRect &rect, bool available) +{ + QRect deskRect = QtHelper::getScreenRect(available); + int formWidth = rect.width(); + int formHeight = rect.height(); + int deskWidth = deskRect.width(); + int deskHeight = deskRect.height(); + int formX = deskWidth / 2 - formWidth / 2 + deskRect.x(); + int formY = deskHeight / 2 - formHeight / 2; + rect = QRect(formX, formY, formWidth, formHeight); + return deskRect; +} + +int QtHelper::deskWidth() +{ + return getScreenRect().width(); +} + +int QtHelper::deskHeight() +{ + return getScreenRect().height(); +} + +QSize QtHelper::deskSize() +{ + return getScreenRect().size(); +} + +QWidget *QtHelper::centerBaseForm = 0; +void QtHelper::setFormInCenter(QWidget *form) +{ + int formWidth = form->width(); + int formHeight = form->height(); + + //如果=0表示采用系统桌面屏幕为参照 + QRect rect; + if (centerBaseForm == 0) { + rect = getScreenRect(); + } else { + rect = centerBaseForm->geometry(); + } + + int deskWidth = rect.width(); + int deskHeight = rect.height(); + QPoint movePoint(deskWidth / 2 - formWidth / 2 + rect.x(), deskHeight / 2 - formHeight / 2 + rect.y()); + form->move(movePoint); +} + +void QtHelper::showForm(QWidget *form) +{ + setFormInCenter(form); + form->show(); + + //判断宽高是否超过了屏幕分辨率,超过了则最大化显示 + //qDebug() << TIMEMS << form->size() << deskSize(); + if (form->width() + 20 > deskWidth() || form->height() + 50 > deskHeight()) { + QMetaObject::invokeMethod(form, "showMaximized", Qt::QueuedConnection); + } +} + +QString QtHelper::appName() +{ + //没有必要每次都获取,只有当变量为空时才去获取一次 + static QString name; + if (name.isEmpty()) { + name = qApp->applicationFilePath(); + //下面的方法主要为了过滤安卓的路径 lib程序名_armeabi-v7a/lib程序名_arm64-v8a + QStringList list = name.split("/"); + name = list.at(list.count() - 1).split(".").at(0); + name.replace("_armeabi-v7a", ""); + name.replace("_arm64-v8a", ""); + } + + return name; +} + +QString QtHelper::appPath() +{ + static QString path; + if (path.isEmpty()) { +#ifdef Q_OS_ANDROID + //默认安卓根目录 + path = "/storage/emulated/0"; + //带上程序名称作为目录 前面加个0方便排序 + path = path + "/0" + appName(); +#else + path = qApp->applicationDirPath(); +#endif + } + + return path; +} + +void QtHelper::getCurrentInfo(char *argv[], QString &path, QString &name) +{ + //必须用fromLocal8Bit保证中文路径正常 + QString argv0 = QString::fromLocal8Bit(argv[0]); + QFileInfo file(argv0); + path = file.path(); + name = file.baseName(); +} + +QString QtHelper::getIniValue(const QString &fileName, const QString &key) +{ + QString value; + QFile file(fileName); + if (file.open(QFile::ReadOnly | QFile::Text)) { + while (!file.atEnd()) { + QString line = file.readLine(); + if (line.startsWith(key)) { + line = line.replace("\n", ""); + line = line.trimmed(); + value = line.split("=").last(); + break; + } + } + } + return value; +} + +QString QtHelper::getIniValue(char *argv[], const QString &key, const QString &dir) +{ + QString path, name; + QtHelper::getCurrentInfo(argv, path, name); + QString fileName = QString("%1/%2%3.ini").arg(path).arg(dir).arg(name); + return getIniValue(fileName, key); +} + +QStringList QtHelper::getLocalIPs() +{ + static QStringList ips; + if (ips.count() == 0) { +#ifdef Q_OS_WASM + ips << "127.0.0.1"; +#else + QList netInterfaces = QNetworkInterface::allInterfaces(); + foreach (QNetworkInterface netInterface, netInterfaces) { + //移除虚拟机和抓包工具的虚拟网卡 + QString humanReadableName = netInterface.humanReadableName().toLower(); + if (humanReadableName.startsWith("vmware network adapter") || humanReadableName.startsWith("npcap loopback adapter")) { + continue; + } + + //过滤当前网络接口 + bool flag = (netInterface.flags() == (QNetworkInterface::IsUp | QNetworkInterface::IsRunning | QNetworkInterface::CanBroadcast | QNetworkInterface::CanMulticast)); + if (!flag) { + continue; + } + + QList addrs = netInterface.addressEntries(); + foreach (QNetworkAddressEntry addr, addrs) { + //只取出IPV4的地址 + if (addr.ip().protocol() != QAbstractSocket::IPv4Protocol) { + continue; + } + + QString ip4 = addr.ip().toString(); + if (ip4 != "127.0.0.1") { + ips << ip4; + } + } + } +#endif + } + + return ips; +} + +QList QtHelper::colors = QList(); +QList QtHelper::getColorList() +{ + //备用颜色集合 可以自行添加 + if (colors.count() == 0) { + colors << QColor(0, 176, 180) << QColor(0, 113, 193) << QColor(255, 192, 0); + colors << QColor(72, 103, 149) << QColor(185, 87, 86) << QColor(0, 177, 125); + colors << QColor(214, 77, 84) << QColor(71, 164, 233) << QColor(34, 163, 169); + colors << QColor(59, 123, 156) << QColor(162, 121, 197) << QColor(72, 202, 245); + colors << QColor(0, 150, 121) << QColor(111, 9, 176) << QColor(250, 170, 20); + } + + return colors; +} + +QStringList QtHelper::getColorNames() +{ + QList colors = getColorList(); + QStringList colorNames; + foreach (QColor color, colors) { + colorNames << color.name(); + } + return colorNames; +} + +QColor QtHelper::getRandColor() +{ + QList colors = getColorList(); + int index = getRandValue(0, colors.count(), true); + return colors.at(index); +} + +void QtHelper::initRand() +{ + //初始化随机数种子 + QTime t = QTime::currentTime(); + srand(t.msec() + t.second() * 1000); +} + +float QtHelper::getRandFloat(float min, float max) +{ + double diff = fabs(max - min); + double value = (double)(rand() % 100) / 100; + value = min + value * diff; + return value; +} + +double QtHelper::getRandValue(int min, int max, bool contansMin, bool contansMax) +{ + int value; +#if (QT_VERSION <= QT_VERSION_CHECK(5,10,0)) + //通用公式 a是起始值,n是整数的范围 + //int value = a + rand() % n; + if (contansMin) { + if (contansMax) { + value = min + 0 + (rand() % (max - min + 1)); + } else { + value = min + 0 + (rand() % (max - min + 0)); + } + } else { + if (contansMax) { + value = min + 1 + (rand() % (max - min + 0)); + } else { + value = min + 1 + (rand() % (max - min - 1)); + } + } +#else + if (contansMin) { + if (contansMax) { + value = QRandomGenerator::global()->bounded(min + 0, max + 1); + } else { + value = QRandomGenerator::global()->bounded(min + 0, max + 0); + } + } else { + if (contansMax) { + value = QRandomGenerator::global()->bounded(min + 1, max + 1); + } else { + value = QRandomGenerator::global()->bounded(min + 1, max + 0); + } + } +#endif + return value; +} + +QStringList QtHelper::getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat) +{ + //随机生成点坐标 + QStringList points; + for (int i = 0; i < count; ++i) { + //0.00881415 0.000442928 +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) + float lngx = QRandomGenerator::global()->bounded(dotLng); + float latx = QRandomGenerator::global()->bounded(dotLat); +#else + float lngx = getRandFloat(dotLng / 10, dotLng); + float latx = getRandFloat(dotLat / 10, dotLat); +#endif + //需要先用精度转换成字符串 + QString lng2 = QString::number(mainLng + lngx, 'f', 8); + QString lat2 = QString::number(mainLat + latx, 'f', 8); + QString point = QString("%1,%2").arg(lng2).arg(lat2); + points << point; + } + + return points; +} + +int QtHelper::getRangeValue(int oldMin, int oldMax, int oldValue, int newMin, int newMax) +{ + return (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin; +} + +QString QtHelper::getUuid() +{ + QString uuid = QUuid::createUuid().toString(); + uuid.replace("{", ""); + uuid.replace("}", ""); + return uuid; +} + +void QtHelper::checkPath(const QString &dirName) +{ + //相对路径需要补全完整路径 + QString path = dirName; + if (path.startsWith("./")) { + path.replace(".", ""); + path = QtHelper::appPath() + path; + } else if (!path.startsWith("/") && !path.contains(":/")) { + path = QtHelper::appPath() + "/" + path; + } + + //目录不存在则新建 + QDir dir(path); + if (!dir.exists()) { + dir.mkpath(path); + } +} + +void QtHelper::sleep(int msec, bool exec) +{ + if (msec <= 0) { + return; + } + + if (exec) { +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //阻塞方式延时(如果在主线程会卡住主界面) + QThread::msleep(msec); +#else + //非阻塞方式延时(不会卡住主界面/据说可能有问题) + QTime endTime = QTime::currentTime().addMSecs(msec); + while (QTime::currentTime() < endTime) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } +#endif + } else { + //非阻塞方式延时(现在很多人推荐的方法) + QEventLoop loop; + QTimer::singleShot(msec, &loop, SLOT(quit())); + loop.exec(); + } +} + +void QtHelper::checkRun() +{ +#ifdef Q_OS_WIN + //延时1秒钟,等待程序释放完毕 + QtHelper::sleep(1000); + //创建共享内存,判断是否已经运行程序 + static QSharedMemory mem(QtHelper::appName()); + if (!mem.create(1)) { + QtHelper::showMessageBoxError("程序已运行, 软件将自动关闭!", 5, true); + exit(0); + } +#endif +} + +void QtHelper::setStyle() +{ + //打印下所有内置风格的名字 + qDebug() << TIMEMS << "QStyleFactory::keys" << QStyleFactory::keys(); + //设置内置风格 +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + qApp->setStyle("Fusion"); +#else + qApp->setStyle("Cleanlooks"); +#endif + + //设置指定颜色 + QPalette palette; + palette.setBrush(QPalette::Window, QColor("#F0F0F0")); + qApp->setPalette(palette); +} + +QFont QtHelper::addFont(const QString &fontFile, const QString &fontName) +{ + //判断图形字体是否存在,不存在则加入 + QFontDatabase fontDb; + if (!fontDb.families().contains(fontName)) { + int fontId = fontDb.addApplicationFont(fontFile); + QStringList listName = fontDb.applicationFontFamilies(fontId); + if (listName.count() == 0) { + qDebug() << QString("load %1 error").arg(fontName); + } + } + + //再次判断是否包含字体名称防止加载失败 + QFont font; + if (fontDb.families().contains(fontName)) { + font = QFont(fontName); +#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0)) + font.setHintingPreference(QFont::PreferNoHinting); +#endif + } + + return font; +} + +void QtHelper::setFont(int fontSize) +{ + //安卓套件在有些手机上默认字体不好看需要主动设置字体 + //网页套件需要主动加载中文字体才能正常显示中文 +#if (defined Q_OS_ANDROID) || (defined Q_OS_WASM) + QString fontFile = ":/font/DroidSansFallback.ttf"; + QString fontName = "Droid Sans Fallback"; + qApp->setFont(addFont(fontFile, fontName)); + return; +#endif + +#ifdef __arm__ + fontSize = 25; +#endif + + QFont font; + font.setFamily("MicroSoft Yahei"); + font.setPixelSize(fontSize); + qApp->setFont(font); +} + +void QtHelper::setCode(bool utf8) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //如果想要控制台打印信息中文正常就注释掉这个设置 + if (utf8) { + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); + } +#else +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#endif +} + +void QtHelper::setTranslator(const QString &qmFile) +{ + //过滤下不存在的就不用设置了 + if (!QFile(qmFile).exists()) { + return; + } + + QTranslator *translator = new QTranslator(qApp); + if (translator->load(qmFile)) { + qApp->installTranslator(translator); + } +} + +#ifdef Q_OS_ANDROID +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) +#include +#else +//Qt6中将相关类移到了core模块而且名字变了 +#include +#endif +#endif + +bool QtHelper::checkPermission(const QString &permission) +{ +#ifdef Q_OS_ANDROID +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0) && QT_VERSION < QT_VERSION_CHECK(6,0,0)) + QtAndroid::PermissionResult result = QtAndroid::checkPermission(permission); + if (result == QtAndroid::PermissionResult::Denied) { + QtAndroid::requestPermissionsSync(QStringList() << permission); + result = QtAndroid::checkPermission(permission); + if (result == QtAndroid::PermissionResult::Denied) { + return false; + } + } +#else + QFuture result = QtAndroidPrivate::requestPermission(permission); + if (result.resultAt(0) == QtAndroidPrivate::PermissionResult::Denied) { + return false; + } +#endif +#endif + return true; +} + +void QtHelper::initAndroidPermission() +{ + //可以把所有要动态申请的权限都写在这里 + checkPermission("android.permission.CALL_PHONE"); + checkPermission("android.permission.SEND_SMS"); + checkPermission("android.permission.CAMERA"); + checkPermission("android.permission.READ_EXTERNAL_STORAGE"); + checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); + + checkPermission("android.permission.ACCESS_COARSE_LOCATION"); + checkPermission("android.permission.BLUETOOTH"); + checkPermission("android.permission.BLUETOOTH_SCAN"); + checkPermission("android.permission.BLUETOOTH_CONNECT"); + checkPermission("android.permission.BLUETOOTH_ADVERTISE"); +} + +void QtHelper::initAll(bool utf8, bool style, int fontSize) +{ + //初始化安卓权限 + QtHelper::initAndroidPermission(); + //初始化随机数种子 + QtHelper::initRand(); + //设置编码 + QtHelper::setCode(utf8); + //设置字体 + QtHelper::setFont(fontSize); + //设置样式风格 + if (style) { + QtHelper::setStyle(); + } + + //设置翻译文件支持多个 + QtHelper::setTranslator(":/qm/widgets.qm"); + QtHelper::setTranslator(":/qm/qt_zh_CN.qm"); + QtHelper::setTranslator(":/qm/designer_zh_CN.qm"); + + //设置不使用本地系统环境代理配置 + QNetworkProxyFactory::setUseSystemConfiguration(false); + //设置当前目录为程序可执行文件所在目录 + QDir::setCurrent(QtHelper::appPath()); + //Qt4中默认没有程序名称需要主动设置 +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) + qApp->setApplicationName(QtHelper::appName()); +#endif +} + +void QtHelper::initMain(bool desktopSettingsAware, bool use96Dpi, bool logCritical) +{ +#ifdef Q_OS_WIN + //Qt6.5开始默认是ffmpeg后端但是不成熟需要换成系统的 + qputenv("QT_MEDIA_BACKEND", "windows"); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //设置是否应用操作系统设置比如字体 + QApplication::setDesktopSettingsAware(desktopSettingsAware); +#endif + + bool highDpi = !use96Dpi; +#ifdef Q_OS_ANDROID + highDpi = true; +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,6,0)) + //开启高分屏缩放支持 + if (highDpi) { + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + } +#endif + +#ifdef Q_OS_WIN + if (use96Dpi) { + //Qt6中AA_Use96Dpi没效果必须下面方式设置强制指定缩放DPI + qputenv("QT_FONT_DPI", "96"); +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //不应用任何缩放 + QApplication::setAttribute(Qt::AA_Use96Dpi); +#endif + } +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + //高分屏缩放策略 + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //下面这行表示不打印Qt内部类的警告提示信息 + if (!logCritical) { + QLoggingCategory::setFilterRules("*.critical=false\n*.warning=false"); + } +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0)) + //设置opengl共享上下文 + QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); +#endif +} + +void QtHelper::initOpenGL(quint8 type, bool checkCardEnable, bool checkVirtualSystem) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0)) + //设置opengl模式 AA_UseDesktopOpenGL(默认) AA_UseOpenGLES AA_UseSoftwareOpenGL + //在一些很旧的设备上或者对opengl支持很低的设备上需要使用AA_UseOpenGLES表示禁用硬件加速 + //如果开启的是AA_UseOpenGLES则无法使用硬件加速比如ffmpeg的dxva2 + if (type == 1) { + QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); + } else if (type == 2) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } else if (type == 3) { + QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); + } + + //检测显卡是否被禁用 + if (checkCardEnable && !isVideoCardEnable()) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } + + //检测是否是虚拟机系统 + if (checkVirtualSystem && isVirtualSystem()) { + QApplication::setAttribute(Qt::AA_UseOpenGLES); + } +#endif +} + +QString QtHelper::doCmd(const QString &program, const QStringList &arguments, int timeout) +{ + QString result; +#ifndef Q_OS_WASM + QProcess p; + p.start(program, arguments); + p.waitForFinished(timeout); + result = QString::fromLocal8Bit(p.readAllStandardOutput()); + result.replace("\r", ""); + result.replace("\n", ""); + result = result.simplified(); + result = result.trimmed(); +#endif + return result; +} + +bool QtHelper::isVideoCardEnable() +{ + QString result; + bool videoCardEnable = true; + +#if defined(Q_OS_WIN) + QStringList args; + //wmic path win32_VideoController get name,Status + args << "path" << "win32_VideoController" << "get" << "name,Status"; + result = doCmd("wmic", args); +#endif + + //Name Status Intel(R) UHD Graphics 630 OK + //Name Status Intel(R) UHD Graphics 630 Error + if (result.contains("Error")) { + videoCardEnable = false; + } + + return videoCardEnable; +} + +bool QtHelper::isVirtualSystem() +{ + QString result; + bool virtualSystem = false; + +#if defined(Q_OS_WIN) + QStringList args; + //wmic computersystem get Model + args << "computersystem" << "get" << "Model"; + result = doCmd("wmic", args); +#elif defined(Q_OS_LINUX) + QStringList args; + //还有个命令需要root权限运行 dmidecode -s system-product-name 执行结果和win一样 + result = doCmd("lscpu", args); +#endif + + //Model MS-7C00 + //Model VMWare Virtual Platform + //Model VirtualBox Virtual Platform + //Model Alibaba Cloud ECS + if (result.contains("VMware") || result.contains("VirtualBox") || result.contains("Alibaba")) { + virtualSystem = true; + } + + return virtualSystem; +} + +QVector QtHelper::msgTypes = QVector() << 0 << 1 << 2 << 3 << 4; +QVector QtHelper::msgKeys = QVector() << QString::fromUtf8("发送") << QString::fromUtf8("接收") << QString::fromUtf8("解析") << QString::fromUtf8("错误") << QString::fromUtf8("提示"); +QVector QtHelper::msgColors = QVector() << QColor("#3BA372") << QColor("#EE6668") << QColor("#9861B4") << QColor("#FA8359") << QColor("#22A3A9"); +QString QtHelper::appendMsg(QTextEdit *textEdit, int type, const QString &data, int maxCount, int ¤tCount, bool clear, bool pause) +{ + if (clear) { + textEdit->clear(); + currentCount = 0; + return QString(); + } + + if (pause) { + return QString(); + } + + if (currentCount >= maxCount) { + textEdit->clear(); + currentCount = 0; + } + + //不同类型不同颜色显示 + QString strType; + int index = msgTypes.indexOf(type); + if (index >= 0) { + strType = msgKeys.at(index); + textEdit->setTextColor(msgColors.at(index)); + } + + //过滤回车换行符 + QString strData = data; + strData.replace("\r", ""); + strData.replace("\n", ""); + strData = QString("时间[%1] %2: %3").arg(TIMEMS).arg(strType).arg(strData); + textEdit->append(strData); + currentCount++; + return strData; +} + +void QtHelper::setFramelessForm(QWidget *widgetMain, bool tool, bool top, bool menu) +{ + widgetMain->setProperty("form", true); + widgetMain->setProperty("canMove", true); + + //根据设定逐个追加属性 +#ifdef __arm__ + widgetMain->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); +#else + widgetMain->setWindowFlags(Qt::FramelessWindowHint); +#endif + if (tool) { + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::Tool); + } + if (top) { + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::WindowStaysOnTopHint); + } + if (menu) { + //如果是其他系统比如neokylin会产生系统边框 +#ifdef Q_OS_WIN + widgetMain->setWindowFlags(widgetMain->windowFlags() | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); +#endif + } +} + +int QtHelper::showMessageBox(const QString &text, int type, int closeSec, bool exec) +{ + int result = 0; + if (type == 0) { + showMessageBoxInfo(text, closeSec, exec); + } else if (type == 1) { + showMessageBoxError(text, closeSec, exec); + } else if (type == 2) { + result = showMessageBoxQuestion(text); + } + + return result; +} + +void QtHelper::showMessageBoxInfo(const QString &text, int closeSec, bool exec) +{ + QMessageBox box(QMessageBox::Information, "提示", text); + box.setStandardButtons(QMessageBox::Yes); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.exec(); + //QMessageBox::information(0, "提示", info, QMessageBox::Yes); +} + +void QtHelper::showMessageBoxError(const QString &text, int closeSec, bool exec) +{ + QMessageBox box(QMessageBox::Critical, "错误", text); + box.setStandardButtons(QMessageBox::Yes); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.exec(); + //QMessageBox::critical(0, "错误", info, QMessageBox::Yes); +} + +int QtHelper::showMessageBoxQuestion(const QString &text) +{ + QMessageBox box(QMessageBox::Question, "询问", text); + box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + box.setButtonText(QMessageBox::Yes, QString("确 定")); + box.setButtonText(QMessageBox::No, QString("取 消")); + return box.exec(); + //return QMessageBox::question(0, "询问", info, QMessageBox::Yes | QMessageBox::No); +} + +void QtHelper::initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName, + const QString &dirName, bool native, int width, int height) +{ + //设置标题 + dialog->setWindowTitle(title); + //设置标签文本 + dialog->setLabelText(QFileDialog::Accept, acceptName); + dialog->setLabelText(QFileDialog::Reject, "取消(&C)"); + dialog->setLabelText(QFileDialog::LookIn, "查看"); + dialog->setLabelText(QFileDialog::FileName, "名称"); + dialog->setLabelText(QFileDialog::FileType, "类型"); + + //设置默认显示目录 + if (!dirName.isEmpty()) { + dialog->setDirectory(dirName); + } + + //设置对话框宽高 + if (width > 0 && height > 0) { +#ifdef Q_OS_ANDROID + bool horizontal = (QtHelper::deskWidth() > QtHelper::deskHeight()); + if (horizontal) { + width = QtHelper::deskWidth() / 2; + height = QtHelper::deskHeight() - 50; + } else { + width = QtHelper::deskWidth() - 10; + height = QtHelper::deskHeight() / 2; + } +#endif + dialog->setFixedSize(width, height); + } + + //设置是否采用本地对话框 + dialog->setOption(QFileDialog::DontUseNativeDialog, !native); + //设置只读可以取消右上角的新建按钮 + //dialog->setReadOnly(true); +} + +QString QtHelper::getDialogResult(QFileDialog *dialog) +{ + QString result; + if (dialog->exec() == QFileDialog::Accepted) { + result = dialog->selectedFiles().first(); + if (!result.contains(".")) { + //自动补全拓展名 保存文件(*.txt *.exe) + QString filter = dialog->selectedNameFilter(); + if (filter.contains("*.")) { + filter = filter.split("(").last(); + filter = filter.mid(0, filter.length() - 1); + //取出第一个作为拓展名 + if (!filter.contains("*.*")) { + filter = filter.split(" ").first(); + result = result + filter.mid(1, filter.length()); + } + } + } + } + return result; +} + +QString QtHelper::getOpenFileName(const QString &filter, const QString &dirName, const QString &fileName, + bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "打开文件", "选择(&S)", dirName, native, width, height); + + //设置文件类型 + if (!filter.isEmpty()) { + dialog.setNameFilter(filter); + } + + //设置默认文件名称 + dialog.selectFile(fileName); + return getDialogResult(&dialog); +} + +QString QtHelper::getSaveFileName(const QString &filter, const QString &dirName, const QString &fileName, + bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "保存文件", "保存(&S)", dirName, native, width, height); + + //设置文件类型 + if (!filter.isEmpty()) { + dialog.setNameFilter(filter); + } + + //设置默认文件名称 + dialog.selectFile(fileName); + //设置模态类型允许输入 + dialog.setWindowModality(Qt::WindowModal); + //设置置顶显示 + dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint); + return getDialogResult(&dialog); +} + +QString QtHelper::getExistingDirectory(const QString &dirName, bool native, int width, int height) +{ + QFileDialog dialog; + initDialog(&dialog, "选择目录", "选择(&S)", dirName, native, width, height); + dialog.setOption(QFileDialog::ReadOnly); + //设置只显示目录 +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + dialog.setFileMode(QFileDialog::DirectoryOnly); +#endif + dialog.setOption(QFileDialog::ShowDirsOnly); + return getDialogResult(&dialog); +} + +QString QtHelper::getXorEncryptDecrypt(const QString &value, char key) +{ + //矫正范围外的数据 + if (key < 0 || key >= 127) { + key = 127; + } + + //大概从5.9版本输出的加密密码字符串前面会加上 @String 字符 + QString result = value; + if (result.startsWith("@String")) { + result = result.mid(8, result.length() - 9); + } + + for (int i = 0; i < result.length(); ++i) { + result[i] = QChar(result.at(i).toLatin1() ^ key); + } + return result; +} + +quint8 QtHelper::getOrCode(const QByteArray &data) +{ + int len = data.length(); + quint8 result = 0; + for (int i = 0; i < len; ++i) { + result ^= data.at(i); + } + + return result; +} + +quint8 QtHelper::getCheckCode(const QByteArray &data) +{ + int len = data.length(); + quint8 temp = 0; + for (int i = 0; i < len; ++i) { + temp += data.at(i); + } + + return temp % 256; +} + +void QtHelper::initTableView(QTableView *tableView, int rowHeight, bool headVisible, bool edit, bool stretchLast) +{ + //设置弱属性用于应用qss特殊样式 + tableView->setProperty("model", true); + //取消自动换行 + tableView->setWordWrap(false); + //超出文本不显示省略号 + tableView->setTextElideMode(Qt::ElideNone); + //奇数偶数行颜色交替 + tableView->setAlternatingRowColors(false); + //垂直表头是否可见 + tableView->verticalHeader()->setVisible(headVisible); + //选中一行表头是否加粗 + tableView->horizontalHeader()->setHighlightSections(false); + //最后一行拉伸填充 + tableView->horizontalHeader()->setStretchLastSection(stretchLast); + //行标题最小宽度尺寸 + tableView->horizontalHeader()->setMinimumSectionSize(0); + //行标题最小高度,等同于和默认行高一致 + tableView->horizontalHeader()->setFixedHeight(rowHeight); + //默认行高 + tableView->verticalHeader()->setDefaultSectionSize(rowHeight); + //选中时一行整体选中 + tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + //只允许选择单个 + tableView->setSelectionMode(QAbstractItemView::SingleSelection); + + //表头不可单击 +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + tableView->horizontalHeader()->setSectionsClickable(false); +#else + tableView->horizontalHeader()->setClickable(false); +#endif + + //鼠标按下即进入编辑模式 + if (edit) { + tableView->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked); + } else { + tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + } +} + +void QtHelper::openFile(const QString &fileName, const QString &msg) +{ +#ifdef __arm__ + return; +#endif + //文件不存在则不用处理 + if (!QFile(fileName).exists()) { + return; + } + if (QtHelper::showMessageBoxQuestion(msg + "成功, 确定现在就打开吗?") == QMessageBox::Yes) { + QString url = QString("file:///%1").arg(fileName); + QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); + } +} + +bool QtHelper::checkIniFile(const QString &iniFile) +{ + //如果配置文件大小为0,则以初始值继续运行,并生成配置文件 + QFile file(iniFile); + if (file.size() == 0) { + return false; + } + + //如果配置文件不完整,则以初始值继续运行,并生成配置文件 + if (file.open(QFile::ReadOnly)) { + bool ok = true; + while (!file.atEnd()) { + QString line = file.readLine(); + line.replace("\r", ""); + line.replace("\n", ""); + QStringList list = line.split("="); + + if (list.count() == 2) { + QString key = list.at(0); + QString value = list.at(1); + if (value.isEmpty()) { + qDebug() << TIMEMS << "ini node no value" << key; + ok = false; + break; + } + } + } + + if (!ok) { + return false; + } + } else { + return false; + } + + return true; +} + +QString QtHelper::cutString(const QString &text, int len, int left, int right, bool file, const QString &mid) +{ + //如果指定了字符串分割则表示是文件名需要去掉拓展名 + QString result = text; + if (file && result.contains(".")) { + int index = result.lastIndexOf("."); + result = result.mid(0, index); + } + + //最终字符串格式为 前缀字符...后缀字符 + if (result.length() > len) { + result = QString("%1%2%3").arg(result.left(left)).arg(mid).arg(result.right(right)); + } + + return result; +} + +QRect QtHelper::getCenterRect(const QSize &imageSize, const QRect &widgetRect, int borderWidth, int scaleMode) +{ + QSize newSize = imageSize; + QSize widgetSize = widgetRect.size() - QSize(borderWidth * 1, borderWidth * 1); + + if (scaleMode == 0) { + if (newSize.width() > widgetSize.width() || newSize.height() > widgetSize.height()) { + newSize.scale(widgetSize, Qt::KeepAspectRatio); + } + } else if (scaleMode == 1) { + newSize.scale(widgetSize, Qt::KeepAspectRatio); + } else { + newSize = widgetSize; + } + + int x = widgetRect.center().x() - newSize.width() / 2; + int y = widgetRect.center().y() - newSize.height() / 2; + //不是2的倍数需要偏移1像素 + x += (x % 2 == 0 ? 1 : 0); + y += (y % 2 == 0 ? 1 : 0); + return QRect(x, y, newSize.width(), newSize.height()); +} + +void QtHelper::getScaledImage(QImage &image, const QSize &widgetSize, int scaleMode, bool fast) +{ + Qt::TransformationMode mode = fast ? Qt::FastTransformation : Qt::SmoothTransformation; + if (scaleMode == 0) { + if (image.width() > widgetSize.width() || image.height() > widgetSize.height()) { + image = image.scaled(widgetSize, Qt::KeepAspectRatio, mode); + } + } else if (scaleMode == 1) { + image = image.scaled(widgetSize, Qt::KeepAspectRatio, mode); + } else { + image = image.scaled(widgetSize, Qt::IgnoreAspectRatio, mode); + } +} + +QString QtHelper::getTimeString(qint64 time) +{ + time = time / 1000; + QString min = QString("%1").arg(time / 60, 2, 10, QChar('0')); + QString sec = QString("%2").arg(time % 60, 2, 10, QChar('0')); + return QString("%1:%2").arg(min).arg(sec); +} + +QString QtHelper::getTimeString(QElapsedTimer timer) +{ + return QString::number((float)timer.elapsed() / 1000, 'f', 3); +} + +QString QtHelper::getSizeString(quint64 size) +{ + float num = size; + QStringList list; + list << "KB" << "MB" << "GB" << "TB"; + + QString unit("bytes"); + QStringListIterator i(list); + while (num >= 1024.0 && i.hasNext()) { + unit = i.next(); + num /= 1024.0; + } + + return QString("%1 %2").arg(QString::number(num, 'f', 2)).arg(unit); +} + +//setSystemDateTime("2022", "07", "01", "12", "22", "55"); +void QtHelper::setSystemDateTime(const QString &year, const QString &month, const QString &day, const QString &hour, const QString &min, const QString &sec) +{ +#ifdef Q_OS_WIN + QProcess p(0); + //先设置日期 + p.start("cmd"); + p.waitForStarted(); + p.write(QString("date %1-%2-%3\n").arg(year).arg(month).arg(day).toLatin1()); + p.closeWriteChannel(); + p.waitForFinished(1000); + p.close(); + //再设置时间 + p.start("cmd"); + p.waitForStarted(); + p.write(QString("time %1:%2:%3.00\n").arg(hour).arg(min).arg(sec).toLatin1()); + p.closeWriteChannel(); + p.waitForFinished(1000); + p.close(); +#else + QString cmd = QString("date %1%2%3%4%5.%6").arg(month).arg(day).arg(hour).arg(min).arg(year).arg(sec); + //设置日期时间 + system(cmd.toLatin1()); + //硬件时钟同步 + system("hwclock -w"); +#endif +} + +void QtHelper::runWithSystem(bool autoRun) +{ + QtHelper::runWithSystem(qApp->applicationName(), qApp->applicationFilePath(), autoRun); +} + +void QtHelper::runWithSystem(const QString &fileName, const QString &filePath, bool autoRun) +{ +#ifdef Q_OS_WIN + //要转换成本地文件路径(不启动则文件路径为空即可) + QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat); + reg.setValue(fileName, autoRun ? QDir::toNativeSeparators(filePath) : ""); +#endif +} + +void QtHelper::runBin(const QString &path, const QString &name) +{ +#ifdef Q_OS_WIN + QString cmd1 = "tasklist"; + QString cmd2 = QString("%1/%2.exe").arg(path).arg(name); +#else + QString cmd1 = "ps -aux"; + QString cmd2 = QString("%1/%2").arg(path).arg(name); +#endif + +#ifndef Q_OS_WASM + QProcess p; + p.start(cmd1); + if (p.waitForFinished()) { + QString result = p.readAll(); + if (result.contains(name)) { + return; + } + } + + //加上引号可以兼容打开带空格的目录(Program Files) + if (cmd2.contains(" ")) { + cmd2 = "\"" + cmd2 + "\""; + } + + //QProcess::execute(cmd2); + QProcess::startDetached(cmd2); +#endif +} diff --git a/tool/nettool/api/qthelper.h b/tool/nettool/api/qthelper.h new file mode 100644 index 0000000..6562b43 --- /dev/null +++ b/tool/nettool/api/qthelper.h @@ -0,0 +1,180 @@ +#ifndef QTHELPER_H +#define QTHELPER_H + +#include "head.h" + +class QtHelper +{ +public: + //获取所有屏幕区域/当前鼠标所在屏幕索引/区域尺寸/缩放系数 + static QList getScreenRects(bool available = true); + static int getScreenIndex(); + static QRect getScreenRect(bool available = true); + static qreal getScreenRatio(bool devicePixel = false); + + //矫正当前鼠标所在屏幕居中尺寸 + static QRect checkCenterRect(QRect &rect, bool available = true); + + //获取桌面宽度高度+居中显示 + static int deskWidth(); + static int deskHeight(); + static QSize deskSize(); + + //居中显示窗体 + //定义标志位指定是以桌面为参照还是主程序界面为参照 + static QWidget *centerBaseForm; + static void setFormInCenter(QWidget *form); + static void showForm(QWidget *form); + + //程序文件名称和当前所在路径 + static QString appName(); + static QString appPath(); + + //程序最前面获取应用程序路径和名称 + static void getCurrentInfo(char *argv[], QString &path, QString &name); + //程序最前面读取配置文件节点的值 + static QString getIniValue(const QString &fileName, const QString &key); + static QString getIniValue(char *argv[], const QString &key, const QString &dir = QString()); + + //获取本地网卡IP集合 + static QStringList getLocalIPs(); + + //获取内置颜色集合 + static QList colors; + static QList getColorList(); + static QStringList getColorNames(); + //随机获取颜色集合中的颜色 + static QColor getRandColor(); + + //初始化随机数种子 + static void initRand(); + //获取随机小数 + static float getRandFloat(float min, float max); + //获取随机数,指定最小值和最大值 + static double getRandValue(int min, int max, bool contansMin = false, bool contansMax = false); + //获取范围值随机经纬度集合 + static QStringList getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat); + //根据旧的范围值和值计算新的范围值对应的值 + static int getRangeValue(int oldMin, int oldMax, int oldValue, int newMin, int newMax); + + //获取uuid + static QString getUuid(); + //校验目录 + static void checkPath(const QString &dirName); + //通用延时函数(支持Qt4 Qt5 Qt6) + static void sleep(int msec, bool exec = true); + //检查程序是否已经运行 + static void checkRun(); + + //设置Qt自带样式 + static void setStyle(); + //设置字体 + static QFont addFont(const QString &fontFile, const QString &fontName); + static void setFont(int fontSize = 12); + //设置编码 + static void setCode(bool utf8 = true); + //设置翻译文件 + static void setTranslator(const QString &qmFile); + + //动态设置权限 + static bool checkPermission(const QString &permission); + //申请安卓权限 + static void initAndroidPermission(); + + //一次性设置所有包括编码样式字体等 + static void initAll(bool utf8 = true, bool style = true, int fontSize = 13); + //初始化main函数最前面执行的一段代码 + static void initMain(bool desktopSettingsAware = false, bool use96Dpi = true, bool logCritical = true); + //初始化opengl类型(1=AA_UseDesktopOpenGL 2=AA_UseOpenGLES 3=AA_UseSoftwareOpenGL) + static void initOpenGL(quint8 type = 0, bool checkCardEnable = false, bool checkVirtualSystem = false); + + //执行命令行返回执行结果 + static QString doCmd(const QString &program, const QStringList &arguments, int timeout = 1000); + //获取显卡是否被禁用 + static bool isVideoCardEnable(); + //获取是否在虚拟机环境 + static bool isVirtualSystem(); + + //插入消息 + static QVector msgTypes; + static QVector msgKeys; + static QVector msgColors; + static QString appendMsg(QTextEdit *textEdit, int type, const QString &data, + int maxCount, int ¤tCount, + bool clear = false, bool pause = false); + + //设置无边框 + static void setFramelessForm(QWidget *widgetMain, bool tool = false, bool top = false, bool menu = true); + + //弹出框 + static int showMessageBox(const QString &text, int type = 0, int closeSec = 0, bool exec = false); + //弹出消息框 + static void showMessageBoxInfo(const QString &text, int closeSec = 0, bool exec = false); + //弹出错误框 + static void showMessageBoxError(const QString &text, int closeSec = 0, bool exec = false); + //弹出询问框 + static int showMessageBoxQuestion(const QString &text); + + //为什么还要自定义对话框因为可控宽高和汉化对应文本等 + //初始化对话框文本 + static void initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName, + const QString &dirName, bool native, int width, int height); + //拿到对话框结果 + static QString getDialogResult(QFileDialog *dialog); + //选择文件对话框 + static QString getOpenFileName(const QString &filter = QString(), + const QString &dirName = QString(), + const QString &fileName = QString(), + bool native = false, int width = 900, int height = 600); + //保存文件对话框 + static QString getSaveFileName(const QString &filter = QString(), + const QString &dirName = QString(), + const QString &fileName = QString(), + bool native = false, int width = 900, int height = 600); + //选择目录对话框 + static QString getExistingDirectory(const QString &dirName = QString(), + bool native = false, int width = 900, int height = 600); + + //异或加密-只支持字符,如果是中文需要将其转换base64编码 + static QString getXorEncryptDecrypt(const QString &value, char key); + //异或校验 + static quint8 getOrCode(const QByteArray &data); + //计算校验码 + static quint8 getCheckCode(const QByteArray &data); + + //初始化表格 + static void initTableView(QTableView *tableView, int rowHeight = 25, + bool headVisible = false, bool edit = false, + bool stretchLast = true); + //打开文件带提示框 + static void openFile(const QString &fileName, const QString &msg); + + //检查ini配置文件 + static bool checkIniFile(const QString &iniFile); + + //首尾截断字符串显示 + static QString cutString(const QString &text, int len, int left, int right, bool file, const QString &mid = "..."); + + //传入图片尺寸和窗体区域及边框大小返回居中区域(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充) + static QRect getCenterRect(const QSize &imageSize, const QRect &widgetRect, int borderWidth = 2, int scaleMode = 0); + //传入图片尺寸和窗体尺寸及缩放策略返回合适尺寸(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充) + static void getScaledImage(QImage &image, const QSize &widgetSize, int scaleMode = 0, bool fast = true); + + //毫秒数转时间 00:00 + static QString getTimeString(qint64 time); + //用时时间转秒数 + static QString getTimeString(QElapsedTimer timer); + //文件大小转 KB MB GB TB + static QString getSizeString(quint64 size); + + //设置系统时间 + static void setSystemDateTime(const QString &year, const QString &month, const QString &day, + const QString &hour, const QString &min, const QString &sec); + //设置开机自启动 + static void runWithSystem(bool autoRun = true); + static void runWithSystem(const QString &fileName, const QString &filePath, bool autoRun = true); + //启动运行程序(已经在运行则不启动) + static void runBin(const QString &path, const QString &name); +}; + +#endif // QTHELPER_H diff --git a/tool/nettool/api/qthelperdata.cpp b/tool/nettool/api/qthelperdata.cpp new file mode 100644 index 0000000..5f26ee5 --- /dev/null +++ b/tool/nettool/api/qthelperdata.cpp @@ -0,0 +1,473 @@ +#include "qthelperdata.h" +#include "qthelper.h" + +int QtHelperData::strHexToDecimal(const QString &strHex) +{ + bool ok; + return strHex.toInt(&ok, 16); +} + +int QtHelperData::strDecimalToDecimal(const QString &strDecimal) +{ + bool ok; + return strDecimal.toInt(&ok, 10); +} + +int QtHelperData::strBinToDecimal(const QString &strBin) +{ + bool ok; + return strBin.toInt(&ok, 2); +} + +QString QtHelperData::strHexToStrBin(const QString &strHex) +{ + quint8 decimal = strHexToDecimal(strHex); + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + + if (len < 8) { + for (int i = 0; i < 8 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrBin1(int decimal) +{ + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + if (len <= 8) { + for (int i = 0; i < 8 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrBin2(int decimal) +{ + QString bin = QString::number(decimal, 2); + quint8 len = bin.length(); + if (len <= 16) { + for (int i = 0; i < 16 - len; ++i) { + bin = "0" + bin; + } + } + + return bin; +} + +QString QtHelperData::decimalToStrHex(int decimal) +{ + QString temp = QString::number(decimal, 16); + if (temp.length() == 1) { + temp = "0" + temp; + } + + return temp; +} + +QByteArray QtHelperData::intToByte(int data, bool reverse) +{ + quint8 data1 = (quint8)(0x000000ff & data); + quint8 data2 = (quint8)((0x0000ff00 & data) >> 8); + quint8 data3 = (quint8)((0x00ff0000 & data) >> 16); + quint8 data4 = (quint8)((0xff000000 & data) >> 24); + + QByteArray result; + result.resize(4); + if (reverse) { + result[0] = data1; + result[1] = data2; + result[2] = data3; + result[3] = data4; + } else { + result[0] = data4; + result[1] = data3; + result[2] = data2; + result[3] = data1; + } + return result; +} + +int QtHelperData::byteToInt(const QByteArray &data, bool reverse) +{ + int result = 0; + if (reverse) { + result = data.at(0) & 0x000000ff; + result |= ((data.at(1) << 8) & 0x0000ff00); + result |= ((data.at(2) << 16) & 0x00ff0000); + result |= ((data.at(3) << 24) & 0xff000000); + } else { + result = data.at(3) & 0x000000ff; + result |= ((data.at(2) << 8) & 0x0000ff00); + result |= ((data.at(1) << 16) & 0x00ff0000); + result |= ((data.at(0) << 24) & 0xff000000); + } + return result; +} + +QByteArray QtHelperData::ushortToByte(int data, bool reverse) +{ + quint8 data1 = (quint8)(0x000000ff & data); + quint8 data2 = (quint8)((0x0000ff00 & data) >> 8); + + QByteArray result; + result.resize(2); + if (reverse) { + result[0] = data1; + result[1] = data2; + } else { + result[0] = data2; + result[1] = data1; + } + return result; +} + +int QtHelperData::byteToShort(const QByteArray &data, bool reverse) +{ + int result = 0; + if (reverse) { + result = data.at(0) & 0x000000ff; + result |= ((data.at(1) << 8) & 0x0000ff00); + } else { + result = data.at(1) & 0x000000ff; + result |= ((data.at(0) << 8) & 0x0000ff00); + } + if (result >= 32768) { + result = result - 65536; + } + return result; +} + +QString QtHelperData::getValue(quint8 value) +{ + QString result = QString::number(value); + if (result.length() <= 1) { + result = QString("0%1").arg(result); + } + return result; +} + +QString QtHelperData::trimmed(const QString &text, int type) +{ + QString temp = text; + QString pattern; + if (type == -1) { + pattern = "^ +\\s*"; + } else if (type == 0) { + pattern = "\\s"; + //temp.replace(" ", ""); + } else if (type == 1) { + pattern = "\\s* +$"; + } else if (type == 2) { + temp = temp.trimmed(); + } else if (type == 3) { + temp = temp.simplified(); + } + + //调用正则表达式移除空格 + if (!pattern.isEmpty()) { +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + temp.remove(QRegularExpression(pattern)); +#else + temp.remove(QRegExp(pattern)); +#endif + } + + return temp; +} + +QString QtHelperData::getXorEncryptDecrypt(const QString &value, char key) +{ + //矫正范围外的数据 + if (key < 0 || key >= 127) { + key = 127; + } + + //大概从5.9版本输出的加密密码字符串前面会加上 @String 字符 + QString result = value; + if (result.startsWith("@String")) { + result = result.mid(8, result.length() - 9); + } + + for (int i = 0; i < result.length(); ++i) { + result[i] = QChar(result.at(i).toLatin1() ^ key); + } + return result; +} + +quint8 QtHelperData::getOrCode(const QByteArray &data) +{ + int len = data.length(); + quint8 result = 0; + for (int i = 0; i < len; ++i) { + result ^= data.at(i); + } + + return result; +} + +quint8 QtHelperData::getCheckCode(const QByteArray &data) +{ + int len = data.length(); + quint8 temp = 0; + for (int i = 0; i < len; ++i) { + temp += data.at(i); + } + + return temp % 256; +} + +void QtHelperData::getFullData(QByteArray &buffer) +{ + //计算校验码 + quint8 checkCode = getCheckCode(buffer); + //尾部插入校验码 + buffer.append(checkCode); + //头部插入固定帧头 + buffer.insert(0, 0x16); +} + +//函数功能:计算CRC16 +//参数1:*data 16位CRC校验数据, +//参数2:len 数据流长度 +//参数3:init 初始化值 +//参数4:table 16位CRC查找表 + +//正序CRC计算 +quint16 QtHelperData::getCrc16(quint8 *data, int len, quint16 init, const quint16 *table) +{ + quint16 crc_16 = init; + quint8 temp; + while (len-- > 0) { + temp = crc_16 & 0xff; + crc_16 = (crc_16 >> 8) ^ table[(temp ^ *data++) & 0xff]; + } + + return crc_16; +} + +//逆序CRC计算 +quint16 QtHelperData::getCrc16Rec(quint8 *data, int len, quint16 init, const quint16 *table) +{ + quint16 crc_16 = init; + quint8 temp; + while (len-- > 0) { + temp = crc_16 >> 8; + crc_16 = (crc_16 << 8) ^ table[(temp ^ *data++) & 0xff]; + } + + return crc_16; +} + +//Modbus CRC16校验 +quint16 QtHelperData::getModbus16(quint8 *data, int len) +{ + //MODBUS CRC-16表 8005 逆序 + const quint16 table_16[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 + }; + + return getCrc16(data, len, 0xFFFF, table_16); +} + +//CRC16校验 +QByteArray QtHelperData::getCrcCode(const QByteArray &data) +{ + quint16 result = getModbus16((quint8 *)data.data(), data.length()); + return QtHelperData::ushortToByte(result, true); +} + +static QMap listChar; +void QtHelperData::initAscii() +{ + //0x20为空格,空格以下都是不可见字符 + if (listChar.count() == 0) { + listChar.insert(0, "\\NUL"); + listChar.insert(1, "\\SOH"); + listChar.insert(2, "\\STX"); + listChar.insert(3, "\\ETX"); + listChar.insert(4, "\\EOT"); + listChar.insert(5, "\\ENQ"); + listChar.insert(6, "\\ACK"); + listChar.insert(7, "\\BEL"); + listChar.insert(8, "\\BS"); + listChar.insert(9, "\\HT"); + listChar.insert(10, "\\LF"); + listChar.insert(11, "\\VT"); + listChar.insert(12, "\\FF"); + listChar.insert(13, "\\CR"); + listChar.insert(14, "\\SO"); + listChar.insert(15, "\\SI"); + listChar.insert(16, "\\DLE"); + listChar.insert(17, "\\DC1"); + listChar.insert(18, "\\DC2"); + listChar.insert(19, "\\DC3"); + listChar.insert(20, "\\DC4"); + listChar.insert(21, "\\NAK"); + listChar.insert(22, "\\SYN"); + listChar.insert(23, "\\ETB"); + listChar.insert(24, "\\CAN"); + listChar.insert(25, "\\EM"); + listChar.insert(26, "\\SUB"); + listChar.insert(27, "\\ESC"); + listChar.insert(28, "\\FS"); + listChar.insert(29, "\\GS"); + listChar.insert(30, "\\RS"); + listChar.insert(31, "\\US"); + listChar.insert(0x5C, "\\"); + listChar.insert(0x7F, "\\DEL"); + } +} + +QString QtHelperData::byteArrayToAsciiStr(const QByteArray &data) +{ + //先初始化字符表 + initAscii(); + + QString temp; + int len = data.length(); + for (int i = 0; i < len; ++i) { + char byte = data.at(i); + QString value = listChar.value(byte); + if (!value.isEmpty()) { + } else if (byte >= 0 && byte <= 0x7F) { + value = QString("%1").arg(byte); + } else { + value = decimalToStrHex((quint8)byte); + value = QString("\\x%1").arg(value.toUpper()); + } + + temp += value; + } + + return temp.trimmed(); +} + +QByteArray QtHelperData::asciiStrToByteArray(const QString &data) +{ + //先初始化字符表 + initAscii(); + + QByteArray buffer; + QStringList list = data.split("\\"); + + int count = list.count(); + for (int i = 1; i < count; ++i) { + QString str = list.at(i); + int key = 0; + if (str.contains("x")) { + key = strHexToDecimal(str.mid(1, 2)); + } else { + key = listChar.key("\\" + str); + } + + buffer.append(key); + } + + //可能是纯字符串不带控制字符 + if (buffer.length() == 0) { + buffer = data.toUtf8(); + } + + return buffer; +} + +char QtHelperData::hexStrToChar(char data) +{ + if ((data >= '0') && (data <= '9')) { + return data - 0x30; + } else if ((data >= 'A') && (data <= 'F')) { + return data - 'A' + 10; + } else if ((data >= 'a') && (data <= 'f')) { + return data - 'a' + 10; + } else { + return (-1); + } +} + +QByteArray QtHelperData::hexStrToByteArray(const QString &data) +{ + QByteArray senddata; + int hexdata, lowhexdata; + int hexdatalen = 0; + int len = data.length(); + senddata.resize(len / 2); + char lstr, hstr; + + for (int i = 0; i < len;) { + hstr = data.at(i).toLatin1(); + if (hstr == ' ') { + i++; + continue; + } + + i++; + if (i >= len) { + break; + } + + lstr = data.at(i).toLatin1(); + hexdata = hexStrToChar(hstr); + lowhexdata = hexStrToChar(lstr); + + if ((hexdata == 16) || (lowhexdata == 16)) { + break; + } else { + hexdata = hexdata * 16 + lowhexdata; + } + + i++; + senddata[hexdatalen] = (char)hexdata; + hexdatalen++; + } + + senddata.resize(hexdatalen); + return senddata; +} + +QString QtHelperData::byteArrayToHexStr(const QByteArray &data) +{ + QString temp = ""; + QString hex = data.toHex(); + for (int i = 0; i < hex.length(); i = i + 2) { + temp += hex.mid(i, 2) + " "; + } + + return temp.trimmed().toUpper(); +} diff --git a/tool/nettool/api/qthelperdata.h b/tool/nettool/api/qthelperdata.h new file mode 100644 index 0000000..0f649c3 --- /dev/null +++ b/tool/nettool/api/qthelperdata.h @@ -0,0 +1,65 @@ +#ifndef QTHELPERDATA_H +#define QTHELPERDATA_H + +#include + +class QtHelperData +{ +public: + //16进制字符串转10进制 + static int strHexToDecimal(const QString &strHex); + //10进制字符串转10进制 + static int strDecimalToDecimal(const QString &strDecimal); + //2进制字符串转10进制 + static int strBinToDecimal(const QString &strBin); + + //16进制字符串转2进制字符串 + static QString strHexToStrBin(const QString &strHex); + //10进制转2进制字符串一个字节 + static QString decimalToStrBin1(int decimal); + //10进制转2进制字符串两个字节 + static QString decimalToStrBin2(int decimal); + //10进制转16进制字符串,补零. + static QString decimalToStrHex(int decimal); + + //int和字节数组互转 + static QByteArray intToByte(int data, bool reverse = false); + static int byteToInt(const QByteArray &data, bool reverse = false); + + //ushort和字节数组互转 + static QByteArray ushortToByte(int data, bool reverse = false); + static int byteToShort(const QByteArray &data, bool reverse = false); + + //字符串补全 + static QString getValue(quint8 value); + //字符串去空格 -1=移除左侧空格 0=移除所有空格 1=移除右侧空格 2=移除首尾空格 3=首尾清除中间留一个空格 + static QString trimmed(const QString &text, int type); + + //异或加密-只支持字符,如果是中文需要将其转换base64编码 + static QString getXorEncryptDecrypt(const QString &value, char key); + //异或校验 + static quint8 getOrCode(const QByteArray &data); + + //公司专用-计算校验码 + static quint8 getCheckCode(const QByteArray &data); + //公司专用-加上桢头和校验码完整数据 + static void getFullData(QByteArray &buffer); + + //CRC校验 + static quint16 getCrc16Rec(quint8 *data, int len, quint16 init, const quint16 *table); + static quint16 getCrc16(quint8 *data, int len, quint16 init, const quint16 *table); + static quint16 getModbus16(quint8 *data, int len); + static QByteArray getCrcCode(const QByteArray &data); + + //字节数组与Ascii字符串互转 + static void initAscii(); + static QString byteArrayToAsciiStr(const QByteArray &data); + static QByteArray asciiStrToByteArray(const QString &data); + + //16进制字符串与字节数组互转 + static char hexStrToChar(char data); + static QByteArray hexStrToByteArray(const QString &data); + static QString byteArrayToHexStr(const QByteArray &data); +}; + +#endif // QTHELPERDATA_H diff --git a/tool/nettool/api/tcpclient.cpp b/tool/nettool/api/tcpclient.cpp new file mode 100644 index 0000000..29930f5 --- /dev/null +++ b/tool/nettool/api/tcpclient.cpp @@ -0,0 +1,96 @@ +#include "tcpclient.h" +#include "qthelper.h" +#include "qthelperdata.h" + +TcpClient::TcpClient(QTcpSocket *socket, QObject *parent) : QObject(parent) +{ + this->socket = socket; + ip = socket->peerAddress().toString(); + ip = ip.replace("::ffff:", ""); + port = socket->peerPort(); + + connect(socket, SIGNAL(disconnected()), this, SLOT(slot_disconnected())); + connect(socket, SIGNAL(readyRead()), this, SLOT(slot_readData())); +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(slot_error())); +#else + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slot_error())); +#endif +} + +QString TcpClient::getIP() const +{ + return this->ip; +} + +int TcpClient::getPort() const +{ + return this->port; +} + +void TcpClient::slot_disconnected() +{ + emit disconnected(ip, port); + socket->deleteLater(); + this->deleteLater(); +} + +void TcpClient::slot_error() +{ + emit error(ip, port, socket->errorString()); +} + +void TcpClient::slot_readData() +{ + QByteArray data = socket->readAll(); + if (data.length() <= 0) { + return; + } + + QString buffer; + if (AppConfig::HexReceiveTcpServer) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else if (AppConfig::AsciiTcpServer) { + buffer = QtHelperData::byteArrayToAsciiStr(data); + } else { + buffer = QString(data); + } + + emit receiveData(ip, port, buffer); + + //自动回复数据,可以回复的数据是以;隔开,每行可以带多个;所以这里不需要继续判断 + if (AppConfig::DebugTcpServer) { + int count = AppData::Keys.count(); + for (int i = 0; i < count; i++) { + if (AppData::Keys.at(i) == buffer) { + sendData(AppData::Values.at(i)); + break; + } + } + } +} + +void TcpClient::sendData(const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexSendTcpServer) { + buffer = QtHelperData::hexStrToByteArray(data); + } else if (AppConfig::AsciiTcpServer) { + buffer = QtHelperData::asciiStrToByteArray(data); + } else { + buffer = data.toUtf8(); + } + + socket->write(buffer); + emit sendData(ip, port, data); +} + +void TcpClient::disconnectFromHost() +{ + socket->disconnectFromHost(); +} + +void TcpClient::abort() +{ + socket->abort(); +} diff --git a/tool/nettool/api/tcpclient.h b/tool/nettool/api/tcpclient.h new file mode 100644 index 0000000..963e16a --- /dev/null +++ b/tool/nettool/api/tcpclient.h @@ -0,0 +1,46 @@ +#ifndef TCPCLIENT_H +#define TCPCLIENT_H + +#include + +//为了方便并发和单独处理数据所以单独写个类专门处理 +#if 1 +//小数据量可以不用线程,收发数据本身默认异步的 +class TcpClient : public QObject +#else +//线程方便处理密集运算比如解析图片 +class TcpClient : public QThread +#endif +{ + Q_OBJECT +public: + explicit TcpClient(QTcpSocket *socket, QObject *parent = 0); + +private: + QTcpSocket *socket; + QString ip; + int port; + +public: + QString getIP() const; + int getPort() const; + +private slots: + void slot_disconnected(); + void slot_error(); + void slot_readData(); + +signals: + void disconnected(const QString &ip, int port); + void error(const QString &ip, int port, const QString &error); + + void sendData(const QString &ip, int port, const QString &data); + void receiveData(const QString &ip, int port, const QString &data); + +public slots: + void sendData(const QString &data); + void disconnectFromHost(); + void abort(); +}; + +#endif // TCPCLIENT_H diff --git a/tool/nettool/api/tcpserver.cpp b/tool/nettool/api/tcpserver.cpp new file mode 100644 index 0000000..347c8dc --- /dev/null +++ b/tool/nettool/api/tcpserver.cpp @@ -0,0 +1,75 @@ +#include "tcpserver.h" +#include "qthelper.h" + +TcpServer::TcpServer(QObject *parent) : QTcpServer(parent) +{ + connect(this, SIGNAL(newConnection()), this, SLOT(slot_newConnection())); +} + +void TcpServer::slot_newConnection() +{ + QTcpSocket *socket = this->nextPendingConnection(); + TcpClient *client = new TcpClient(socket, this); + connect(client, SIGNAL(disconnected(QString, int)), this, SLOT(slot_disconnected(QString, int))); + connect(client, SIGNAL(error(QString, int, QString)), this, SIGNAL(error(QString, int, QString))); + connect(client, SIGNAL(sendData(QString, int, QString)), this, SIGNAL(sendData(QString, int, QString))); + connect(client, SIGNAL(receiveData(QString, int, QString)), this, SIGNAL(receiveData(QString, int, QString))); + + emit connected(client->getIP(), client->getPort()); + //连接后加入链表 + clients.append(client); +} + +void TcpServer::slot_disconnected(const QString &ip, int port) +{ + TcpClient *client = (TcpClient *)sender(); + emit disconnected(ip, port); + //断开连接后从链表中移除 + clients.removeOne(client); +} + +bool TcpServer::start() +{ + bool ok = listen(QHostAddress(AppConfig::TcpListenIP), AppConfig::TcpListenPort); + return ok; +} + +void TcpServer::stop() +{ + remove(); + this->close(); +} + +void TcpServer::writeData(const QString &ip, int port, const QString &data) +{ + foreach (TcpClient *client, clients) { + if (client->getIP() == ip && client->getPort() == port) { + client->sendData(data); + break; + } + } +} + +void TcpServer::writeData(const QString &data) +{ + foreach (TcpClient *client, clients) { + client->sendData(data); + } +} + +void TcpServer::remove(const QString &ip, int port) +{ + foreach (TcpClient *client, clients) { + if (client->getIP() == ip && client->getPort() == port) { + client->abort(); + break; + } + } +} + +void TcpServer::remove() +{ + foreach (TcpClient *client, clients) { + client->abort(); + } +} diff --git a/tool/nettool/api/tcpserver.h b/tool/nettool/api/tcpserver.h new file mode 100644 index 0000000..f289c69 --- /dev/null +++ b/tool/nettool/api/tcpserver.h @@ -0,0 +1,44 @@ +#ifndef TCPSERVER_H +#define TCPSERVER_H + +#include "tcpclient.h" + +class TcpServer : public QTcpServer +{ + Q_OBJECT +public: + explicit TcpServer(QObject *parent = 0); + +private: + QList clients; + +private slots: + void slot_newConnection(); + void slot_disconnected(const QString &ip, int port); + +signals: + void connected(const QString &ip, int port); + void disconnected(const QString &ip, int port); + void error(const QString &ip, int port, const QString &error); + + void sendData(const QString &ip, int port, const QString &data); + void receiveData(const QString &ip, int port, const QString &data); + +public slots: + //启动服务 + bool start(); + //停止服务 + void stop(); + + //指定连接发送数据 + void writeData(const QString &ip, int port, const QString &data); + //对所有连接发送数据 + void writeData(const QString &data); + + //断开指定连接 + void remove(const QString &ip, int port); + //断开所有连接 + void remove(); +}; + +#endif // TCPSERVER_H diff --git a/tool/nettool/api/webclient.cpp b/tool/nettool/api/webclient.cpp new file mode 100644 index 0000000..3276dff --- /dev/null +++ b/tool/nettool/api/webclient.cpp @@ -0,0 +1,105 @@ +#include "webclient.h" +#include "qthelper.h" +#include "qthelperdata.h" + +WebClient::WebClient(QWebSocket *socket, QObject *parent) : QObject(parent) +{ + this->socket = socket; + ip = socket->peerAddress().toString(); + ip = ip.replace("::ffff:", ""); + port = socket->peerPort(); + + connect(socket, SIGNAL(disconnected()), this, SLOT(slot_disconnected())); + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slot_error())); + + //暂时使用前面两个信号,部分系统后面两个信号Qt没实现,目前测试到5.15.2 + //在win上如果两组信号都关联了则都会触发,另外一组信号就是多个参数表示是否是最后一个数据包 + connect(socket, SIGNAL(textMessageReceived(QString)), this, SLOT(textMessageReceived(QString))); + connect(socket, SIGNAL(binaryMessageReceived(QByteArray)), this, SLOT(binaryMessageReceived(QByteArray))); + //connect(socket, SIGNAL(textFrameReceived(QString, bool)), this, SLOT(textFrameReceived(QString, bool))); + //connect(socket, SIGNAL(binaryFrameReceived(QByteArray, bool)), this, SLOT(binaryFrameReceived(QByteArray, bool))); +} + +QString WebClient::getIP() const +{ + return this->ip; +} + +int WebClient::getPort() const +{ + return this->port; +} + +void WebClient::slot_disconnected() +{ + emit disconnected(ip, port); + socket->deleteLater(); + this->deleteLater(); +} + +void WebClient::slot_error() +{ + emit error(ip, port, socket->errorString()); +} + +void WebClient::textFrameReceived(const QString &data, bool isLastFrame) +{ + QString buffer = data; + emit receiveData(ip, port, buffer); + + //自动回复数据,可以回复的数据是以;隔开,每行可以带多个;所以这里不需要继续判断 + if (AppConfig::DebugWebServer) { + int count = AppData::Keys.count(); + for (int i = 0; i < count; i++) { + if (AppData::Keys.at(i) == buffer) { + sendData(AppData::Values.at(i)); + break; + } + } + } +} + +void WebClient::binaryFrameReceived(const QByteArray &data, bool isLastFrame) +{ + QString buffer; + if (AppConfig::HexReceiveWebClient) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else { + buffer = QString(data); + } + + textFrameReceived(buffer, isLastFrame); +} + +void WebClient::textMessageReceived(const QString &data) +{ + textFrameReceived(data, true); +} + +void WebClient::binaryMessageReceived(const QByteArray &data) +{ + binaryFrameReceived(data, true); +} + +void WebClient::sendData(const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexSendWebServer) { + buffer = QtHelperData::hexStrToByteArray(data); + } else { + buffer = data.toUtf8(); + } + + if (AppConfig::AsciiWebServer) { + socket->sendTextMessage(data); + } else { + socket->sendBinaryMessage(buffer); + } + + emit sendData(ip, port, data); +} + +void WebClient::abort() +{ + socket->abort(); +} diff --git a/tool/nettool/api/webclient.h b/tool/nettool/api/webclient.h new file mode 100644 index 0000000..2ea7523 --- /dev/null +++ b/tool/nettool/api/webclient.h @@ -0,0 +1,49 @@ +#ifndef WEBCLIENT_H +#define WEBCLIENT_H + +#include + +//为了方便并发和单独处理数据所以单独写个类专门处理 +#if 1 +//小数据量可以不用线程,收发数据本身默认异步的 +class WebClient : public QObject +#else +//线程方便处理密集运算比如解析图片 +class WebClient : public QThread +#endif +{ + Q_OBJECT +public: + explicit WebClient(QWebSocket *socket, QObject *parent = 0); + +private: + QWebSocket *socket; + QString ip; + int port; + +public: + QString getIP() const; + int getPort() const; + +private slots: + void slot_disconnected(); + void slot_error(); + + void textFrameReceived(const QString &data, bool isLastFrame); + void binaryFrameReceived(const QByteArray &data, bool isLastFrame); + void textMessageReceived(const QString &data); + void binaryMessageReceived(const QByteArray &data); + +signals: + void disconnected(const QString &ip, int port); + void error(const QString &ip, int port, const QString &error); + + void sendData(const QString &ip, int port, const QString &data); + void receiveData(const QString &ip, int port, const QString &data); + +public slots: + void sendData(const QString &data); + void abort(); +}; + +#endif // WEBCLIENT_H diff --git a/tool/nettool/api/webserver.cpp b/tool/nettool/api/webserver.cpp new file mode 100644 index 0000000..0df95cb --- /dev/null +++ b/tool/nettool/api/webserver.cpp @@ -0,0 +1,75 @@ +#include "webserver.h" +#include "qthelper.h" + +WebServer::WebServer(const QString &serverName, SslMode secureMode, QObject *parent) : QWebSocketServer(serverName, secureMode, parent) +{ + connect(this, SIGNAL(newConnection()), this, SLOT(slot_newConnection())); +} + +void WebServer::slot_newConnection() +{ + QWebSocket *socket = this->nextPendingConnection(); + WebClient *client = new WebClient(socket, this); + connect(client, SIGNAL(disconnected(QString, int)), this, SLOT(slot_disconnected(QString, int))); + connect(client, SIGNAL(error(QString, int, QString)), this, SIGNAL(error(QString, int, QString))); + connect(client, SIGNAL(sendData(QString, int, QString)), this, SIGNAL(sendData(QString, int, QString))); + connect(client, SIGNAL(receiveData(QString, int, QString)), this, SIGNAL(receiveData(QString, int, QString))); + + emit connected(client->getIP(), client->getPort()); + //连接后加入链表 + clients.append(client); +} + +void WebServer::slot_disconnected(const QString &ip, int port) +{ + WebClient *client = (WebClient *)sender(); + emit disconnected(ip, port); + //断开连接后从链表中移除 + clients.removeOne(client); +} + +bool WebServer::start() +{ + bool ok = listen(QHostAddress(AppConfig::WebListenIP), AppConfig::WebListenPort); + return ok; +} + +void WebServer::stop() +{ + remove(); + this->close(); +} + +void WebServer::writeData(const QString &ip, int port, const QString &data) +{ + foreach (WebClient *client, clients) { + if (client->getIP() == ip && client->getPort() == port) { + client->sendData(data); + break; + } + } +} + +void WebServer::writeData(const QString &data) +{ + foreach (WebClient *client, clients) { + client->sendData(data); + } +} + +void WebServer::remove(const QString &ip, int port) +{ + foreach (WebClient *client, clients) { + if (client->getIP() == ip && client->getPort() == port) { + client->abort(); + break; + } + } +} + +void WebServer::remove() +{ + foreach (WebClient *client, clients) { + client->abort(); + } +} diff --git a/tool/nettool/api/webserver.h b/tool/nettool/api/webserver.h new file mode 100644 index 0000000..a30c728 --- /dev/null +++ b/tool/nettool/api/webserver.h @@ -0,0 +1,44 @@ +#ifndef WEBSERVER_H +#define WEBSERVER_H + +#include "webclient.h" + +class WebServer : public QWebSocketServer +{ + Q_OBJECT +public: + explicit WebServer(const QString &serverName = QString(), QWebSocketServer::SslMode secureMode = QWebSocketServer::NonSecureMode, QObject *parent = 0); + +private: + QList clients; + +private slots: + void slot_newConnection(); + void slot_disconnected(const QString &ip, int port); + +signals: + void connected(const QString &ip, int port); + void disconnected(const QString &ip, int port); + void error(const QString &ip, int port, const QString &error); + + void sendData(const QString &ip, int port, const QString &data); + void receiveData(const QString &ip, int port, const QString &data); + +public slots: + //启动服务 + bool start(); + //停止服务 + void stop(); + + //指定连接发送数据 + void writeData(const QString &ip, int port, const QString &data); + //对所有连接发送数据 + void writeData(const QString &data); + + //断开指定连接 + void remove(const QString &ip, int port); + //断开所有连接 + void remove(); +}; + +#endif // WEBSERVER_H diff --git a/tool/nettool/file/device.txt b/tool/nettool/file/device.txt new file mode 100644 index 0000000..47b4650 --- /dev/null +++ b/tool/nettool/file/device.txt @@ -0,0 +1,20 @@ +2015;\NUL2015 +666;667 +3001P;301PST1:hehe'2:P2'3:P3' +3002P;301PST +3003P;301PST +3004P;301PST +3005P;301PST +326;00110 +320;00101 +330010;00101 +331;332001 +568X;5691:0 +5700;5710:10:1;2;3 +330051;00101 +112P001000I1';113P001100I1'101I1'102B0'103B0'106B0'107I0'108I1'109I0'110R1.750000'111R6.300000'112R1.500000'113R3.100000'114R4.500000'115R1.050000'116R7.000000'117R9999.000000'118I0'119R3.500000'120R1.750000'121I1'122I0'123I0'124I70'130I1000'131I8000'132I1500'133I10000'134I10'135I5'136I20'137I40'140R0.000000'105B1'138I700'104I0'125I0'126I9999'141R0.200000'142R0.200000'143R0.000000'144R30.000000'150I1'151I10'152B0'153I0'160I0'200B0'210B0'211I1'212I1'213R1.050000'214R9999.000000'220B0'221I0'222I1'223I1'224R1.050000'225R7.000000'230B0'240I0'241B1'242B0'243B0'244B0'245R100.000000'246B0'260R0.000000'261I0'262I0'263I50'264I0'280B0'281R1.050000'282I9999'283I1'284R7.000000'285I1'286I1'290I0'291R9999.000000'292R9999.000000'293I10'294I150'295I0'402Shehe'406I1433082933'500R0.000000'501R9999.000000'502I4'503I10'504I1'505I30'506B0'510R0.000000'511R9999.000000'512R0.000000'513R9999.000000'514R0.000000'515R0.000000'507B0'520I0'521I9999'522I0'523I9999'524I0'525I0'508B0'560R0.000000'561R9999.000000'562R0.000000'563R9999.000000'564R0.000000'565R0.000000'530I0'531I9999'532I0'533I9999'534I0'535I0'540R0.000000'541R9999.000000'542R0.000000'543R9999.000000'544R0.000000'545R0.000000'550R0.000000'551R9999.000000'552R0.000000'553R9999.000000'554R0.000000'555R0.000000' +302P001;00101 +002;003\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL +112R000;113R001100R2.530000'101I1'102I23'103I1'104I0'105I0'106I3'107B1'108I0'109I2'110R0.000000'111I1'116R0.000000'117R0.000000'118I1'120I0'121I1'122R0.000000'123I1'300I186'301S2015-06-01'302S15:53:56'303S'305S359194'311I0'312I0'313I0'314I1'319I0'340I1'341I0'351SGUT'360S'361S'362S' +126;123G100I00186'101S2015-06-01'102S15:53:56'103S'104S0'105S359194'106I00000'107I00000'110I00000'111I00000'112I00000'113I00000'114I00001'115I00000'116I00000'200I00003'201R00001.50'202I00000'203I01060'204I1638400'205I00001'206R00002.50'210R00002.20'211R00002.80'212R00000.00'213R00000.00'214R00000.42'215R09999.00'216R00000.42'217R00002.80'218R00000.00'219R00000.00'230R00000.42'231R00002.80'232R00002.53';\ETX\xA6\EOT]\ENQI\ACK{\x08\ETX\x07\xB0\ENQ\xEA\NUL\xD8\xFF\x9F\xFF\x7F\xFF\xC3\xFF\xFC\xFF\x10\xFF\xC1\NUL\EOT\xFF\xFC\NUL\CR\SOH\CR\SOH\xB4\SOH\xC2\SOH\xC8\SOH\xC8\SOH\xA6\SOH\x94\SOH\xA8\SOH\xC6\SOH\xD8\SOH\xDC\SOH\xDA\SOH\xD8\SOH\xDA\SOH\xDA\SOH\xDC\SOH\xDC\SOH\xE4\SOH\xEC\SOH\xF4\STX\NUL\STX\LF\STX\x12\STX\x12\STX\x16\STX\x14\STX\x10\STX\x08\SOH\xE8\SOH\x98\SOH-\NUL\xE1\NUL\xA2\NUL\x86\NUL\x86\NUL\x96\NUL\xA8\NUL\xBF\NUL\xDD\NUL\xFF\SOH\x1D\SOH?\SOH_\SOHz\SOH\x98\SOH\xB4\SOH\xCC\SOH\xE4\SOH\xFA\STX\NUL\STX\ACK\STX\x08\STX\x0C\STX\ACK\STX\STX\SOH\xFE\SOH\xF6\SOH\xF4\SOH\xF6\SOH\xFA\STX\STX\STX\x0E\STX\x16\STX\x19\STX\x19\STX\ESC\STX\x1F\STX\x1F\STX\ESC\STX\x14\STX\x12\STX\x16\STX\ESC\STX%\STX3\STXA\STXC\STXG\STXM\STXO\STXO\STXO\STXO\STXO\STXU\STXU\STX]\STXe\STXq\STXw\STXy\STX\x7F\STX\x7F\STX\x81\STX\x85\STX\x83\STX\x83\STX\x87\STX\x8B\STX\x95\STX\xA7\STX\xBB\STX\xCE\STX\xD8\STX\xE6\STX\xF8\ETX\x10\ETX$\ETX:\ETXP\ETXn\ETX\x8F\ETX\xB3\ETX\xDD\EOT\x07\EOT+\EOTN\EOTh\EOT\x84\EOT\xA0\EOT\xBA\EOT\xD4\EOT\xE7\EOT\xF9\ENQ\x0F\ENQ)\ENQG\ENQi\ENQ\x95\ENQ\xB4\ENQ\xD0\ENQ\xEC\ACK\x0C\ACK(\ACKF\ACK[\ACKm\ACK}\ACK\x93\ACK\xA3\ACK\xBD\ACK\xDD\x07\STX\x07"\x07D\x07h\x07\x86\x07\x9E\x07\xB7\x07\xC7\x07\xD5\x07\xE5\x07\xFB\x08\ESC\x08C\x08p\x08\x8E\x08\xA6\x08\xB8\x08\xC2\x08\xCC\x08\xDA\x08\xE6\x08\xF4\x09\ACK\x09\x19\x09-\x09G\x09c\x09y\x09\x8B\x09\xA3\x09\xB9\x09\xC8\x09\xDA\x09\xE8\x09\xF8\LF\x10\LF(\LFB\LF^\LF\x81\LF\x9D\LF\xB3\LF\xCB\LF\xE5\LF\xFD\x0B\x13\x0B,\x0B>\x0BX\x0Br\x0B\x90\x0B\xAE\x0B\xCC\x0B\xED\x0C\x09\x0C%\x0CE\x0Ce\x0C}\x0C\x92\x0C\xA8\x0C\xBC\x0C\xD4\x0C\xEE\CR\x0C\CR,\CRO\CRk\CR\x87\CR\xA3\CR\xBD\CR\xD5\CR\xF0\x0E\ACK\x0E\x1C\x0E4\x0ER\x0En\x0E\x90\x0E\xB9\x0E\xDF\x0E\xFF\x0F\x1D\x0F?\x0F%\x0E\xB6\CR\xC3\x0C\x1F\LF:\x08e\ACK\xD3\ENQ\xA3\ENQ\x11\ENQE\ACK$\x07`\x08\x8F\x09}\LF\x12\LFV\LFb\LFH\LF\x16\x09\xDA\x09\x9D\x09k\x09C\x09\x16\x08\xF0\x08\xD8\x08\xC4\x08\xB4\x08\xAE\x08\xAE\x08\xB4\x08\xC0\x08\xC4\x08\xC2\x08\xB2\x08\xA4\x08\x94\x08x\x08Q\x08)\x07\xFB\x07\xD1\x07\xB3\x07\x98\x07\x82\x07h\x07N\x07B\x07B\x07D\x07@\x074\x07$\x07\x12\ACK\xF9\ACK\xDD\ACK\xBF\ACK\xA5\ACK\x93\ACK\x87\ACKy\ACKi\ACK[\ACKM\ACK:\ACK$\ACK\x08\ENQ\xE4\ENQ\xCC\ENQ\xB6\ENQ\xA0\ENQ\x83\ENQk\ENQY\ENQM\ENQM\ENQM\ENQK\ENQE\ENQA\ENQ?\ENQ5\ENQ%\ENQ\x11\ENQ\SOH\EOT\xF7\EOT\xEB\EOT\xE7\EOT\xE7\EOT\xED\EOT\xED\EOT\xEB\EOT\xE3\EOT\xD6\EOT\xCE\EOT\xCE\EOT\xC8\EOT\xBE\EOT\xB4\EOT\xAC\EOT\xA4\EOT\xAA\EOT\xA8\EOT\x9E\EOT\x94\EOT\x8C\EOT\x80\EOTn\EOTT\EOT8\EOT\x17\ETX\xFF\ETX\xE9\ETX\xD1\ETX\xC5\ETX\xB5\ETX\xA7\ETX\x8F\ETXx\ETX\\\ETX>\ETX$\ETX\x0E\STX\xE8\STX\xC5\STX\xA5\STX\x91\STX\x7F\STXm\STX]\STXG\STX-\STX\x1D\STX\x0C\SOH\xFA\SOH\xF0\SOH\xDE\SOH\xD0\SOH\xBE\SOH\xB2\SOH\xA4\SOH\x9A\SOH\x88\SOH~\SOHp\SOH]\SOHE\SOH3\SOH%\SOH\x17\SOH\ETX\NUL\xDF\NUL\xB0\NUL\x84\NULj\NULT\NUL>\NUL*\NUL\CAN\NUL\x0C\xFF\xFE\xFF\xF1\xFF\xE9\xFF\xE1\xFF\xE1\xFF\xE1\xFF\xE1\xFF\xE3\xFF\xEB\xFF\xEF\xFF\xF3\xFF\xF5\xFF\xF7\xFF\xF3\xFF\xF1\xFF\xEB\xFF\xE7\xFF\xE7\xFF\xE7\xFF\xE7\xFF\xE9\xFF\xEF\xFF\xF7\xFF\xF9\xFF\xFE\NUL\NUL\NUL\NUL\xFF\xFE\xFF\xF7\xFF\xF3\xFF\xED\xFF\xED\xFF\xED\xFF\xF3\xFF\xFC\NUL\EOT\NUL\x0C\NUL\x0E\NUL\x12\NUL\x12\NUL\x10\NUL\x08\NUL\STX\xFF\xFE\xFF\xF9\xFF\xF9\xFF\xF9\NUL\NUL\NUL\ACK\NUL\x0C\NUL\x12\NUL\x12\NUL\x10\NUL\LF\NUL\STX\xFF\xF9\xFF\xF3\xFF\xF3\xFF\xED\xFF\xED\xFF\xF1\xFF\xF7\xFF\xFE\NUL\EOT\NUL\ACK\NUL\ACK\NUL\EOT\xFF\xFA\xFF\xF3\xFF\xF3\xFF\xF3\xFF\xF3\xFF\xF3\xFF\xF3\xFF\xF9\xFF\xFC\xFF\xF9\xFF\xF9\xFF\xF9\xFF\xFE\xFF\xF9\xFF\xF5\xFF\xEF\xFF\xE9\xFF\xE5\xFF\xE1\xFF\xE1\xFF\xE9\xFF\xED\xFF\xF5\xFF\xF9\xFF\xF9\NUL\NUL\xFF\xFE\xFF\xF9\xFF\xF3\xFF\xF3\xFF\xF3\xFF\xEF\xFF\xF3\xFF\xF5\xFF\xFE\NUL\EOT\NUL\ACK\NUL\ACK\NUL\ACK\NUL\ACK\NUL\ACK\NUL\NUL\xFF\xF9\xFF\xF3 +127;125G100I00186'101S2015-06-01'102S15:53:56'103S'104S0'105S359194'106I00000'107I00000'110I00000'111I00000'112I00000'113I00000'114I00001'115I00000'116I00000'200I00003'201R00001.50'202I00000'203I36000'204I01979'205I08192'220I00002'221I09000'222I00000'223I09999'224I00771'225I00000'226I00001'227I00000'228I00001'229I00023'240I-9997'241I00001'242I00001'243I00001'244I00000'245I09998';\NUL\NUL\x08%\CR4\x111\NAK\xA6\CAN\ETX\x16\xD6\x14\CR\x0F\xBA\x0C\x12\x07\x85\EOT\xCB\ETX]\ETX\x80\EOT\x9E\ENQ\xE4\x07\x8B\x08\xCB\LFA\x0BM\x0Cq\CR:\x0E\x16\x0E\xAB\x0FM\x0F\xC1\x10>\x10\x93\x10\xF3\x115\x11}\x11\xAE\x11\xE3\x12\x08\x120\x12N\x12n\x12\x81\x12\x96\x12\xA4\x12\xB5\x12\xC1\x12\xCD\x12\xD4\x12\xD8\x12\xCA\x12\xA3\x12\x82\x12^\x12E\x12/\x12$\x12\x1A\x12\x13\x12\CR\x12\ACK\x11\xFF\x11\xF9\x11\xF0\x11\xE8\x11\xDE\x11\xDA\x11\xCF\x11\xC7\x11\xBC\x11\xB2\x11\xA8\x11\xA4\x11\x9E\x11\x9C\x11\x9C\x11\x9C\x11\x9D\x11\x9F\x11\x9F\x11\x9F\x11\xA0\x11\xA3\x11\xA7\x11\xA9\x11\xA9\x11\xAB\x11\xB2\x11\xBA\x11\xC3\x11\xCC\x11\xD7\x11\xE0\x11\xEB\x11\xF6\x12\ACK\x12\x11\x12"\x12/\x12@\x12M\x12b\x12r\x12\x86\x12\x9A\x12\xB3\x12\xC9\x12\xDD\x12\xF1\x13\x08\x13\x1C\x134\x13I\x13d\x13|\x13\x99\x13\xB3\x13\xD2\x13\xEC\x14\CR\x14%\x14F\x14_\x14\x7F\x14\x9A\x14\xBC\x14\xD9\x14\xFB\NAK\NAK\NAK7\NAKS\NAKw\NAK\x91\NAK\xB1\NAK\xC9\NAK\xE3\NAK\xF7\x16\x0F\x16"\x168\x16K\x16d\x16v\x16\x8D\x16\x9E\x16\xB2\x16\xC5\x16\xDE\x16\xF4\x17\x0E\x17"\x17>\x17T\x17u\x17\x91\x17\xB3\x17\xCF\x17\xEF\CAN\LF\CAN*\CAND\CANd\CAN\x7F\CAN\xA4\CAN\xC4\CAN\xEE\x19\x0F\x199\x19[\x19\x82\x19\xA3\x19\xC5\x19\xE1\x1A\ENQ\x1A#\x1AI\x1Al\x1A\x98\x1A\xBC\x1A\xE8\ESC\x0E\ESC>\ESCg\ESC\x9D\ESC\xCC\x1C\x08\x1C:\x1Cw\x1C\xAA\x1C\xE7\x1D\x17\x1DP\x1D~\x1D\xB8\x1D\xE8\x1E"\x1EO\x1E\x89\x1E\xBA\x1E\xF7\x1F(\x1Fj\x1F\xA1\x1F\xE2 \NAK Q \x82 \xBD \xEE!-!a!\xA5!\xDD"$"^"\xA7"\xDE###W#\x98#\xD0$\x1C$Y$\xA5$\xE4%4%v%\xC9&\x07&S&\x8F&\xD6'\x13'a'\x9F'\xEB(((y(\xBD)\x13)W)\xB0)\xF3*J*\x90*\xE4+-+\x81+\xAD+\xA5+}+\x1C*\xBF*:)\xD0)\\)!)\x11)\x1F)6)>)9)))\x0E(\xF7(\xD5(\xBE(\x9F(\x8B(t(c(P(?(,(\x1D(\x0B'\xFD'\xEC'\xDF'\xCE'\xC1'\xAE'\x9E'\x8B'|'j'Y'F'8'%'\x19'\LF&\xFF&\xEB&\xDC&\xCC&\xC1&\xB1&\xA5&\x94&\x88&w&j&Y&L&>&4&&&\x1C&\CR&\STX%\xF7%\xEE%\xDF%\xD1%\xC1%\xB7%\xAA%\x9E%\x89%{%j%]%O%C%6%+%\x1E%\x11%\NUL$\xF0$\xD8$\xC8$\xB2$\x9D$\x85$p$X$E$($\x0F#\xF1#\xDB#\xC0#\xA7#\x85#j#M#4#\x12"\xF6"\xD5"\xBA"\x9A"}"W":"\x12!\xF5!\xD0!\xB4!\x8F!r!Q!8!\x1A!\SOH \xE4 \xCC \xB3 \x9B } g L 6 \x1C \ENQ\x1F\xEA\x1F\xD3\x1F\xBA\x1F\xA5\x1F\x8B\x1Fv\x1F[\x1FF\x1F(\x1F\x13\x1E\xF4\x1E\xDB\x1E\xBF\x1E\xA9\x1E\x8F\x1Ew\x1E[\x1EB\x1E(\x1E\x12\x1D\xFB\x1D\xE5\x1D\xC4\x1D\xA5\x1Dz\x1DU\x1D(\x1D\x07\x1C\xDB\x1C\xBB\x1C\x95\x1Cx\x1CZ\x1CD\x1C*\x1C\x1C\x1C\LF\ESC\xFE\ESC\xF4\ESC\xEE\ESC\xEA\ESC\xE5\ESC\xE7\ESC\xE7\ESC\xE8\ESC\xEB\ESC\xF0\ESC\xF3\ESC\xF8\ESC\xFF\x1C\x08\x1C\x0B\x1C\x16\x1C\ESC\x1C#\x1C(\x1C/\x1C5\x1C<\x1C@\x1CH\x1CN\x1CT\x1CZ\x1Cb\x1Ce\x1Ck\x1Cp\x1Cv\x1Cy\x1C{\x1C{\x1Cx\x1Cv\x1Cr\x1Cq\x1Cp\x1Co\x1Co\x1Co\x1Co\x1Cp\x1Cq\x1Cq\x1Cq\x1Cq\x1Ct\x1Ct\x1Ct\x1Cv\x1Cs\x1Cu\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cv\x1Cw\x1Cx\x1Cz\x1Cz\x1C{\x1C{\x1C{\x1C{\x1C{\x1C}\x1C\x7F\x1C}\x1C~\x1C}\x1C}\x1C\x7F\x1C}\x1C}\x1C|\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{\x1C{ diff --git a/tool/nettool/file/send.txt b/tool/nettool/file/send.txt new file mode 100644 index 0000000..51b3944 --- /dev/null +++ b/tool/nettool/file/send.txt @@ -0,0 +1,17 @@ +16 FF 01 01 E0 E1 +16 FF 01 01 E1 E2 +16 01 02 DF BC 16 01 02 DF BC 16 01 02 DF BC 12 13 14 15 +16 00 00 04 D0 F0 F1 65 C4 +16 00 00 04 D0 05 AB 5A C4 +16 01 10 02 F0 03 06 16 01 11 02 F0 03 06 16 01 12 02 F0 03 06 16 01 13 02 F0 03 06 16 01 +14 02 F0 03 06 16 01 15 02 F0 03 06 16 01 16 02 F0 03 06 +16 11 01 03 E8 01 10 0E +16 11 01 03 E8 01 12 10 +16 11 01 03 E8 01 14 12 +16 11 01 03 E8 01 15 13 +DISARMEDALL +BURGLARY 012 +BYPASS 012 +DISARMED 012 +16 00 01 01 D1 D3 +16 01 11 11 \ No newline at end of file diff --git a/tool/nettool/form/form.pri b/tool/nettool/form/form.pri new file mode 100644 index 0000000..fe4386d --- /dev/null +++ b/tool/nettool/form/form.pri @@ -0,0 +1,28 @@ +FORMS += $$PWD/frmmain.ui +FORMS += $$PWD/frmtcpclient.ui +FORMS += $$PWD/frmtcpserver.ui +FORMS += $$PWD/frmudpclient.ui +FORMS += $$PWD/frmudpserver.ui + +HEADERS += $$PWD/frmmain.h +HEADERS += $$PWD/frmtcpclient.h +HEADERS += $$PWD/frmtcpserver.h +HEADERS += $$PWD/frmudpclient.h +HEADERS += $$PWD/frmudpserver.h + +SOURCES += $$PWD/frmmain.cpp +SOURCES += $$PWD/frmtcpclient.cpp +SOURCES += $$PWD/frmtcpserver.cpp +SOURCES += $$PWD/frmudpclient.cpp +SOURCES += $$PWD/frmudpserver.cpp + +contains(DEFINES, websocket) { +FORMS += $$PWD/frmwebclient.ui +FORMS += $$PWD/frmwebserver.ui + +HEADERS += $$PWD/frmwebclient.h +HEADERS += $$PWD/frmwebserver.h + +SOURCES += $$PWD/frmwebclient.cpp +SOURCES += $$PWD/frmwebserver.cpp +} diff --git a/tool/nettool/form/frmmain.cpp b/tool/nettool/form/frmmain.cpp new file mode 100644 index 0000000..d1d0c05 --- /dev/null +++ b/tool/nettool/form/frmmain.cpp @@ -0,0 +1,51 @@ +#include "frmmain.h" +#include "ui_frmmain.h" +#include "qthelper.h" + +#include "frmtcpclient.h" +#include "frmtcpserver.h" +#include "frmudpclient.h" +#include "frmudpserver.h" +#ifdef websocket +#include "frmwebclient.h" +#include "frmwebserver.h" +#endif + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::initForm() +{ + ui->tabWidget->addTab(new frmTcpClient, "TCP客户端"); + ui->tabWidget->addTab(new frmTcpServer, "TCP服务端"); + ui->tabWidget->addTab(new frmUdpClient, "UDP客户端"); + ui->tabWidget->addTab(new frmUdpServer, "UDP服务端"); +#ifdef websocket + ui->tabWidget->addTab(new frmWebClient, "WEB客户端"); + ui->tabWidget->addTab(new frmWebServer, "WEB服务端"); +#endif +#ifdef Q_OS_WASM + AppConfig::CurrentIndex = 4; +#endif +} + +void frmMain::initConfig() +{ + ui->tabWidget->setCurrentIndex(AppConfig::CurrentIndex); + connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(saveConfig())); +} + +void frmMain::saveConfig() +{ + AppConfig::CurrentIndex = ui->tabWidget->currentIndex(); + AppConfig::writeConfig(); +} diff --git a/tool/nettool/form/frmmain.h b/tool/nettool/form/frmmain.h new file mode 100644 index 0000000..55dc775 --- /dev/null +++ b/tool/nettool/form/frmmain.h @@ -0,0 +1,27 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +namespace Ui { +class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); +}; + +#endif // FRMMAIN_H diff --git a/tool/nettool/form/frmmain.ui b/tool/nettool/form/frmmain.ui new file mode 100644 index 0000000..d6f91ef --- /dev/null +++ b/tool/nettool/form/frmmain.ui @@ -0,0 +1,46 @@ + + + frmMain + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QTabWidget::South + + + -1 + + + + + + + + diff --git a/tool/nettool/form/frmtcpclient.cpp b/tool/nettool/form/frmtcpclient.cpp new file mode 100644 index 0000000..92f475f --- /dev/null +++ b/tool/nettool/form/frmtcpclient.cpp @@ -0,0 +1,246 @@ +#include "frmtcpclient.h" +#include "ui_frmtcpclient.h" +#include "qthelper.h" +#include "qthelperdata.h" + +frmTcpClient::frmTcpClient(QWidget *parent) : QWidget(parent), ui(new Ui::frmTcpClient) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); +} + +frmTcpClient::~frmTcpClient() +{ + delete ui; +} + +bool frmTcpClient::eventFilter(QObject *watched, QEvent *event) +{ + //双击清空 + if (watched == ui->txtMain->viewport()) { + if (event->type() == QEvent::MouseButtonDblClick) { + on_btnClear_clicked(); + } + } + + return QWidget::eventFilter(watched, event); +} + +void frmTcpClient::initForm() +{ + QFont font; + font.setPixelSize(16); + ui->txtMain->setFont(font); + ui->txtMain->viewport()->installEventFilter(this); + + isOk = false; + + //实例化对象并绑定信号槽 + socket = new QTcpSocket(this); + connect(socket, SIGNAL(connected()), this, SLOT(connected())); + connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); + connect(socket, SIGNAL(readyRead()), this, SLOT(readData())); +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(error())); +#else + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error())); +#endif + + //定时器发送数据 + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(on_btnSend_clicked())); + + //填充数据到下拉框 + ui->cboxInterval->addItems(AppData::Intervals); + ui->cboxData->addItems(AppData::Datas); + AppData::loadIP(ui->cboxBindIP); +} + +void frmTcpClient::initConfig() +{ + ui->ckHexSend->setChecked(AppConfig::HexSendTcpClient); + connect(ui->ckHexSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexReceive->setChecked(AppConfig::HexReceiveTcpClient); + connect(ui->ckHexReceive, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAscii->setChecked(AppConfig::AsciiTcpClient); + connect(ui->ckAscii, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckDebug->setChecked(AppConfig::DebugTcpClient); + connect(ui->ckDebug, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSend->setChecked(AppConfig::AutoSendTcpClient); + connect(ui->ckAutoSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->cboxInterval->setCurrentIndex(ui->cboxInterval->findText(QString::number(AppConfig::IntervalTcpClient))); + connect(ui->cboxInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->cboxBindIP->setCurrentIndex(ui->cboxBindIP->findText(AppConfig::TcpBindIP)); + connect(ui->cboxBindIP, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->txtBindPort->setText(QString::number(AppConfig::TcpBindPort)); + connect(ui->txtBindPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtServerIP->setText(AppConfig::TcpServerIP); + connect(ui->txtServerIP, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtServerPort->setText(QString::number(AppConfig::TcpServerPort)); + connect(ui->txtServerPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + this->initTimer(); +} + +void frmTcpClient::saveConfig() +{ + AppConfig::HexSendTcpClient = ui->ckHexSend->isChecked(); + AppConfig::HexReceiveTcpClient = ui->ckHexReceive->isChecked(); + AppConfig::AsciiTcpClient = ui->ckAscii->isChecked(); + AppConfig::DebugTcpClient = ui->ckDebug->isChecked(); + AppConfig::AutoSendTcpClient = ui->ckAutoSend->isChecked(); + AppConfig::IntervalTcpClient = ui->cboxInterval->currentText().toInt(); + AppConfig::TcpBindIP = ui->cboxBindIP->currentText(); + AppConfig::TcpBindPort = ui->txtBindPort->text().trimmed().toInt(); + AppConfig::TcpServerIP = ui->txtServerIP->text().trimmed(); + AppConfig::TcpServerPort = ui->txtServerPort->text().trimmed().toInt(); + AppConfig::writeConfig(); + + this->initTimer(); +} + +void frmTcpClient::initTimer() +{ + if (timer->interval() != AppConfig::IntervalTcpClient) { + timer->setInterval(AppConfig::IntervalTcpClient); + } + + if (AppConfig::AutoSendTcpClient) { + if (!timer->isActive()) { + timer->start(); + } + } else { + if (timer->isActive()) { + timer->stop(); + } + } +} + +void frmTcpClient::append(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain, type, data, maxCount, currentCount, clear, ui->ckShow->isChecked()); +} + +void frmTcpClient::connected() +{ + isOk = true; + ui->btnConnect->setText("断开"); + append(2, "服务器连接"); + append(4, QString("本地地址: %1 本地端口: %2").arg(socket->localAddress().toString()).arg(socket->localPort())); + append(4, QString("远程地址: %1 远程端口: %2").arg(socket->peerAddress().toString()).arg(socket->peerPort())); +} + +void frmTcpClient::disconnected() +{ + isOk = false; + ui->btnConnect->setText("连接"); + append(2, "服务器断开"); +} + +void frmTcpClient::error() +{ + append(3, socket->errorString()); +} + +void frmTcpClient::readData() +{ + QByteArray data = socket->readAll(); + if (data.length() <= 0) { + return; + } + + QString buffer; + if (AppConfig::HexReceiveTcpClient) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else if (AppConfig::AsciiTcpClient) { + buffer = QtHelperData::byteArrayToAsciiStr(data); + } else { + buffer = QString(data); + } + + append(1, buffer); + + //自动回复数据,可以回复的数据是以;隔开,每行可以带多个;所以这里不需要继续判断 + if (AppConfig::DebugTcpClient) { + int count = AppData::Keys.count(); + for (int i = 0; i < count; i++) { + if (AppData::Keys.at(i) == buffer) { + sendData(AppData::Values.at(i)); + break; + } + } + } +} + +void frmTcpClient::sendData(const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexSendTcpClient) { + buffer = QtHelperData::hexStrToByteArray(data); + } else if (AppConfig::AsciiTcpClient) { + buffer = QtHelperData::asciiStrToByteArray(data); + } else { + buffer = data.toUtf8(); + } + + socket->write(buffer); + append(0, data); +} + +void frmTcpClient::on_btnConnect_clicked() +{ + if (ui->btnConnect->text() == "连接") { + //断开所有连接和操作 + //socket->abort(); + //绑定网卡和端口 + //有个后遗症,客户端这边断开连接后还会保持几分钟导致不能重复绑定 + //如果是服务器断开则可以继续使用 + //提示 The bound address is already in use + //参考 https://www.cnblogs.com/baiduboy/p/7426822.html +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + //socket->bind(QHostAddress(AppConfig::TcpBindIP), AppConfig::TcpBindPort); +#endif + //连接服务器 + socket->connectToHost(AppConfig::TcpServerIP, AppConfig::TcpServerPort); + } else { + socket->abort(); + } +} + +void frmTcpClient::on_btnSave_clicked() +{ + QString data = ui->txtMain->toPlainText(); + AppData::saveData(data); + on_btnClear_clicked(); +} + +void frmTcpClient::on_btnClear_clicked() +{ + append(0, "", true); +} + +void frmTcpClient::on_btnSend_clicked() +{ + if (!isOk) { + return; + } + + QString data = ui->cboxData->currentText(); + if (data.length() <= 0) { + return; + } + + sendData(data); +} diff --git a/tool/nettool/form/frmtcpclient.h b/tool/nettool/form/frmtcpclient.h new file mode 100644 index 0000000..2a1604b --- /dev/null +++ b/tool/nettool/form/frmtcpclient.h @@ -0,0 +1,50 @@ +#ifndef FRMTCPCLIENT_H +#define FRMTCPCLIENT_H + +#include +#include + +namespace Ui { +class frmTcpClient; +} + +class frmTcpClient : public QWidget +{ + Q_OBJECT + +public: + explicit frmTcpClient(QWidget *parent = 0); + ~frmTcpClient(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + Ui::frmTcpClient *ui; + + bool isOk; + QTcpSocket *socket; + QTimer *timer; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); + void initTimer(); + void append(int type, const QString &data, bool clear = false); + +private slots: + void connected(); + void disconnected(); + void error(); + void readData(); + void sendData(const QString &data); + +private slots: + void on_btnConnect_clicked(); + void on_btnSave_clicked(); + void on_btnClear_clicked(); + void on_btnSend_clicked(); +}; + +#endif // FRMTCPCLIENT_H diff --git a/tool/nettool/form/frmtcpclient.ui b/tool/nettool/form/frmtcpclient.ui new file mode 100644 index 0000000..4675e0e --- /dev/null +++ b/tool/nettool/form/frmtcpclient.ui @@ -0,0 +1,264 @@ + + + frmTcpClient + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 170 + 0 + + + + + 170 + 16777215 + + + + QFrame::Box + + + QFrame::Sunken + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 16进制接收 + + + + + + + 16进制发送 + + + + + + + 控制字符 + + + + + + + 暂停显示 + + + + + + + 模拟设备 + + + + + + + 定时发送 + + + + + + + + + + 绑定地址 + + + + + + + + + + 绑定端口 + + + + + + + + + + 服务器地址 + + + + + + + + + + 服务器端口 + + + + + + + + + + 连接 + + + + + + + 保存 + + + + + + + 清空 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 发送 + + + + + + + + + + txtMain + cboxData + btnSend + ckHexReceive + ckHexSend + ckAscii + ckShow + ckDebug + ckAutoSend + cboxInterval + cboxBindIP + txtBindPort + txtServerIP + txtServerPort + btnConnect + btnSave + btnClear + + + + diff --git a/tool/nettool/form/frmtcpserver.cpp b/tool/nettool/form/frmtcpserver.cpp new file mode 100644 index 0000000..79dc5a0 --- /dev/null +++ b/tool/nettool/form/frmtcpserver.cpp @@ -0,0 +1,236 @@ +#include "frmtcpserver.h" +#include "ui_frmtcpserver.h" +#include "qthelper.h" + +frmTcpServer::frmTcpServer(QWidget *parent) : QWidget(parent), ui(new Ui::frmTcpServer) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); + on_btnListen_clicked(); +} + +frmTcpServer::~frmTcpServer() +{ + //结束的时候停止服务 + server->stop(); + delete ui; +} + +bool frmTcpServer::eventFilter(QObject *watched, QEvent *event) +{ + //双击清空 + if (watched == ui->txtMain->viewport()) { + if (event->type() == QEvent::MouseButtonDblClick) { + on_btnClear_clicked(); + } + } + + return QWidget::eventFilter(watched, event); +} + +void frmTcpServer::initForm() +{ + QFont font; + font.setPixelSize(16); + ui->txtMain->setFont(font); + ui->txtMain->viewport()->installEventFilter(this); + + isOk = false; + + //实例化对象并绑定信号槽 + server = new TcpServer(this); + connect(server, SIGNAL(connected(QString, int)), this, SLOT(connected(QString, int))); + connect(server, SIGNAL(disconnected(QString, int)), this, SLOT(disconnected(QString, int))); + connect(server, SIGNAL(error(QString, int, QString)), this, SLOT(error(QString, int, QString))); + connect(server, SIGNAL(sendData(QString, int, QString)), this, SLOT(sendData(QString, int, QString))); + connect(server, SIGNAL(receiveData(QString, int, QString)), this, SLOT(receiveData(QString, int, QString))); + + //定时器发送数据 + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(on_btnSend_clicked())); + + //填充数据到下拉框 + ui->cboxInterval->addItems(AppData::Intervals); + ui->cboxData->addItems(AppData::Datas); + AppData::loadIP(ui->cboxListenIP); +} + +void frmTcpServer::initConfig() +{ + ui->ckHexSend->setChecked(AppConfig::HexSendTcpServer); + connect(ui->ckHexSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexReceive->setChecked(AppConfig::HexReceiveTcpServer); + connect(ui->ckHexReceive, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAscii->setChecked(AppConfig::AsciiTcpServer); + connect(ui->ckAscii, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckDebug->setChecked(AppConfig::DebugTcpServer); + connect(ui->ckDebug, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSend->setChecked(AppConfig::AutoSendTcpServer); + connect(ui->ckAutoSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->cboxInterval->setCurrentIndex(ui->cboxInterval->findText(QString::number(AppConfig::IntervalTcpServer))); + connect(ui->cboxInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->cboxListenIP->setCurrentIndex(ui->cboxListenIP->findText(AppConfig::TcpListenIP)); + connect(ui->cboxListenIP, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->txtListenPort->setText(QString::number(AppConfig::TcpListenPort)); + connect(ui->txtListenPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->ckSelectAll->setChecked(AppConfig::SelectAllTcpServer); + connect(ui->ckSelectAll, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + this->initTimer(); +} + +void frmTcpServer::saveConfig() +{ + AppConfig::HexSendTcpServer = ui->ckHexSend->isChecked(); + AppConfig::HexReceiveTcpServer = ui->ckHexReceive->isChecked(); + AppConfig::AsciiTcpServer = ui->ckAscii->isChecked(); + AppConfig::DebugTcpServer = ui->ckDebug->isChecked(); + AppConfig::AutoSendTcpServer = ui->ckAutoSend->isChecked(); + AppConfig::IntervalTcpServer = ui->cboxInterval->currentText().toInt(); + AppConfig::TcpListenIP = ui->cboxListenIP->currentText(); + AppConfig::TcpListenPort = ui->txtListenPort->text().trimmed().toInt(); + AppConfig::SelectAllTcpServer = ui->ckSelectAll->isChecked(); + AppConfig::writeConfig(); + + this->initTimer(); +} + +void frmTcpServer::initTimer() +{ + if (timer->interval() != AppConfig::IntervalTcpServer) { + timer->setInterval(AppConfig::IntervalTcpServer); + } + + if (AppConfig::AutoSendTcpServer) { + if (!timer->isActive()) { + timer->start(); + } + } else { + if (timer->isActive()) { + timer->stop(); + } + } +} + +void frmTcpServer::append(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain, type, data, maxCount, currentCount, clear, ui->ckShow->isChecked()); +} + +void frmTcpServer::connected(const QString &ip, int port) +{ + append(2, QString("[%1:%2] %3").arg(ip).arg(port).arg("客户端上线")); + + QString str = QString("%1:%2").arg(ip).arg(port); + ui->listWidget->addItem(str); + ui->labCount->setText(QString("共 %1 个客户端").arg(ui->listWidget->count())); +} + +void frmTcpServer::disconnected(const QString &ip, int port) +{ + append(2, QString("[%1:%2] %3").arg(ip).arg(port).arg("客户端下线")); + + int row = -1; + QString str = QString("%1:%2").arg(ip).arg(port); + for (int i = 0; i < ui->listWidget->count(); i++) { + if (ui->listWidget->item(i)->text() == str) { + row = i; + break; + } + } + + delete ui->listWidget->takeItem(row); + ui->labCount->setText(QString("共 %1 个客户端").arg(ui->listWidget->count())); +} + +void frmTcpServer::error(const QString &ip, int port, const QString &error) +{ + append(3, QString("[%1:%2] %3").arg(ip).arg(port).arg(error)); +} + +void frmTcpServer::sendData(const QString &ip, int port, const QString &data) +{ + append(0, QString("[%1:%2] %3").arg(ip).arg(port).arg(data)); +} + +void frmTcpServer::receiveData(const QString &ip, int port, const QString &data) +{ + append(1, QString("[%1:%2] %3").arg(ip).arg(port).arg(data)); +} + +void frmTcpServer::on_btnListen_clicked() +{ + if (ui->btnListen->text() == "监听") { + isOk = server->start(); + if (isOk) { + append(2, "监听成功"); + ui->btnListen->setText("关闭"); + } else { + append(3, QString("监听失败: %1").arg(server->errorString())); + } + } else { + isOk = false; + server->stop(); + ui->btnListen->setText("监听"); + } +} + +void frmTcpServer::on_btnSave_clicked() +{ + QString data = ui->txtMain->toPlainText(); + AppData::saveData(data); + on_btnClear_clicked(); +} + +void frmTcpServer::on_btnClear_clicked() +{ + append(0, "", true); +} + +void frmTcpServer::on_btnSend_clicked() +{ + if (!isOk) { + return; + } + + QString data = ui->cboxData->currentText(); + if (data.length() <= 0) { + return; + } + + if (ui->ckSelectAll->isChecked()) { + server->writeData(data); + } else { + int row = ui->listWidget->currentRow(); + if (row >= 0) { + QString str = ui->listWidget->item(row)->text(); + QStringList list = str.split(":"); + server->writeData(list.at(0), list.at(1).toInt(), data); + } + } +} + +void frmTcpServer::on_btnRemove_clicked() +{ + if (ui->ckSelectAll->isChecked()) { + server->remove(); + } else { + int row = ui->listWidget->currentRow(); + if (row >= 0) { + QString str = ui->listWidget->item(row)->text(); + QStringList list = str.split(":"); + server->remove(list.at(0), list.at(1).toInt()); + } + } +} diff --git a/tool/nettool/form/frmtcpserver.h b/tool/nettool/form/frmtcpserver.h new file mode 100644 index 0000000..276e856 --- /dev/null +++ b/tool/nettool/form/frmtcpserver.h @@ -0,0 +1,52 @@ +#ifndef FRMTCPSERVER_H +#define FRMTCPSERVER_H + +#include +#include "tcpserver.h" + +namespace Ui { +class frmTcpServer; +} + +class frmTcpServer : public QWidget +{ + Q_OBJECT + +public: + explicit frmTcpServer(QWidget *parent = 0); + ~frmTcpServer(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + Ui::frmTcpServer *ui; + + bool isOk; + TcpServer *server; + QTimer *timer; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); + void initTimer(); + void append(int type, const QString &data, bool clear = false); + +private slots: + void connected(const QString &ip, int port); + void disconnected(const QString &ip, int port); + void error(const QString &ip, int port, const QString &error); + + void sendData(const QString &ip, int port, const QString &data); + void receiveData(const QString &ip, int port, const QString &data); + +private slots: + void on_btnListen_clicked(); + void on_btnSave_clicked(); + void on_btnClear_clicked(); + void on_btnSend_clicked(); + void on_btnRemove_clicked(); +}; + +#endif // FRMTCPSERVER_H diff --git a/tool/nettool/form/frmtcpserver.ui b/tool/nettool/form/frmtcpserver.ui new file mode 100644 index 0000000..cc9bdb5 --- /dev/null +++ b/tool/nettool/form/frmtcpserver.ui @@ -0,0 +1,271 @@ + + + frmTcpServer + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 170 + 0 + + + + + 170 + 16777215 + + + + QFrame::Box + + + QFrame::Sunken + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 16进制接收 + + + + + + + 16进制发送 + + + + + + + 控制字符 + + + + + + + 暂停显示 + + + + + + + 模拟设备 + + + + + + + 定时发送 + + + + + + + + + + 监听地址 + + + + + + + + + + 监听端口 + + + + + + + + + + 监听 + + + + + + + 保存 + + + + + + + 清空 + + + + + + + 移除 + + + + + + + + 0 + 25 + + + + QFrame::Box + + + QFrame::Sunken + + + 共 0 个客户端 + + + Qt::AlignCenter + + + + + + + + + + 对所有客户端发送 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 发送 + + + + + + + + + + txtMain + cboxData + btnSend + ckHexReceive + ckHexSend + ckAscii + ckShow + ckDebug + ckAutoSend + cboxInterval + cboxListenIP + txtListenPort + btnListen + btnSave + btnClear + btnRemove + listWidget + ckSelectAll + + + + diff --git a/tool/nettool/form/frmudpclient.cpp b/tool/nettool/form/frmudpclient.cpp new file mode 100644 index 0000000..89ba991 --- /dev/null +++ b/tool/nettool/form/frmudpclient.cpp @@ -0,0 +1,222 @@ +#include "frmudpclient.h" +#include "ui_frmudpclient.h" +#include "qthelper.h" +#include "qthelperdata.h" + +frmUdpClient::frmUdpClient(QWidget *parent) : QWidget(parent), ui(new Ui::frmUdpClient) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); +} + +frmUdpClient::~frmUdpClient() +{ + delete ui; +} + +bool frmUdpClient::eventFilter(QObject *watched, QEvent *event) +{ + //双击清空 + if (watched == ui->txtMain->viewport()) { + if (event->type() == QEvent::MouseButtonDblClick) { + on_btnClear_clicked(); + } + } + + return QWidget::eventFilter(watched, event); +} + +void frmUdpClient::initForm() +{ + QFont font; + font.setPixelSize(16); + ui->txtMain->setFont(font); + ui->txtMain->viewport()->installEventFilter(this); + + //实例化对象并绑定信号槽 + socket = new QUdpSocket(this); + connect(socket, SIGNAL(readyRead()), this, SLOT(readData())); +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(error())); +#else + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error())); +#endif + + //定时器发送数据 + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(on_btnSend_clicked())); + + //填充数据到下拉框 + ui->cboxInterval->addItems(AppData::Intervals); + ui->cboxData->addItems(AppData::Datas); + AppData::loadIP(ui->cboxBindIP); +} + +void frmUdpClient::initConfig() +{ + ui->ckHexSend->setChecked(AppConfig::HexSendUdpClient); + connect(ui->ckHexSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexReceive->setChecked(AppConfig::HexReceiveUdpClient); + connect(ui->ckHexReceive, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAscii->setChecked(AppConfig::AsciiUdpClient); + connect(ui->ckAscii, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckDebug->setChecked(AppConfig::DebugUdpClient); + connect(ui->ckDebug, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSend->setChecked(AppConfig::AutoSendUdpClient); + connect(ui->ckAutoSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->cboxInterval->setCurrentIndex(ui->cboxInterval->findText(QString::number(AppConfig::IntervalUdpClient))); + connect(ui->cboxInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->cboxBindIP->setCurrentIndex(ui->cboxBindIP->findText(AppConfig::UdpBindIP)); + connect(ui->cboxBindIP, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->txtBindPort->setText(QString::number(AppConfig::UdpBindPort)); + connect(ui->txtBindPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtServerIP->setText(AppConfig::UdpServerIP); + connect(ui->txtServerIP, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtServerPort->setText(QString::number(AppConfig::UdpServerPort)); + connect(ui->txtServerPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + this->initTimer(); +} + +void frmUdpClient::saveConfig() +{ + AppConfig::HexSendUdpClient = ui->ckHexSend->isChecked(); + AppConfig::HexReceiveUdpClient = ui->ckHexReceive->isChecked(); + AppConfig::AsciiUdpClient = ui->ckAscii->isChecked(); + AppConfig::DebugUdpClient = ui->ckDebug->isChecked(); + AppConfig::AutoSendUdpClient = ui->ckAutoSend->isChecked(); + AppConfig::IntervalUdpClient = ui->cboxInterval->currentText().toInt(); + AppConfig::UdpBindIP = ui->cboxBindIP->currentText(); + AppConfig::UdpBindPort = ui->txtBindPort->text().trimmed().toInt(); + AppConfig::UdpServerIP = ui->txtServerIP->text().trimmed(); + AppConfig::UdpServerPort = ui->txtServerPort->text().trimmed().toInt(); + AppConfig::writeConfig(); + + this->initTimer(); +} + +void frmUdpClient::initTimer() +{ + if (timer->interval() != AppConfig::IntervalUdpClient) { + timer->setInterval(AppConfig::IntervalUdpClient); + } + + if (AppConfig::AutoSendUdpClient) { + if (!timer->isActive()) { + timer->start(); + } + } else { + if (timer->isActive()) { + timer->stop(); + } + } +} + +void frmUdpClient::append(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain, type, data, maxCount, currentCount, clear, ui->ckShow->isChecked()); +} + +void frmUdpClient::error() +{ + append(3, socket->errorString()); +} + +void frmUdpClient::readData() +{ + QHostAddress host; + quint16 port; + QByteArray data; + QString buffer; + + while (socket->hasPendingDatagrams()) { + data.resize(socket->pendingDatagramSize()); + socket->readDatagram(data.data(), data.size(), &host, &port); + + if (AppConfig::HexReceiveUdpClient) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else if (AppConfig::AsciiUdpClient) { + buffer = QtHelperData::byteArrayToAsciiStr(data); + } else { + buffer = QString(data); + } + + QString ip = host.toString(); + ip = ip.replace("::ffff:", ""); + if (ip.isEmpty()) { + continue; + } + + QString str = QString("[%1:%2] %3").arg(ip).arg(port).arg(buffer); + append(1, str); + + if (AppConfig::DebugUdpClient) { + int count = AppData::Keys.count(); + for (int i = 0; i < count; i++) { + if (AppData::Keys.at(i) == buffer) { + sendData(ip, port, AppData::Values.at(i)); + break; + } + } + } + } +} + +void frmUdpClient::sendData(const QString &ip, int port, const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexSendUdpClient) { + buffer = QtHelperData::hexStrToByteArray(data); + } else if (AppConfig::AsciiUdpClient) { + buffer = QtHelperData::asciiStrToByteArray(data); + } else { + buffer = data.toUtf8(); + } + + //绑定网卡和端口,没有绑定过才需要绑定 + //采用端口是否一样来判断是为了方便可以直接动态绑定切换端口 + if (socket->localPort() != AppConfig::UdpBindPort) { + socket->abort(); + socket->bind(QHostAddress(AppConfig::UdpBindIP), AppConfig::UdpBindPort); + } + + //指定地址和端口发送数据 + socket->writeDatagram(buffer, QHostAddress(ip), port); + + QString str = QString("[%1:%2] %3").arg(ip).arg(port).arg(data); + append(0, str); +} + +void frmUdpClient::on_btnSave_clicked() +{ + QString data = ui->txtMain->toPlainText(); + AppData::saveData(data); + on_btnClear_clicked(); +} + +void frmUdpClient::on_btnClear_clicked() +{ + append(0, "", true); +} + +void frmUdpClient::on_btnSend_clicked() +{ + QString data = ui->cboxData->currentText(); + if (data.length() <= 0) { + return; + } + + sendData(AppConfig::UdpServerIP, AppConfig::UdpServerPort, data); +} diff --git a/tool/nettool/form/frmudpclient.h b/tool/nettool/form/frmudpclient.h new file mode 100644 index 0000000..072b714 --- /dev/null +++ b/tool/nettool/form/frmudpclient.h @@ -0,0 +1,46 @@ +#ifndef FRMUDPCLIENT_H +#define FRMUDPCLIENT_H + +#include +#include + +namespace Ui { +class frmUdpClient; +} + +class frmUdpClient : public QWidget +{ + Q_OBJECT + +public: + explicit frmUdpClient(QWidget *parent = 0); + ~frmUdpClient(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + Ui::frmUdpClient *ui; + + QUdpSocket *socket; + QTimer *timer; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); + void initTimer(); + void append(int type, const QString &data, bool clear = false); + +private slots: + void error(); + void readData(); + void sendData(const QString &ip, int port, const QString &data); + +private slots: + void on_btnSave_clicked(); + void on_btnClear_clicked(); + void on_btnSend_clicked(); +}; + +#endif // FRMUDPCLIENT_H diff --git a/tool/nettool/form/frmudpclient.ui b/tool/nettool/form/frmudpclient.ui new file mode 100644 index 0000000..360a19e --- /dev/null +++ b/tool/nettool/form/frmudpclient.ui @@ -0,0 +1,256 @@ + + + frmUdpClient + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 170 + 0 + + + + + 170 + 16777215 + + + + QFrame::Box + + + QFrame::Sunken + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 16进制接收 + + + + + + + 16进制发送 + + + + + + + 控制字符 + + + + + + + 暂停显示 + + + + + + + 模拟设备 + + + + + + + 定时发送 + + + + + + + + + + 绑定地址 + + + + + + + + + + 绑定端口 + + + + + + + + + + 服务器地址 + + + + + + + + + + 服务器端口 + + + + + + + + + + 保存 + + + + + + + 清空 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 发送 + + + + + + + + + + txtMain + cboxData + btnSend + ckHexReceive + ckHexSend + ckAscii + ckShow + ckDebug + ckAutoSend + cboxInterval + cboxBindIP + txtBindPort + txtServerIP + txtServerPort + btnSave + btnClear + + + + diff --git a/tool/nettool/form/frmudpserver.cpp b/tool/nettool/form/frmudpserver.cpp new file mode 100644 index 0000000..cbecfc2 --- /dev/null +++ b/tool/nettool/form/frmudpserver.cpp @@ -0,0 +1,265 @@ +#include "frmudpserver.h" +#include "ui_frmudpserver.h" +#include "qthelper.h" +#include "qthelperdata.h" + +frmUdpServer::frmUdpServer(QWidget *parent) : QWidget(parent), ui(new Ui::frmUdpServer) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); + on_btnListen_clicked(); +} + +frmUdpServer::~frmUdpServer() +{ + delete ui; +} + +bool frmUdpServer::eventFilter(QObject *watched, QEvent *event) +{ + //双击清空 + if (watched == ui->txtMain->viewport()) { + if (event->type() == QEvent::MouseButtonDblClick) { + on_btnClear_clicked(); + } + } + + return QWidget::eventFilter(watched, event); +} + +void frmUdpServer::initForm() +{ + QFont font; + font.setPixelSize(16); + ui->txtMain->setFont(font); + ui->txtMain->viewport()->installEventFilter(this); + + //实例化对象并绑定信号槽 + socket = new QUdpSocket(this); + connect(socket, SIGNAL(readyRead()), this, SLOT(readData())); +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(error())); +#else + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error())); +#endif + + //定时器发送数据 + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(on_btnSend_clicked())); + + //填充数据到下拉框 + ui->cboxInterval->addItems(AppData::Intervals); + ui->cboxData->addItems(AppData::Datas); + AppData::loadIP(ui->cboxListenIP); +} + +void frmUdpServer::initConfig() +{ + ui->ckHexSend->setChecked(AppConfig::HexSendUdpServer); + connect(ui->ckHexSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexReceive->setChecked(AppConfig::HexReceiveUdpServer); + connect(ui->ckHexReceive, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAscii->setChecked(AppConfig::AsciiUdpServer); + connect(ui->ckAscii, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckDebug->setChecked(AppConfig::DebugUdpServer); + connect(ui->ckDebug, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSend->setChecked(AppConfig::AutoSendUdpServer); + connect(ui->ckAutoSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->cboxInterval->setCurrentIndex(ui->cboxInterval->findText(QString::number(AppConfig::IntervalUdpServer))); + connect(ui->cboxInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->cboxListenIP->setCurrentIndex(ui->cboxListenIP->findText(AppConfig::UdpListenIP)); + connect(ui->cboxListenIP, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->txtListenPort->setText(QString::number(AppConfig::UdpListenPort)); + connect(ui->txtListenPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->ckSelectAll->setChecked(AppConfig::SelectAllUdpServer); + connect(ui->ckSelectAll, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + this->initTimer(); +} + +void frmUdpServer::saveConfig() +{ + AppConfig::HexSendUdpServer = ui->ckHexSend->isChecked(); + AppConfig::HexReceiveUdpServer = ui->ckHexReceive->isChecked(); + AppConfig::AsciiUdpServer = ui->ckAscii->isChecked(); + AppConfig::DebugUdpServer = ui->ckDebug->isChecked(); + AppConfig::AutoSendUdpServer = ui->ckAutoSend->isChecked(); + AppConfig::IntervalUdpServer = ui->cboxInterval->currentText().toInt(); + AppConfig::UdpListenIP = ui->cboxListenIP->currentText(); + AppConfig::UdpListenPort = ui->txtListenPort->text().trimmed().toInt(); + AppConfig::SelectAllUdpServer = ui->ckSelectAll->isChecked(); + AppConfig::writeConfig(); + + this->initTimer(); +} + +void frmUdpServer::initTimer() +{ + if (timer->interval() != AppConfig::IntervalUdpServer) { + timer->setInterval(AppConfig::IntervalUdpServer); + } + + if (AppConfig::AutoSendUdpServer) { + if (!timer->isActive()) { + timer->start(); + } + } else { + if (timer->isActive()) { + timer->stop(); + } + } +} + +void frmUdpServer::append(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain, type, data, maxCount, currentCount, clear, ui->ckShow->isChecked()); +} + +void frmUdpServer::error() +{ + append(3, socket->errorString()); +} + +void frmUdpServer::readData() +{ + QHostAddress host; + quint16 port; + QByteArray data; + QString buffer; + + while (socket->hasPendingDatagrams()) { + data.resize(socket->pendingDatagramSize()); + socket->readDatagram(data.data(), data.size(), &host, &port); + + if (AppConfig::HexReceiveUdpServer) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else if (AppConfig::AsciiUdpServer) { + buffer = QtHelperData::byteArrayToAsciiStr(data); + } else { + buffer = QString(data); + } + + QString ip = host.toString(); + ip = ip.replace("::ffff:", ""); + if (ip.isEmpty()) { + continue; + } + + QString str = QString("[%1:%2] %3").arg(ip).arg(port).arg(buffer); + append(1, str); + + //先过滤重复的 + str = QString("%1:%2").arg(ip).arg(port); + for (int i = 0; i < ui->listWidget->count(); i++) { + QString s = ui->listWidget->item(i)->text(); + if (str == s) { + return; + } + } + + //添加到列表 + ui->listWidget->addItem(str); + ui->labCount->setText(QString("共 %1 个客户端").arg(ui->listWidget->count())); + + if (AppConfig::DebugUdpServer) { + int count = AppData::Keys.count(); + for (int i = 0; i < count; i++) { + if (AppData::Keys.at(i) == buffer) { + sendData(ip, port, AppData::Values.at(i)); + break; + } + } + } + } +} + +void frmUdpServer::sendData(const QString &ip, int port, const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexSendUdpServer) { + buffer = QtHelperData::hexStrToByteArray(data); + } else if (AppConfig::AsciiUdpServer) { + buffer = QtHelperData::asciiStrToByteArray(data); + } else { + buffer = data.toUtf8(); + } + + socket->writeDatagram(buffer, QHostAddress(ip), port); + + QString str = QString("[%1:%2] %3").arg(ip).arg(port).arg(data); + append(0, str); +} + +void frmUdpServer::on_btnListen_clicked() +{ + if (ui->btnListen->text() == "监听") { + bool ok = socket->bind(QHostAddress(AppConfig::UdpListenIP), AppConfig::UdpListenPort); + if (ok) { + append(2, "监听成功"); + ui->btnListen->setText("关闭"); + } else { + append(3, QString("监听失败: %1").arg(socket->errorString())); + } + } else { + socket->abort(); + ui->btnListen->setText("监听"); + } +} + +void frmUdpServer::on_btnSave_clicked() +{ + QString data = ui->txtMain->toPlainText(); + AppData::saveData(data); + on_btnClear_clicked(); +} + +void frmUdpServer::on_btnClear_clicked() +{ + append(0, "", true); +} + +void frmUdpServer::on_btnSend_clicked() +{ + QString data = ui->cboxData->currentText(); + if (data.length() <= 0) { + return; + } + + if (ui->ckSelectAll->isChecked()) { + for (int i = 0; i < ui->listWidget->count(); i++) { + QString str = ui->listWidget->item(i)->text(); + QStringList list = str.split(":"); + sendData(list.at(0), list.at(1).toInt(), data); + } + } else { + int row = ui->listWidget->currentRow(); + if (row >= 0) { + QString str = ui->listWidget->item(row)->text(); + QStringList list = str.split(":"); + sendData(list.at(0), list.at(1).toInt(), data); + } + } +} + +void frmUdpServer::on_btnRemove_clicked() +{ + if (ui->ckSelectAll->isChecked()) { + ui->listWidget->clear(); + } else { + int row = ui->listWidget->currentRow(); + if (row >= 0) { + delete ui->listWidget->takeItem(row); + } + } +} diff --git a/tool/nettool/form/frmudpserver.h b/tool/nettool/form/frmudpserver.h new file mode 100644 index 0000000..c851b3c --- /dev/null +++ b/tool/nettool/form/frmudpserver.h @@ -0,0 +1,48 @@ +#ifndef FRMUDPSERVER_H +#define FRMUDPSERVER_H + +#include +#include + +namespace Ui { +class frmUdpServer; +} + +class frmUdpServer : public QWidget +{ + Q_OBJECT + +public: + explicit frmUdpServer(QWidget *parent = 0); + ~frmUdpServer(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + Ui::frmUdpServer *ui; + + QUdpSocket *socket; + QTimer *timer; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); + void initTimer(); + void append(int type, const QString &data, bool clear = false); + +private slots: + void error(); + void readData(); + void sendData(const QString &ip, int port, const QString &data); + +private slots: + void on_btnListen_clicked(); + void on_btnSave_clicked(); + void on_btnClear_clicked(); + void on_btnSend_clicked(); + void on_btnRemove_clicked(); +}; + +#endif // FRMUDPSERVER_H diff --git a/tool/nettool/form/frmudpserver.ui b/tool/nettool/form/frmudpserver.ui new file mode 100644 index 0000000..c686cf2 --- /dev/null +++ b/tool/nettool/form/frmudpserver.ui @@ -0,0 +1,270 @@ + + + frmUdpServer + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 170 + 0 + + + + + 170 + 16777215 + + + + QFrame::Box + + + QFrame::Sunken + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 16进制接收 + + + + + + + 16进制发送 + + + + + + + 控制字符 + + + + + + + 暂停显示 + + + + + + + 模拟设备 + + + + + + + 定时发送 + + + + + + + + + + 监听地址 + + + + + + + + + + 监听端口 + + + + + + + + + + 监听 + + + + + + + 保存 + + + + + + + 清空 + + + + + + + 移除 + + + + + + + + 0 + 25 + + + + QFrame::Box + + + QFrame::Sunken + + + 共 0 个客户端 + + + Qt::AlignCenter + + + + + + + + + + 对所有客户端发送 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 发送 + + + + + + + + + + txtMain + cboxData + btnSend + ckHexReceive + ckHexSend + ckAscii + ckShow + ckDebug + ckAutoSend + cboxInterval + cboxListenIP + txtListenPort + btnListen + btnSave + btnClear + listWidget + ckSelectAll + + + + diff --git a/tool/nettool/form/frmwebclient.cpp b/tool/nettool/form/frmwebclient.cpp new file mode 100644 index 0000000..c731011 --- /dev/null +++ b/tool/nettool/form/frmwebclient.cpp @@ -0,0 +1,242 @@ +#include "frmwebclient.h" +#include "ui_frmwebclient.h" +#include "qthelper.h" +#include "qthelperdata.h" + +frmWebClient::frmWebClient(QWidget *parent) : QWidget(parent), ui(new Ui::frmWebClient) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); +} + +frmWebClient::~frmWebClient() +{ + delete ui; +} + +bool frmWebClient::eventFilter(QObject *watched, QEvent *event) +{ + //双击清空 + if (watched == ui->txtMain->viewport()) { + if (event->type() == QEvent::MouseButtonDblClick) { + on_btnClear_clicked(); + } + } + + return QWidget::eventFilter(watched, event); +} + +void frmWebClient::initForm() +{ + QFont font; + font.setPixelSize(16); + ui->txtMain->setFont(font); + ui->txtMain->viewport()->installEventFilter(this); + + isOk = false; + + //实例化对象并绑定信号槽 + socket = new QWebSocket("WebSocket", QWebSocketProtocol::VersionLatest, this); + connect(socket, SIGNAL(connected()), this, SLOT(connected())); + connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error())); + + //暂时使用前面两个信号,部分系统上后面两个信号Qt没实现,目前测试到5.15.2 + //在win上如果两组信号都关联了则都会触发,另外一组信号就是多个参数表示是否是最后一个数据包 + connect(socket, SIGNAL(textMessageReceived(QString)), this, SLOT(textMessageReceived(QString))); + connect(socket, SIGNAL(binaryMessageReceived(QByteArray)), this, SLOT(binaryMessageReceived(QByteArray))); + //connect(socket, SIGNAL(textFrameReceived(QString, bool)), this, SLOT(textFrameReceived(QString, bool))); + //connect(socket, SIGNAL(binaryFrameReceived(QByteArray, bool)), this, SLOT(binaryFrameReceived(QByteArray, bool))); + + //定时器发送数据 + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(on_btnSend_clicked())); + + //填充数据到下拉框 + ui->cboxInterval->addItems(AppData::Intervals); + ui->cboxData->addItems(AppData::Datas); +} + +void frmWebClient::initConfig() +{ + ui->ckHexSend->setChecked(AppConfig::HexSendWebClient); + connect(ui->ckHexSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexReceive->setChecked(AppConfig::HexReceiveWebClient); + connect(ui->ckHexReceive, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAscii->setChecked(AppConfig::AsciiWebClient); + connect(ui->ckAscii, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckDebug->setChecked(AppConfig::DebugWebClient); + connect(ui->ckDebug, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSend->setChecked(AppConfig::AutoSendWebClient); + connect(ui->ckAutoSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->cboxInterval->setCurrentIndex(ui->cboxInterval->findText(QString::number(AppConfig::IntervalWebClient))); + connect(ui->cboxInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->txtServerIP->setText(AppConfig::WebServerIP); + connect(ui->txtServerIP, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->txtServerPort->setText(QString::number(AppConfig::WebServerPort)); + connect(ui->txtServerPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + this->initTimer(); +} + +void frmWebClient::saveConfig() +{ + AppConfig::HexSendWebClient = ui->ckHexSend->isChecked(); + AppConfig::HexReceiveWebClient = ui->ckHexReceive->isChecked(); + AppConfig::AsciiWebClient = ui->ckAscii->isChecked(); + AppConfig::DebugWebClient = ui->ckDebug->isChecked(); + AppConfig::AutoSendWebClient = ui->ckAutoSend->isChecked(); + AppConfig::IntervalWebClient = ui->cboxInterval->currentText().toInt(); + AppConfig::WebServerIP = ui->txtServerIP->text().trimmed(); + AppConfig::WebServerPort = ui->txtServerPort->text().trimmed().toInt(); + AppConfig::writeConfig(); + + this->initTimer(); +} + +void frmWebClient::initTimer() +{ + if (timer->interval() != AppConfig::IntervalWebClient) { + timer->setInterval(AppConfig::IntervalWebClient); + } + + if (AppConfig::AutoSendWebClient) { + if (!timer->isActive()) { + timer->start(); + } + } else { + if (timer->isActive()) { + timer->stop(); + } + } +} + +void frmWebClient::append(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain, type, data, maxCount, currentCount, clear, ui->ckShow->isChecked()); +} + +void frmWebClient::connected() +{ + isOk = true; + ui->btnConnect->setText("断开"); + append(2, "服务器连接"); + append(4, QString("本地地址: %1 本地端口: %2").arg(socket->localAddress().toString()).arg(socket->localPort())); + append(4, QString("远程地址: %1 远程端口: %2").arg(socket->peerAddress().toString()).arg(socket->peerPort())); +} + +void frmWebClient::disconnected() +{ + isOk = false; + ui->btnConnect->setText("连接"); + append(2, "服务器断开"); +} + +void frmWebClient::error() +{ + append(4, socket->errorString()); +} + +void frmWebClient::sendData(const QString &data) +{ + QByteArray buffer; + if (AppConfig::HexSendWebClient) { + buffer = QtHelperData::hexStrToByteArray(data); + } else { + buffer = data.toUtf8(); + } + + if (AppConfig::AsciiWebClient) { + socket->sendTextMessage(data); + } else { + socket->sendBinaryMessage(buffer); + } + + append(0, data); +} + +void frmWebClient::textFrameReceived(const QString &data, bool isLastFrame) +{ + QString buffer = data; + append(1, buffer); + + //自动回复数据,可以回复的数据是以;隔开,每行可以带多个;所以这里不需要继续判断 + if (AppConfig::DebugWebClient) { + int count = AppData::Keys.count(); + for (int i = 0; i < count; i++) { + if (AppData::Keys.at(i) == buffer) { + sendData(AppData::Values.at(i)); + break; + } + } + } +} + +void frmWebClient::binaryFrameReceived(const QByteArray &data, bool isLastFrame) +{ + QString buffer; + if (AppConfig::HexReceiveWebClient) { + buffer = QtHelperData::byteArrayToHexStr(data); + } else { + buffer = QString(data); + } + + textFrameReceived(buffer, isLastFrame); +} + +void frmWebClient::textMessageReceived(const QString &data) +{ + textFrameReceived(data, true); +} + +void frmWebClient::binaryMessageReceived(const QByteArray &data) +{ + binaryFrameReceived(data, true); +} + +void frmWebClient::on_btnConnect_clicked() +{ + if (ui->btnConnect->text() == "连接") { + QString url = QString("%1:%2").arg(AppConfig::WebServerIP).arg(AppConfig::WebServerPort); + socket->abort(); + socket->open(QUrl(url)); + } else { + socket->abort(); + } +} + +void frmWebClient::on_btnSave_clicked() +{ + QString data = ui->txtMain->toPlainText(); + AppData::saveData(data); + on_btnClear_clicked(); +} + +void frmWebClient::on_btnClear_clicked() +{ + append(0, "", true); +} + +void frmWebClient::on_btnSend_clicked() +{ + if (!isOk) { + return; + } + + QString data = ui->cboxData->currentText(); + if (data.length() <= 0) { + return; + } + + sendData(data); +} diff --git a/tool/nettool/form/frmwebclient.h b/tool/nettool/form/frmwebclient.h new file mode 100644 index 0000000..a6e617e --- /dev/null +++ b/tool/nettool/form/frmwebclient.h @@ -0,0 +1,54 @@ +#ifndef FRMWEBCLIENT_H +#define FRMWEBCLIENT_H + +#include +#include + +namespace Ui { +class frmWebClient; +} + +class frmWebClient : public QWidget +{ + Q_OBJECT + +public: + explicit frmWebClient(QWidget *parent = 0); + ~frmWebClient(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + Ui::frmWebClient *ui; + + bool isOk; + QWebSocket *socket; + QTimer *timer; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); + void initTimer(); + void append(int type, const QString &data, bool clear = false); + +private slots: + void connected(); + void disconnected(); + void error(); + void sendData(const QString &data); + + void textFrameReceived(const QString &data, bool isLastFrame); + void binaryFrameReceived(const QByteArray &data, bool isLastFrame); + void textMessageReceived(const QString &data); + void binaryMessageReceived(const QByteArray &data); + +private slots: + void on_btnConnect_clicked(); + void on_btnSave_clicked(); + void on_btnClear_clicked(); + void on_btnSend_clicked(); +}; + +#endif // FRMWEBCLIENT_H diff --git a/tool/nettool/form/frmwebclient.ui b/tool/nettool/form/frmwebclient.ui new file mode 100644 index 0000000..6ce3ab0 --- /dev/null +++ b/tool/nettool/form/frmwebclient.ui @@ -0,0 +1,225 @@ + + + frmWebClient + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 170 + 0 + + + + + 170 + 16777215 + + + + QFrame::Box + + + QFrame::Sunken + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 16进制接收 + + + + + + + 16进制发送 + + + + + + + 文本字符 + + + + + + + 暂停显示 + + + + + + + 模拟设备 + + + + + + + 定时发送 + + + + + + + + + + 服务器地址 + + + + + + + + + + 服务器端口 + + + + + + + + + + 连接 + + + + + + + 保存 + + + + + + + 清空 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 发送 + + + + + + + + + + + diff --git a/tool/nettool/form/frmwebserver.cpp b/tool/nettool/form/frmwebserver.cpp new file mode 100644 index 0000000..433d183 --- /dev/null +++ b/tool/nettool/form/frmwebserver.cpp @@ -0,0 +1,234 @@ +#include "frmwebserver.h" +#include "ui_frmwebserver.h" +#include "qthelper.h" + +frmWebServer::frmWebServer(QWidget *parent) : QWidget(parent), ui(new Ui::frmWebServer) +{ + ui->setupUi(this); + this->initForm(); + this->initConfig(); + on_btnListen_clicked(); +} + +frmWebServer::~frmWebServer() +{ + delete ui; +} + +bool frmWebServer::eventFilter(QObject *watched, QEvent *event) +{ + //双击清空 + if (watched == ui->txtMain->viewport()) { + if (event->type() == QEvent::MouseButtonDblClick) { + on_btnClear_clicked(); + } + } + + return QWidget::eventFilter(watched, event); +} + +void frmWebServer::initForm() +{ + QFont font; + font.setPixelSize(16); + ui->txtMain->setFont(font); + ui->txtMain->viewport()->installEventFilter(this); + + isOk = false; + + //实例化对象并绑定信号槽 + server = new WebServer("WebServer", QWebSocketServer::NonSecureMode, this); + connect(server, SIGNAL(connected(QString, int)), this, SLOT(connected(QString, int))); + connect(server, SIGNAL(disconnected(QString, int)), this, SLOT(disconnected(QString, int))); + connect(server, SIGNAL(error(QString, int, QString)), this, SLOT(error(QString, int, QString))); + connect(server, SIGNAL(sendData(QString, int, QString)), this, SLOT(sendData(QString, int, QString))); + connect(server, SIGNAL(receiveData(QString, int, QString)), this, SLOT(receiveData(QString, int, QString))); + + //定时器发送数据 + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(on_btnSend_clicked())); + + //填充数据到下拉框 + ui->cboxInterval->addItems(AppData::Intervals); + ui->cboxData->addItems(AppData::Datas); + AppData::loadIP(ui->cboxListenIP); +} + +void frmWebServer::initConfig() +{ + ui->ckHexSend->setChecked(AppConfig::HexSendWebServer); + connect(ui->ckHexSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckHexReceive->setChecked(AppConfig::HexReceiveWebServer); + connect(ui->ckHexReceive, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAscii->setChecked(AppConfig::AsciiWebServer); + connect(ui->ckAscii, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckDebug->setChecked(AppConfig::DebugWebServer); + connect(ui->ckDebug, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->ckAutoSend->setChecked(AppConfig::AutoSendWebServer); + connect(ui->ckAutoSend, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + ui->cboxInterval->setCurrentIndex(ui->cboxInterval->findText(QString::number(AppConfig::IntervalWebServer))); + connect(ui->cboxInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->cboxListenIP->setCurrentIndex(ui->cboxListenIP->findText(AppConfig::WebListenIP)); + connect(ui->cboxListenIP, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig())); + + ui->txtListenPort->setText(QString::number(AppConfig::WebListenPort)); + connect(ui->txtListenPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig())); + + ui->ckSelectAll->setChecked(AppConfig::SelectAllWebServer); + connect(ui->ckSelectAll, SIGNAL(stateChanged(int)), this, SLOT(saveConfig())); + + this->initTimer(); +} + +void frmWebServer::saveConfig() +{ + AppConfig::HexSendWebServer = ui->ckHexSend->isChecked(); + AppConfig::HexReceiveWebServer = ui->ckHexReceive->isChecked(); + AppConfig::AsciiWebServer = ui->ckAscii->isChecked(); + AppConfig::DebugWebServer = ui->ckDebug->isChecked(); + AppConfig::AutoSendWebServer = ui->ckAutoSend->isChecked(); + AppConfig::IntervalWebServer = ui->cboxInterval->currentText().toInt(); + AppConfig::WebListenIP = ui->cboxListenIP->currentText(); + AppConfig::WebListenPort = ui->txtListenPort->text().trimmed().toInt(); + AppConfig::SelectAllWebServer = ui->ckSelectAll->isChecked(); + AppConfig::writeConfig(); + + this->initTimer(); +} + +void frmWebServer::initTimer() +{ + if (timer->interval() != AppConfig::IntervalWebServer) { + timer->setInterval(AppConfig::IntervalWebServer); + } + + if (AppConfig::AutoSendWebServer) { + if (!timer->isActive()) { + timer->start(); + } + } else { + if (timer->isActive()) { + timer->stop(); + } + } +} + +void frmWebServer::append(int type, const QString &data, bool clear) +{ + static int currentCount = 0; + static int maxCount = 100; + QtHelper::appendMsg(ui->txtMain, type, data, maxCount, currentCount, clear, ui->ckShow->isChecked()); +} + +void frmWebServer::connected(const QString &ip, int port) +{ + append(2, QString("[%1:%2] %3").arg(ip).arg(port).arg("客户端上线")); + + QString str = QString("%1:%2").arg(ip).arg(port); + ui->listWidget->addItem(str); + ui->labCount->setText(QString("共 %1 个客户端").arg(ui->listWidget->count())); +} + +void frmWebServer::disconnected(const QString &ip, int port) +{ + append(2, QString("[%1:%2] %3").arg(ip).arg(port).arg("客户端下线")); + + int row = -1; + QString str = QString("%1:%2").arg(ip).arg(port); + for (int i = 0; i < ui->listWidget->count(); i++) { + if (ui->listWidget->item(i)->text() == str) { + row = i; + break; + } + } + + delete ui->listWidget->takeItem(row); + ui->labCount->setText(QString("共 %1 个客户端").arg(ui->listWidget->count())); +} + +void frmWebServer::error(const QString &ip, int port, const QString &error) +{ + append(4, QString("[%1:%2] %3").arg(ip).arg(port).arg(error)); +} + +void frmWebServer::sendData(const QString &ip, int port, const QString &data) +{ + append(0, QString("[%1:%2] %3").arg(ip).arg(port).arg(data)); +} + +void frmWebServer::receiveData(const QString &ip, int port, const QString &data) +{ + append(1, QString("[%1:%2] %3").arg(ip).arg(port).arg(data)); +} + +void frmWebServer::on_btnListen_clicked() +{ + if (ui->btnListen->text() == "监听") { + isOk = server->start(); + if (isOk) { + append(2, "监听成功"); + ui->btnListen->setText("关闭"); + } else { + append(3, QString("监听失败: %1").arg(server->errorString())); + } + } else { + isOk = false; + server->stop(); + ui->btnListen->setText("监听"); + } +} + +void frmWebServer::on_btnSave_clicked() +{ + QString data = ui->txtMain->toPlainText(); + AppData::saveData(data); + on_btnClear_clicked(); +} + +void frmWebServer::on_btnClear_clicked() +{ + append(0, "", true); +} + +void frmWebServer::on_btnSend_clicked() +{ + if (!isOk) { + return; + } + + QString data = ui->cboxData->currentText(); + if (data.length() <= 0) { + return; + } + + if (ui->ckSelectAll->isChecked()) { + server->writeData(data); + } else { + int row = ui->listWidget->currentRow(); + if (row >= 0) { + QString str = ui->listWidget->item(row)->text(); + QStringList list = str.split(":"); + server->writeData(list.at(0), list.at(1).toInt(), data); + } + } +} + +void frmWebServer::on_btnRemove_clicked() +{ + if (ui->ckSelectAll->isChecked()) { + server->remove(); + } else { + int row = ui->listWidget->currentRow(); + if (row >= 0) { + QString str = ui->listWidget->item(row)->text(); + QStringList list = str.split(":"); + server->remove(list.at(0), list.at(1).toInt()); + } + } +} diff --git a/tool/nettool/form/frmwebserver.h b/tool/nettool/form/frmwebserver.h new file mode 100644 index 0000000..15c19e5 --- /dev/null +++ b/tool/nettool/form/frmwebserver.h @@ -0,0 +1,52 @@ +#ifndef FRMWEBSERVER_H +#define FRMWEBSERVER_H + +#include +#include "webserver.h" + +namespace Ui { +class frmWebServer; +} + +class frmWebServer : public QWidget +{ + Q_OBJECT + +public: + explicit frmWebServer(QWidget *parent = 0); + ~frmWebServer(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + Ui::frmWebServer *ui; + + bool isOk; + WebServer *server; + QTimer *timer; + +private slots: + void initForm(); + void initConfig(); + void saveConfig(); + void initTimer(); + void append(int type, const QString &data, bool clear = false); + +private slots: + void connected(const QString &ip, int port); + void disconnected(const QString &ip, int port); + void error(const QString &ip, int port, const QString &error); + + void sendData(const QString &ip, int port, const QString &data); + void receiveData(const QString &ip, int port, const QString &data); + +private slots: + void on_btnListen_clicked(); + void on_btnSave_clicked(); + void on_btnClear_clicked(); + void on_btnSend_clicked(); + void on_btnRemove_clicked(); +}; + +#endif // FRMWEBSERVER_H diff --git a/tool/nettool/form/frmwebserver.ui b/tool/nettool/form/frmwebserver.ui new file mode 100644 index 0000000..61b0726 --- /dev/null +++ b/tool/nettool/form/frmwebserver.ui @@ -0,0 +1,271 @@ + + + frmWebServer + + + + 0 + 0 + 800 + 600 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + + + + + 170 + 0 + + + + + 170 + 16777215 + + + + QFrame::Box + + + QFrame::Sunken + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 16进制接收 + + + + + + + 16进制发送 + + + + + + + 文本字符 + + + + + + + 暂停显示 + + + + + + + 模拟设备 + + + + + + + 定时发送 + + + + + + + + + + 监听地址 + + + + + + + + + + 监听端口 + + + + + + + + + + 监听 + + + + + + + 保存 + + + + + + + 清空 + + + + + + + 移除 + + + + + + + + 0 + 25 + + + + QFrame::Box + + + QFrame::Sunken + + + 共 0 个客户端 + + + Qt::AlignCenter + + + + + + + + + + 对所有客户端发送 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 发送 + + + + + + + + + + txtMain + cboxData + btnSend + ckHexReceive + ckHexSend + ckAscii + ckShow + ckDebug + ckAutoSend + cboxInterval + cboxListenIP + txtListenPort + btnListen + btnSave + btnClear + btnRemove + listWidget + ckSelectAll + + + + diff --git a/tool/nettool/head.h b/tool/nettool/head.h new file mode 100644 index 0000000..0f655d6 --- /dev/null +++ b/tool/nettool/head.h @@ -0,0 +1,21 @@ +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) +#include +#ifdef websocket +#include +#endif +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +#include +#endif + +#pragma execution_character_set("utf-8") +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) +#define STRDATETIME qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")) + +#include "appconfig.h" +#include "appdata.h" diff --git a/tool/nettool/main.cpp b/tool/nettool/main.cpp new file mode 100644 index 0000000..a23f0a0 --- /dev/null +++ b/tool/nettool/main.cpp @@ -0,0 +1,34 @@ +#include "frmmain.h" +#include "qthelper.h" + +int main(int argc, char *argv[]) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) + QApplication::setAttribute(Qt::AA_Use96Dpi); +#endif +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor); +#endif + + QApplication a(argc, argv); + a.setWindowIcon(QIcon(":/main.ico")); + + //设置编码+字体+中文翻译文件 + QtHelper::initAll(); + + //读取配置文件 + AppConfig::ConfigFile = QString("%1/%2.ini").arg(QtHelper::appPath()).arg(QtHelper::appName()); + AppConfig::readConfig(); + + AppData::Intervals << "1" << "10" << "20" << "50" << "100" << "200" << "300" << "500" << "1000" << "1500" << "2000" << "3000" << "5000" << "10000"; + AppData::readSendData(); + AppData::readDeviceData(); + + frmMain w; + w.setWindowTitle("网络调试助手 V2023 (QQ: 517216493 WX: feiyangqingyun)"); + w.resize(950, 700); + QtHelper::setFormInCenter(&w); + w.show(); + + return a.exec(); +} diff --git a/tool/nettool/nettool.pro b/tool/nettool/nettool.pro new file mode 100644 index 0000000..1f9e7c4 --- /dev/null +++ b/tool/nettool/nettool.pro @@ -0,0 +1,31 @@ +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4) { +QT += widgets +#判断是否有websocket模块 +qtHaveModule(websockets) { +QT += websockets +DEFINES += websocket +}} + +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = nettool +TEMPLATE = app +RC_FILE = qrc/main.rc +wasm { +RESOURCES += qrc/font.qrc +} else { +DESTDIR = $$PWD/../bin +} + +HEADERS += head.h +SOURCES += main.cpp +RESOURCES += qrc/main.qrc +CONFIG += warn_off + +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD/api +INCLUDEPATH += $$PWD/form + +include ($$PWD/api/api.pri) +include ($$PWD/form/form.pri) diff --git a/tool/nettool/qrc/font.qrc b/tool/nettool/qrc/font.qrc new file mode 100644 index 0000000..1d77f67 --- /dev/null +++ b/tool/nettool/qrc/font.qrc @@ -0,0 +1,5 @@ + + + font/DroidSansFallback.ttf + + diff --git a/tool/nettool/qrc/font/DroidSansFallback.ttf b/tool/nettool/qrc/font/DroidSansFallback.ttf new file mode 100644 index 0000000..8c6fabe Binary files /dev/null and b/tool/nettool/qrc/font/DroidSansFallback.ttf differ diff --git a/tool/nettool/qrc/main.ico b/tool/nettool/qrc/main.ico new file mode 100644 index 0000000..fa39937 Binary files /dev/null and b/tool/nettool/qrc/main.ico differ diff --git a/tool/nettool/qrc/main.qrc b/tool/nettool/qrc/main.qrc new file mode 100644 index 0000000..8bd6284 --- /dev/null +++ b/tool/nettool/qrc/main.qrc @@ -0,0 +1,7 @@ + + + main.ico + qm/qt_zh_CN.qm + qm/widgets.qm + + diff --git a/tool/nettool/qrc/main.rc b/tool/nettool/qrc/main.rc new file mode 100644 index 0000000..fc0d770 --- /dev/null +++ b/tool/nettool/qrc/main.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "main.ico" \ No newline at end of file diff --git a/tool/nettool/qrc/qm/qt_zh_CN.qm b/tool/nettool/qrc/qm/qt_zh_CN.qm new file mode 100644 index 0000000..623b8e3 Binary files /dev/null and b/tool/nettool/qrc/qm/qt_zh_CN.qm differ diff --git a/tool/nettool/qrc/qm/widgets.qm b/tool/nettool/qrc/qm/widgets.qm new file mode 100644 index 0000000..244bf0d Binary files /dev/null and b/tool/nettool/qrc/qm/widgets.qm differ diff --git a/tool/nettool/readme.md b/tool/nettool/readme.md new file mode 100644 index 0000000..52d348c --- /dev/null +++ b/tool/nettool/readme.md @@ -0,0 +1,14 @@ +**基本功能** +1. 16进制数据和ASCII数据收发。 +2. 定时器自动发送。 +3. 自动从配置文件加载最后一次的界面设置。 +4. 自动从配置文件加载数据发送下拉框的数据。可以将经常使用的数据填写在send.txt中。 +5. 可启用设备模拟回复,当收到某个数据时,模拟设备自动回复数据。对应数据格式填写在device.txt中。 +6. 可对单个在线连接发送数据,也可勾选全部进行发送。 +7. 支持多个客户端连接并发。 +8. 采用单线程。 +9. 多种模式,tcp客户端、tcp服务器、udp客户端、udp服务器、websocket客户端、websocket服务器。 + +**其他说明** +1. 编译后请将源码下的file目录中的所有文件复制到可执行文件同一目录。 +2. 如果有更好的建议或者意见,请留言,谢谢! \ No newline at end of file diff --git a/tool/pngtool/frmpngtool.cpp b/tool/pngtool/frmpngtool.cpp new file mode 100644 index 0000000..4d6d5ef --- /dev/null +++ b/tool/pngtool/frmpngtool.cpp @@ -0,0 +1,78 @@ +#pragma execution_character_set("utf-8") +#include "frmpngtool.h" +#include "ui_frmpngtool.h" +#include "qfile.h" +#include "qfiledialog.h" +#include "qdatetime.h" +#include "qdebug.h" + +#define TIMEMS QTime::currentTime().toString("hh:mm:ss zzz") + +frmPngTool::frmPngTool(QWidget *parent) : QWidget(parent), ui(new Ui::frmPngTool) +{ + ui->setupUi(this); + ui->progress->setRange(0, 0); + ui->progress->setValue(0); +} + +frmPngTool::~frmPngTool() +{ + delete ui; +} + +void frmPngTool::on_btnFile_clicked() +{ + QString file = QFileDialog::getOpenFileName(this, "选择png文件", qApp->applicationDirPath(), "png图片文件(*.png)"); + if (!file.isEmpty()) { + ui->txtFile->setText(file); + ui->progress->setValue(0); + } +} + +void frmPngTool::on_btnDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, "选择目录"); + if (!dir.isEmpty()) { + ui->txtDir->setText(dir); + ui->progress->setValue(0); + } +} + +void frmPngTool::on_btnOk_clicked() +{ + files.clear(); + + //将单个文件加入队列 + QString currentFile = ui->txtFile->text().trimmed(); + if (!currentFile.isEmpty()) { + files.append(currentFile); + } + + //将该目录下的所有png文件存入链表 + QString currentDir = ui->txtDir->text().trimmed(); + if (!currentDir.isEmpty()) { + QDir imagePath(currentDir); + QStringList filter; + filter << "*.png"; + QStringList list = imagePath.entryList(filter); + foreach (QString str, list) { + files.append(currentDir + "/" + str); + } + } + + ui->progress->setRange(0, files.count()); + ui->progress->setValue(0); + + ui->txtMain->clear(); + int count = 0; + foreach (QString file, files) { + ui->txtMain->append(QString("%1 -> %2").arg(TIMEMS).arg(file)); + QImage image(file); + image.save(file, "png"); + count++; + ui->progress->setValue(count); + qApp->processEvents(); + } + + ui->txtMain->append(QString("%1 -> 处理完成, 共 %2 个文件").arg(TIMEMS).arg(files.count())); +} diff --git a/tool/pngtool/frmpngtool.h b/tool/pngtool/frmpngtool.h new file mode 100644 index 0000000..7214868 --- /dev/null +++ b/tool/pngtool/frmpngtool.h @@ -0,0 +1,28 @@ +#ifndef FRMPNGTOOL_H +#define FRMPNGTOOL_H + +#include + +namespace Ui { +class frmPngTool; +} + +class frmPngTool : public QWidget +{ + Q_OBJECT + +public: + explicit frmPngTool(QWidget *parent = 0); + ~frmPngTool(); + +private slots: + void on_btnFile_clicked(); + void on_btnDir_clicked(); + void on_btnOk_clicked(); + +private: + Ui::frmPngTool *ui; + QStringList files; +}; + +#endif // FRMPNGTOOL_H diff --git a/tool/pngtool/frmpngtool.ui b/tool/pngtool/frmpngtool.ui new file mode 100644 index 0000000..33344f1 --- /dev/null +++ b/tool/pngtool/frmpngtool.ui @@ -0,0 +1,61 @@ + + + frmPngTool + + + + 0 + 0 + 800 + 600 + + + + Form + + + + + + + + + 执行转换 + + + + + + + + + + 选择目录 + + + + + + + 选择文件 + + + + + + + 0 + + + Qt::AlignCenter + + + + + + + + + + + diff --git a/tool/pngtool/main.cpp b/tool/pngtool/main.cpp new file mode 100644 index 0000000..52f8d8d --- /dev/null +++ b/tool/pngtool/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") + +#include "frmpngtool.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QFont font; + font.setFamily("Microsoft Yahei"); + font.setPixelSize(13); + a.setFont(font); + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmPngTool w; + w.setWindowTitle("PNG图片警告去除工具 (QQ: 517216493 WX: feiyangqingyun)"); + w.show(); + + return a.exec(); +} diff --git a/tool/pngtool/pngtool.pro b/tool/pngtool/pngtool.pro new file mode 100644 index 0000000..c7322b0 --- /dev/null +++ b/tool/pngtool/pngtool.pro @@ -0,0 +1,14 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat + +TARGET = pngtool +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmpngtool.cpp +HEADERS += frmpngtool.h +FORMS += frmpngtool.ui + diff --git a/tool/tool.pro b/tool/tool.pro new file mode 100644 index 0000000..c690d8a --- /dev/null +++ b/tool/tool.pro @@ -0,0 +1,15 @@ +TEMPLATE = subdirs +SUBDIRS += comtool +SUBDIRS += nettool +SUBDIRS += netserver + +SUBDIRS += base64helper +SUBDIRS += countcode +SUBDIRS += emailtool +SUBDIRS += moneytool +SUBDIRS += pngtool + +SUBDIRS += keytool +SUBDIRS += keydemo +SUBDIRS += livetool +SUBDIRS += livedemo