upload all files
This commit is contained in:
82
.gitignore
vendored
Normal file
82
.gitignore
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# This file is used to ignore files which are generated
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.autosave
|
||||||
|
*.a
|
||||||
|
*.core
|
||||||
|
*.moc
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*_pch.h.cpp
|
||||||
|
*_resource.rc
|
||||||
|
*.qm
|
||||||
|
.#*
|
||||||
|
*.*#
|
||||||
|
core
|
||||||
|
!core/
|
||||||
|
tags
|
||||||
|
.DS_Store
|
||||||
|
.directory
|
||||||
|
*.debug
|
||||||
|
Makefile*
|
||||||
|
*.prl
|
||||||
|
*.app
|
||||||
|
moc_*.cpp
|
||||||
|
ui_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
Thumbs.db
|
||||||
|
*.res
|
||||||
|
*.rc
|
||||||
|
/.qmake.cache
|
||||||
|
/.qmake.stash
|
||||||
|
|
||||||
|
# qtcreator generated files
|
||||||
|
*.pro.user*
|
||||||
|
*.qbs.user*
|
||||||
|
CMakeLists.txt.user*
|
||||||
|
|
||||||
|
# xemacs temporary files
|
||||||
|
*.flc
|
||||||
|
|
||||||
|
# Vim temporary files
|
||||||
|
.*.swp
|
||||||
|
|
||||||
|
# Visual Studio generated files
|
||||||
|
*.ib_pdb_index
|
||||||
|
*.idb
|
||||||
|
*.ilk
|
||||||
|
*.pdb
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.vcproj
|
||||||
|
*vcproj.*.*.user
|
||||||
|
*.ncb
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.vcxproj
|
||||||
|
*vcxproj.*
|
||||||
|
|
||||||
|
# MinGW generated files
|
||||||
|
*.Debug
|
||||||
|
*.Release
|
||||||
|
|
||||||
|
# Python byte code
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
# --------
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
|
||||||
|
# Directories with generated files
|
||||||
|
.moc/
|
||||||
|
.obj/
|
||||||
|
.pch/
|
||||||
|
.rcc/
|
||||||
|
.uic/
|
||||||
|
/build*/
|
||||||
72
Modules/Logger.cpp
Normal file
72
Modules/Logger.cpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#include "Logger.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <ctime>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <array>
|
||||||
|
#include <string_view>
|
||||||
|
#include <mutex>
|
||||||
|
#include <QDebug> // For Qt logging
|
||||||
|
|
||||||
|
structIs is;
|
||||||
|
|
||||||
|
std::string colorOut_256(std::string_view s, int ForeColor = 7)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "\033[38;5;" << ForeColor << "m" << s << "\033[m";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getSystemTime() {
|
||||||
|
using namespace std::chrono;
|
||||||
|
const auto now = system_clock::now();
|
||||||
|
const auto now_time_t = system_clock::to_time_t(now);
|
||||||
|
const auto ms = duration_cast<milliseconds>(now.time_since_epoch()).count() % 1000;
|
||||||
|
|
||||||
|
std::tm ltm{};
|
||||||
|
localtime_s(<m, &now_time_t);
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::put_time(<m, "%Y-%m-%d %H:%M:%S")
|
||||||
|
<< '.' << std::setw(3) << std::setfill('0') << ms;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger mutex to ensure whole log lines are emitted atomically
|
||||||
|
static std::mutex loggerMutex;
|
||||||
|
|
||||||
|
void postLog(const std::string& message, int level) {
|
||||||
|
const auto timeNow = getSystemTime();
|
||||||
|
|
||||||
|
constexpr std::array<const char*, 5> levelNames = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
|
||||||
|
constexpr std::array<int, 5> levelColors = {34, 27, 220, 196, 124};
|
||||||
|
|
||||||
|
const int idx = (level >= 0 && level < static_cast<int>(levelNames.size())) ? level : 1; // default to INFO
|
||||||
|
|
||||||
|
// Lock to make reading isDebug and all output atomic across threads
|
||||||
|
std::scoped_lock lock(loggerMutex);
|
||||||
|
|
||||||
|
if (is.debug == false) {
|
||||||
|
if (idx == 0) return; // skip DEBUG when debug is off
|
||||||
|
qInfo() << "[" << QString::fromStdString(timeNow) << " - " << QString::fromStdString(levelNames[idx]) << "] " << QString::fromStdString(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDebug == 1 -> colored output
|
||||||
|
const std::string levelDisplay = colorOut_256(levelNames[idx], levelColors[idx]);
|
||||||
|
QString levelDisplayQt = QString::fromStdString(levelDisplay);
|
||||||
|
|
||||||
|
if (idx == 0) { // DEBUG level
|
||||||
|
qDebug("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
|
||||||
|
} else if (idx == 1) { // INFO level
|
||||||
|
qInfo("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
|
||||||
|
} else if (idx == 2) { // WARNING level
|
||||||
|
qWarning("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
|
||||||
|
} else if (idx == 3) { // ERROR level
|
||||||
|
qCritical("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
|
||||||
|
} else if (idx == 4) { // FATAL level
|
||||||
|
qFatal("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Modules/Logger.h
Normal file
9
Modules/Logger.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string getSystemTime();
|
||||||
|
void postLog(const std::string& message, int level);
|
||||||
|
|
||||||
|
#endif
|
||||||
83
Modules/global.h
Normal file
83
Modules/global.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#ifndef GLOBAL_H
|
||||||
|
#define GLOBAL_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QTableWidget>
|
||||||
|
|
||||||
|
// *** dialogLogin ***
|
||||||
|
struct structCheckBox {
|
||||||
|
QCheckBox *rememberMe = nullptr;
|
||||||
|
};
|
||||||
|
extern structCheckBox checkBox;
|
||||||
|
|
||||||
|
struct structComboBox{
|
||||||
|
QComboBox *findBy = nullptr;
|
||||||
|
};
|
||||||
|
extern structComboBox comboBox;
|
||||||
|
|
||||||
|
struct structTextEdit {
|
||||||
|
QTextEdit *username = nullptr;
|
||||||
|
QTextEdit *passwd = nullptr;
|
||||||
|
QTextEdit *search = nullptr;
|
||||||
|
};
|
||||||
|
extern structTextEdit textEdit;
|
||||||
|
|
||||||
|
struct structPushButton {
|
||||||
|
QPushButton *ok = nullptr;
|
||||||
|
QPushButton *cancel = nullptr;
|
||||||
|
QPushButton *seacrh = nullptr;
|
||||||
|
QPushButton *clear = nullptr;
|
||||||
|
QPushButton *submit = nullptr;
|
||||||
|
QPushButton *remove = nullptr;
|
||||||
|
};
|
||||||
|
extern structPushButton pushButton;
|
||||||
|
|
||||||
|
struct structLabel {
|
||||||
|
QLabel *connStatus = nullptr;
|
||||||
|
QLabel *salaryShould = nullptr;
|
||||||
|
QLabel *salaryDiscount = nullptr;
|
||||||
|
QLabel *salaryActual = nullptr;
|
||||||
|
};
|
||||||
|
extern structLabel label;
|
||||||
|
|
||||||
|
struct structTableWidget {
|
||||||
|
QTableWidget *teacherInfo = nullptr;
|
||||||
|
QTableWidget *teacherSalary = nullptr;
|
||||||
|
};
|
||||||
|
extern structTableWidget tableWidget;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class DialogLogin;
|
||||||
|
}
|
||||||
|
// *******************
|
||||||
|
|
||||||
|
|
||||||
|
// *** main ***
|
||||||
|
struct structIs{
|
||||||
|
bool debug = true;
|
||||||
|
bool loggedIn = false;
|
||||||
|
bool connected = false;
|
||||||
|
};
|
||||||
|
extern structIs is;
|
||||||
|
|
||||||
|
struct structSession{
|
||||||
|
std::string token;
|
||||||
|
std::string userName;
|
||||||
|
std::string userID;
|
||||||
|
};
|
||||||
|
extern structSession session;
|
||||||
|
|
||||||
|
struct structUserInfo{
|
||||||
|
std::string userName;
|
||||||
|
std::string passwd;
|
||||||
|
};
|
||||||
|
extern structUserInfo userInfo;
|
||||||
|
// ************
|
||||||
|
|
||||||
|
#endif // GLOBAL_H
|
||||||
960
Modules/inicpp.hpp
Normal file
960
Modules/inicpp.hpp
Normal file
@@ -0,0 +1,960 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 dujingning <djn2019x@163.com> <https://github.com/dujingning/inicpp.git>
|
||||||
|
*
|
||||||
|
* 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 __JN_INICPP_H__
|
||||||
|
#define __JN_INICPP_H__
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#ifdef _ENBABLE_INICPP_STD_WSTRING_ // Not all of C++ 11 support <codecvt>
|
||||||
|
// for std::string <==> std::wstring convert
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INICPP_DEBUG
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <ctime>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class TimeFormatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string format(const std::string &format = "%Y-%m-%d %H:%M:%S")
|
||||||
|
{
|
||||||
|
std::time_t t = std::time(nullptr);
|
||||||
|
std::tm tm = *std::localtime(&t);
|
||||||
|
std::array<char, 100> buffer;
|
||||||
|
std::strftime(buffer.data(), buffer.size(), format.c_str(), &tm);
|
||||||
|
return buffer.data();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CODE_INFO std::string(" \t``````|") + std::string(__FILE__) + ":" + std::to_string(__LINE__) + " fun:" + std::string(__FUNCTION__)
|
||||||
|
#define INI_DEBUG(x) std::cout << "INICPP " << TimeFormatter::format() << " : " << x << CODE_INFO << std::endl
|
||||||
|
|
||||||
|
#else // #ifdef INICPP_DEBUG
|
||||||
|
#define INI_DEBUG(x)
|
||||||
|
#endif // #ifdef INICPP_DEBUG
|
||||||
|
|
||||||
|
namespace inicpp
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef struct ValueNode
|
||||||
|
{
|
||||||
|
std::string Value = "";
|
||||||
|
int lineNumber = -1; // text line start with 1
|
||||||
|
} ValueNode;
|
||||||
|
|
||||||
|
class parentHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual parentHelper *parent()
|
||||||
|
{
|
||||||
|
INI_DEBUG("called parentHelper virtual impl: need to impl parent");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
virtual void setParent(parentHelper *parent)
|
||||||
|
{
|
||||||
|
INI_DEBUG("called parentHelper virtual impl: need to impl setParent");
|
||||||
|
}
|
||||||
|
virtual bool set(const std::string &Section, const std::string &Key, const std::string &Value, const std::string &comment = "")
|
||||||
|
{
|
||||||
|
INI_DEBUG("called parentHelper virtual impl: need to impl set");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ValueProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ValueProxy(std::string &value) : _value(value) {}
|
||||||
|
~ValueProxy() {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ValueProxy(const T &value) : _value(to_string(value)) {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static std::string to_string(const T &value)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << value;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T get() const
|
||||||
|
{
|
||||||
|
static_assert(!std::is_pointer<T>::value, "Pointer types are not supported for conversion.");
|
||||||
|
std::istringstream iss(_value);
|
||||||
|
T result;
|
||||||
|
if (!(iss >> result))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Type mismatch or invalid conversion. with(section-key-value): " +_sectionName +"-"+ _keyName +"-"+ _value); // error notify
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator char() const { return this->get<char>(); }
|
||||||
|
operator short() const { return this->get<short>(); }
|
||||||
|
operator int() const { return this->get<int>(); }
|
||||||
|
operator long() const { return this->get<long>(); }
|
||||||
|
operator long long() const { return this->get<long long>(); }
|
||||||
|
operator float() const { return this->get<float>(); }
|
||||||
|
operator double() const { return this->get<double>(); }
|
||||||
|
|
||||||
|
operator unsigned char() const { return this->get<unsigned char>(); }
|
||||||
|
operator unsigned short() const { return this->get<unsigned short>(); }
|
||||||
|
operator unsigned int() const { return this->get<unsigned int>(); }
|
||||||
|
operator unsigned long() const { return this->get<unsigned long>(); }
|
||||||
|
operator unsigned long long() const { return this->get<unsigned long long>(); }
|
||||||
|
|
||||||
|
// false:'0' or 'false', true : others
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
if (_value == "0" || _value == "false" || _value == "no")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::ostream &operator<<(std::ostream &os, const ValueProxy &proxy)
|
||||||
|
{
|
||||||
|
os << proxy._value;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignment
|
||||||
|
template <typename T>
|
||||||
|
ValueProxy &operator=(const T &other)
|
||||||
|
{
|
||||||
|
std::string value = this->to_string(other);
|
||||||
|
|
||||||
|
if (_value != value)
|
||||||
|
{
|
||||||
|
set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_value = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueProxy &operator=(const std::string &other)
|
||||||
|
{
|
||||||
|
if (_value != other)
|
||||||
|
{
|
||||||
|
INI_DEBUG("Value Proxy Wanna Set Value: " << other);
|
||||||
|
set(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
_value = other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify std::string
|
||||||
|
const std::string &String() noexcept
|
||||||
|
{
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setWriteCB(parentHelper *sectionObj, const std::string §ionName, const std::string &keyName)
|
||||||
|
{
|
||||||
|
_section = sectionObj;
|
||||||
|
_sectionName = sectionName;
|
||||||
|
_keyName = keyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set(const std::string &value)
|
||||||
|
{
|
||||||
|
if (value.empty() || _keyName.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_section && _section->parent() && _section->parent()->parent())
|
||||||
|
{
|
||||||
|
_section->parent()->parent()->set(_sectionName, _keyName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string &_value;
|
||||||
|
|
||||||
|
std::string _sectionName, _keyName;
|
||||||
|
parentHelper *_section = nullptr;
|
||||||
|
};
|
||||||
|
} // namespace inicpp
|
||||||
|
|
||||||
|
namespace inicpp
|
||||||
|
{
|
||||||
|
|
||||||
|
class section : parentHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
section() : _sectionName()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit section(const std::string §ionName) : _sectionName(sectionName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &name()
|
||||||
|
{
|
||||||
|
return _sectionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string getValue(const std::string &Key)
|
||||||
|
{
|
||||||
|
if (!_sectionMap.count(Key))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return _sectionMap[Key].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setName(const std::string &name, const int &lineNumber)
|
||||||
|
{
|
||||||
|
_sectionName = name;
|
||||||
|
_lineNumber = lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(const std::string &Key, const std::string &Value, const int line)
|
||||||
|
{
|
||||||
|
_sectionMap[Key].Value = Value;
|
||||||
|
_sectionMap[Key].lineNumber = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(section &sec)
|
||||||
|
{
|
||||||
|
_sectionMap.insert(sec._sectionMap.begin(), sec._sectionMap.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isKeyExist(const std::string &Key)
|
||||||
|
{
|
||||||
|
return !_sectionMap.count(Key) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getEndSection()
|
||||||
|
{
|
||||||
|
int line = -1;
|
||||||
|
|
||||||
|
if (_sectionMap.empty() && _sectionName != "")
|
||||||
|
{
|
||||||
|
return _lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &data : _sectionMap)
|
||||||
|
{
|
||||||
|
if (data.second.lineNumber > line)
|
||||||
|
{
|
||||||
|
line = data.second.lineNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLine(const std::string &Key)
|
||||||
|
{
|
||||||
|
if (!_sectionMap.count(Key))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _sectionMap[Key].lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
_lineNumber = -1;
|
||||||
|
_sectionName.clear();
|
||||||
|
_sectionMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return _sectionMap.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int toInt(const std::string &Key) noexcept
|
||||||
|
{
|
||||||
|
if (!_sectionMap.count(Key))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = std::stoi(_sectionMap[Key].Value);
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument &e)
|
||||||
|
{
|
||||||
|
INI_DEBUG("Invalid argument: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
|
||||||
|
}
|
||||||
|
catch (const std::out_of_range &e)
|
||||||
|
{
|
||||||
|
INI_DEBUG("Out of range: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toString(const std::string &Key) noexcept
|
||||||
|
{
|
||||||
|
if (!_sectionMap.count(Key))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return _sectionMap[Key].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _ENBABLE_INICPP_STD_WSTRING_
|
||||||
|
std::wstring toWString(const std::string &Key)
|
||||||
|
{
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
return converter.from_bytes(toString(Key));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double toDouble(const std::string &Key) noexcept
|
||||||
|
{
|
||||||
|
if (!_sectionMap.count(Key))
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double result = 0.0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = std::stod(_sectionMap[Key].Value);
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument &e)
|
||||||
|
{
|
||||||
|
INI_DEBUG("Invalid argument: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
|
||||||
|
}
|
||||||
|
catch (const std::out_of_range &e)
|
||||||
|
{
|
||||||
|
INI_DEBUG("Out of range: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string /*Key*/, std::string /*Value*/> getSectionMap()
|
||||||
|
{
|
||||||
|
std::map<std::string /*Key*/, std::string /*Value*/> sectionKVMap;
|
||||||
|
|
||||||
|
for (auto &iter : _sectionMap)
|
||||||
|
{
|
||||||
|
sectionKVMap[iter.first] = iter.second.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sectionKVMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatically converts to any type; throws std::runtime_error if not found or conversion fails
|
||||||
|
ValueProxy operator[](const std::string &Key)
|
||||||
|
{
|
||||||
|
ValueProxy vp(_sectionMap[Key].Value);
|
||||||
|
|
||||||
|
vp.setWriteCB(this, _sectionName, Key);
|
||||||
|
|
||||||
|
return vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline parentHelper *parent() override { return _parent; };
|
||||||
|
inline void setParent(parentHelper *parent) override { _parent = parent; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string _sectionName;
|
||||||
|
std::map<std::string /*Key*/, ValueNode> _sectionMap;
|
||||||
|
int _lineNumber = -1; // text line start with 1
|
||||||
|
|
||||||
|
parentHelper *_parent = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ini : parentHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void addSection(section &sec)
|
||||||
|
{
|
||||||
|
if (_iniInfoMap.count(sec.name())) // if exist,need to merge
|
||||||
|
{
|
||||||
|
_iniInfoMap[sec.name()].append(sec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_iniInfoMap.emplace(sec.name(), sec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeSection(const std::string §ionName)
|
||||||
|
{
|
||||||
|
if (!_iniInfoMap.count(sectionName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_iniInfoMap.erase(sectionName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSectionExists(const std::string §ionName)
|
||||||
|
{
|
||||||
|
return !_iniInfoMap.count(sectionName) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// may contains default of Unnamed section with ""
|
||||||
|
std::list<std::string> getSectionsList()
|
||||||
|
{
|
||||||
|
std::list<std::string> sectionList;
|
||||||
|
for (const auto &data : _iniInfoMap)
|
||||||
|
{
|
||||||
|
if (data.first == "" && data.second.isEmpty()) // default section: no section name,if empty,not count it.
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sectionList.emplace_back(data.first);
|
||||||
|
}
|
||||||
|
return sectionList;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string /*key*/, std::string /*value*/> getSectionMap(const std::string §ionName)
|
||||||
|
{
|
||||||
|
std::map<std::string /*key*/, std::string /*value*/> kvMap;
|
||||||
|
if (_iniInfoMap.count(sectionName) == 0)
|
||||||
|
{
|
||||||
|
return kvMap;
|
||||||
|
}
|
||||||
|
return _iniInfoMap[sectionName].getSectionMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
const section &operator[](const std::string §ionName)
|
||||||
|
{
|
||||||
|
_iniInfoMap[sectionName].setParent(this);
|
||||||
|
|
||||||
|
if (_iniInfoMap[sectionName].name().empty())
|
||||||
|
{
|
||||||
|
_iniInfoMap[sectionName].setName(sectionName, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _iniInfoMap[sectionName];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t getSectionSize()
|
||||||
|
{
|
||||||
|
return _iniInfoMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getValue(const std::string §ionName, const std::string &Key)
|
||||||
|
{
|
||||||
|
if (!_iniInfoMap.count(sectionName))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return _iniInfoMap[sectionName][Key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// for none section
|
||||||
|
int getLine(const std::string &Key)
|
||||||
|
{
|
||||||
|
if (!_iniInfoMap.count(""))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _iniInfoMap[""].getLine(Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for section-key
|
||||||
|
int getLine(const std::string §ionName, const std::string &Key)
|
||||||
|
{
|
||||||
|
if (!_iniInfoMap.count(sectionName))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _iniInfoMap[sectionName].getLine(Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void clear() { _iniInfoMap.clear(); }
|
||||||
|
inline bool empty() { return _iniInfoMap.empty(); }
|
||||||
|
|
||||||
|
parentHelper *parent() override { return _parent; }
|
||||||
|
void setParent(parentHelper *parent) override { _parent = parent; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::map<std::string /*Section Name*/, section> _iniInfoMap;
|
||||||
|
|
||||||
|
private:
|
||||||
|
parentHelper *_parent = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IniManager : parentHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#ifdef _ENBABLE_INICPP_STD_WSTRING_
|
||||||
|
explicit IniManager(const std::wstring &configFileName = L"")
|
||||||
|
{
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
std::string stringValue = converter.to_bytes(configFileName);
|
||||||
|
_configFileName = stringValue;
|
||||||
|
|
||||||
|
_iniData.setParent(this);
|
||||||
|
parse();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
explicit IniManager(const std::string &configFileName = "") : _configFileName(configFileName)
|
||||||
|
{
|
||||||
|
_iniData.setParent(this);
|
||||||
|
|
||||||
|
parse();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
~IniManager()
|
||||||
|
{
|
||||||
|
_iniFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
section operator[](const std::string §ionName)
|
||||||
|
{
|
||||||
|
return _iniData[sectionName];
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse()
|
||||||
|
{
|
||||||
|
if (_configFileName.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_iniFile.is_open())
|
||||||
|
{
|
||||||
|
_iniFile.clear();
|
||||||
|
_iniFile.open(_configFileName, std::ifstream::in | std::ifstream::out | std::fstream::app);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_iniFile.is_open())
|
||||||
|
{
|
||||||
|
INI_DEBUG("Failed to open(WR),try to open with readonly(R).");
|
||||||
|
_iniFile.clear();
|
||||||
|
_iniFile.open(_configFileName, std::ifstream::in);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_iniFile.is_open())
|
||||||
|
{
|
||||||
|
INI_DEBUG("Failed to open the input INI file for parsing! file:" << _configFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_iniData.clear();
|
||||||
|
|
||||||
|
_iniFile.seekg(0, _iniFile.beg);
|
||||||
|
std::string data, sectionName;
|
||||||
|
int sectionLine = -1;
|
||||||
|
|
||||||
|
section sectionRecord;
|
||||||
|
|
||||||
|
_SumOfLines = 1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
std::getline(_iniFile, data);
|
||||||
|
|
||||||
|
if (!filterData(data))
|
||||||
|
{
|
||||||
|
++_SumOfLines;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.find('[') == 0) // section
|
||||||
|
{
|
||||||
|
if (!sectionRecord.isEmpty() || sectionRecord.name() != "")
|
||||||
|
{
|
||||||
|
_iniData.addSection(sectionRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t first = data.find('[');
|
||||||
|
size_t last = data.find(']');
|
||||||
|
|
||||||
|
if (last == std::string::npos)
|
||||||
|
{
|
||||||
|
++_SumOfLines;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sectionName = data.substr(first + 1, last - first - 1);
|
||||||
|
sectionLine = _SumOfLines;
|
||||||
|
|
||||||
|
sectionRecord.clear();
|
||||||
|
sectionRecord.setName(sectionName, sectionLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pos = data.find('=');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{ // k=v
|
||||||
|
std::string key = data.substr(0, pos);
|
||||||
|
std::string value = data.substr(pos + 1);
|
||||||
|
|
||||||
|
trimEdges(key);
|
||||||
|
trimEdges(value);
|
||||||
|
|
||||||
|
sectionRecord.setValue(key, value, _SumOfLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
++_SumOfLines;
|
||||||
|
|
||||||
|
} while (!_iniFile.eof());
|
||||||
|
|
||||||
|
if (!sectionRecord.isEmpty())
|
||||||
|
{
|
||||||
|
sectionRecord.setName(sectionName, -1);
|
||||||
|
_iniData.addSection(sectionRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_iniFile.is_open())
|
||||||
|
{
|
||||||
|
_iniFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set(const std::string &Section, const std::string &Key, const std::string &Value, const std::string &comment = "") override
|
||||||
|
{
|
||||||
|
parse();
|
||||||
|
|
||||||
|
std::string key = Key, value = Value;
|
||||||
|
|
||||||
|
trimEdges(key);
|
||||||
|
trimEdges(key);
|
||||||
|
|
||||||
|
if (key == "" || value == "")
|
||||||
|
{
|
||||||
|
INI_DEBUG("Invalid parameter input: key[" << key << "],value[" << value << "]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string keyValueData = key + "=" + value + "\n";
|
||||||
|
if (comment.length() > 0)
|
||||||
|
{
|
||||||
|
keyValueData = comment + "\n" + keyValueData;
|
||||||
|
if (comment[0] != ';')
|
||||||
|
{
|
||||||
|
keyValueData = ";" + keyValueData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &tempFile = ".temp.ini";
|
||||||
|
std::fstream input(_configFileName, std::ifstream::in);
|
||||||
|
std::ofstream output(tempFile);
|
||||||
|
|
||||||
|
if (!input.is_open())
|
||||||
|
{
|
||||||
|
INI_DEBUG("Failed to open the input INI file for modification! File name:" << _configFileName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output.is_open())
|
||||||
|
{
|
||||||
|
INI_DEBUG("Failed to open the output INI file for modification!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int line_number_mark = -1;
|
||||||
|
bool isInputDataWited = false;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// exist key at one section replace it, or need to create it
|
||||||
|
if (_iniData.isSectionExists(Section))
|
||||||
|
{
|
||||||
|
line_number_mark = (*this)[Section].getLine(key);
|
||||||
|
|
||||||
|
if (line_number_mark == -1)
|
||||||
|
{ // section exist, key not exist
|
||||||
|
line_number_mark = (*this)[Section].getEndSection();
|
||||||
|
|
||||||
|
std::string lineData;
|
||||||
|
int input_line_number = 0;
|
||||||
|
while (std::getline(input, lineData))
|
||||||
|
{
|
||||||
|
++input_line_number;
|
||||||
|
|
||||||
|
if (input_line_number == (line_number_mark + 1))
|
||||||
|
{ // new line,append to next line
|
||||||
|
isInputDataWited = true;
|
||||||
|
output << keyValueData;
|
||||||
|
}
|
||||||
|
|
||||||
|
output << lineData << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.eof() && !isInputDataWited)
|
||||||
|
{
|
||||||
|
isInputDataWited = true;
|
||||||
|
output << keyValueData;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_number_mark <= 0) // not found key at config file
|
||||||
|
{
|
||||||
|
input.seekg(0, input.beg);
|
||||||
|
|
||||||
|
bool isHoldSection = false;
|
||||||
|
std::string newLine = "\n\n";
|
||||||
|
if (Section != "" && Section.find("[") == std::string::npos && Section.find("]") == std::string::npos && Section.find("=") == std::string::npos)
|
||||||
|
{
|
||||||
|
if (_iniData.empty() || _iniData.getSectionSize() <= 0)
|
||||||
|
{
|
||||||
|
newLine.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
isHoldSection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.section is exist or empty section
|
||||||
|
if (_iniData.isSectionExists(Section) || Section == "")
|
||||||
|
{
|
||||||
|
// write key/value to head
|
||||||
|
if (isHoldSection)
|
||||||
|
{
|
||||||
|
output << newLine << "[" << Section << "]" << "\n";
|
||||||
|
}
|
||||||
|
output << keyValueData;
|
||||||
|
// write others
|
||||||
|
std::string lineData;
|
||||||
|
while (std::getline(input, lineData))
|
||||||
|
{
|
||||||
|
output << lineData << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2.section is not exist
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// write others
|
||||||
|
std::string lineData;
|
||||||
|
while (std::getline(input, lineData))
|
||||||
|
{
|
||||||
|
output << lineData << "\n";
|
||||||
|
}
|
||||||
|
// write key/value to end
|
||||||
|
if (isHoldSection)
|
||||||
|
{
|
||||||
|
output << newLine << "[" << Section << "]" << "\n";
|
||||||
|
}
|
||||||
|
output << keyValueData;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // found, replace it
|
||||||
|
|
||||||
|
std::string lineData;
|
||||||
|
int input_line_number = 0;
|
||||||
|
|
||||||
|
while (std::getline(input, lineData))
|
||||||
|
{
|
||||||
|
++input_line_number;
|
||||||
|
|
||||||
|
// delete old comment if new comment is set
|
||||||
|
if (input_line_number == (line_number_mark - 1) && lineData.length() > 0 && lineData[0] == ';' && comment != "")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_line_number == line_number_mark)
|
||||||
|
{ // replace to this line
|
||||||
|
output << keyValueData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output << lineData << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
INI_DEBUG("error! inicpp lost process of set function");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
// clear work
|
||||||
|
input.close();
|
||||||
|
output.close();
|
||||||
|
|
||||||
|
std::remove(_configFileName.c_str());
|
||||||
|
std::rename(tempFile.c_str(), _configFileName.c_str());
|
||||||
|
|
||||||
|
// reload
|
||||||
|
parse();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set(const std::string &Section, const std::string &Key, const int Value, const std::string &comment = "")
|
||||||
|
{
|
||||||
|
std::string stringValue = std::to_string(Value);
|
||||||
|
return set(Section, Key, stringValue, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set(const std::string &Section, const std::string &Key, const double &Value, const std::string &comment = "")
|
||||||
|
{
|
||||||
|
std::string stringValue = std::to_string(Value);
|
||||||
|
return set(Section, Key, stringValue, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set(const std::string &Section, const std::string &Key, const char &Value, const std::string &comment = "")
|
||||||
|
{
|
||||||
|
std::string stringValue = ValueProxy::to_string(Value);
|
||||||
|
return set(Section, Key, stringValue, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no sections: head of config file
|
||||||
|
bool set(const std::string &Key, const std::string &Value)
|
||||||
|
{
|
||||||
|
return set("", Key, Value, "");
|
||||||
|
}
|
||||||
|
bool set(const std::string &Key, const char *Value)
|
||||||
|
{
|
||||||
|
return set("", Key, Value, "");
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
bool set(const std::string &Key, const T &Value)
|
||||||
|
{
|
||||||
|
std::string stringValue = std::to_string(Value);
|
||||||
|
return set("", Key, stringValue, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _ENBABLE_INICPP_STD_WSTRING_
|
||||||
|
bool set(const std::string &Section, const std::string &Key, const std::wstring &Value, const std::string &comment = "")
|
||||||
|
{
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
std::string stringValue = converter.to_bytes(Value);
|
||||||
|
|
||||||
|
return set(Section, Key, stringValue, comment);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// comment for section name of key
|
||||||
|
bool setComment(const std::string &Section, const std::string &Key, const std::string &comment)
|
||||||
|
{
|
||||||
|
return set(Section, Key, (*this)[Section].toString(Key), comment);
|
||||||
|
}
|
||||||
|
// comment for no section name of key
|
||||||
|
bool setComment(const std::string &Key, const std::string &comment)
|
||||||
|
{
|
||||||
|
return set("", Key, (*this)[""].toString(Key), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSectionExists(const std::string §ionName)
|
||||||
|
{
|
||||||
|
return _iniData.isSectionExists(sectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::list<std::string /*section name*/> sectionsList()
|
||||||
|
{
|
||||||
|
return _iniData.getSectionsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::map<std::string /*key*/, std::string /*value*/> sectionMap(const std::string §ionName)
|
||||||
|
{
|
||||||
|
return _iniData.getSectionMap(sectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _ENBABLE_INICPP_STD_WSTRING_
|
||||||
|
void setFileName(const std::wstring &fileName)
|
||||||
|
{
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
std::string name = converter.to_bytes(fileName);
|
||||||
|
|
||||||
|
_configFileName = name;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void setFileName(const std::string &fileName)
|
||||||
|
{
|
||||||
|
_configFileName = fileName;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool filterData(std::string &data)
|
||||||
|
{
|
||||||
|
if (data.length() == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] == ';')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] == '#')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trimEdges(std::string &data)
|
||||||
|
{
|
||||||
|
// remove left ' ' and '\t'
|
||||||
|
data.erase(data.begin(), std::find_if(data.begin(), data.end(), [](unsigned char c)
|
||||||
|
{ return !std::isspace(c); }));
|
||||||
|
// remove right ' ' and '\t'
|
||||||
|
data.erase(std::find_if(data.rbegin(), data.rend(), [](unsigned char c)
|
||||||
|
{ return !std::isspace(c); })
|
||||||
|
.base(),
|
||||||
|
data.end());
|
||||||
|
|
||||||
|
// INI_DEBUG("trimEdges data:|" << data << "|");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ini _iniData;
|
||||||
|
int _SumOfLines;
|
||||||
|
std::fstream _iniFile;
|
||||||
|
std::string _configFileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace inicpp
|
||||||
|
|
||||||
|
#endif
|
||||||
33
Modules/methods.cpp
Normal file
33
Modules/methods.cpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "methods.h"
|
||||||
|
#include <ctime>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
methods::methods() {}
|
||||||
|
|
||||||
|
using inicpp::ini;
|
||||||
|
using inicpp::IniManager;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
int getUnixTimestamp() { // 获取当前Unix时间戳
|
||||||
|
return static_cast<int>(time(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
string getTextMiddle(string source, string left, string right) {
|
||||||
|
size_t leftPos = source.find(left);
|
||||||
|
if (leftPos == string::npos) return "";
|
||||||
|
leftPos += left.length();
|
||||||
|
size_t rightPos = source.find(right, leftPos);
|
||||||
|
if (rightPos == string::npos) return "";
|
||||||
|
return source.substr(leftPos, rightPos - leftPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
string getKeyText(string iniFilePath, string mainLevel, string subLevel) {
|
||||||
|
IniManager _ini(iniFilePath); // Load and parse the INI file
|
||||||
|
string returnValue = _ini[mainLevel][subLevel];
|
||||||
|
return (returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setKeyText(string iniFilePath, string mainLevel, string subLevel, string value) {
|
||||||
|
IniManager _ini(iniFilePath); // Load and parse the INI file
|
||||||
|
_ini.set(mainLevel, subLevel, value);
|
||||||
|
}
|
||||||
19
Modules/methods.h
Normal file
19
Modules/methods.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef METHODS_H
|
||||||
|
#define METHODS_H
|
||||||
|
#include <iostream>
|
||||||
|
#include "Modules/inicpp.hpp"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
class methods
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
methods();
|
||||||
|
};
|
||||||
|
|
||||||
|
int getUnixTimestamp();
|
||||||
|
string getTextMiddle(string source, string left, string right); // Get a middle text from a string
|
||||||
|
string getKeyText(string iniFilePath, string mainLevel, string subLevel); // Get key value from INI file
|
||||||
|
void setKeyText(string iniFilePath, string mainLevel, string subLevel, string value); // Set key value to INI file
|
||||||
|
|
||||||
|
#endif // METHODS_H
|
||||||
348
Modules/socketactions.cpp
Normal file
348
Modules/socketactions.cpp
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
#include "socketactions.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace sockAct {
|
||||||
|
|
||||||
|
struct SocketContext {
|
||||||
|
std::unique_ptr<QTcpSocket> socket;
|
||||||
|
QMutex sendMutex;
|
||||||
|
QMutex connectMutex;
|
||||||
|
bool isInitialized = false;
|
||||||
|
std::string lastError;
|
||||||
|
QHostAddress lastConnectedHost;
|
||||||
|
quint16 lastConnectedPort = 0;
|
||||||
|
qint64 lastSendTime = 0;
|
||||||
|
qint64 lastReceiveTime = 0;
|
||||||
|
int sendCount = 0;
|
||||||
|
int receiveCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SocketContext& context() { // Static context
|
||||||
|
static SocketContext ctx;
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool ensureInitialized();
|
||||||
|
bool internalConnectToHost(const std::string& host, quint16 port, int timeoutMs);
|
||||||
|
std::string waitForResponse(int timeoutMs);
|
||||||
|
void logNetworkEvent(const std::string& message, LogLevel level);
|
||||||
|
void handleSocketError(QAbstractSocket::SocketError error);
|
||||||
|
void resetSocket();
|
||||||
|
QString toQString(const std::string& str);
|
||||||
|
std::string fromQString(const QString& str);
|
||||||
|
// Add UTF-8 encoding helper functions
|
||||||
|
QByteArray stringToUtf8Bytes(const std::string& str);
|
||||||
|
std::string bytesToUtf8String(const QByteArray& bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sockInit() {
|
||||||
|
QMutexLocker locker(&context().connectMutex);
|
||||||
|
|
||||||
|
if (context().isInitialized) {
|
||||||
|
logNetworkEvent("[Socket] Initialization completed.", INFO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QNetworkInterface::allInterfaces().isEmpty()) { // Check Qt Network Module
|
||||||
|
logNetworkEvent("[Socket] Qt Networking module initializing completed.", INFO);
|
||||||
|
} else {
|
||||||
|
logNetworkEvent("[Socket] No avaliable network interfaces", WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
context().isInitialized = true;
|
||||||
|
logNetworkEvent("[Socket] Initialization completed.", INFO);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connectToHost(const std::string& host, quint16 port, int timeoutMs) {
|
||||||
|
if (!ensureInitialized()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutexLocker locker(&context().connectMutex);
|
||||||
|
|
||||||
|
QString qhost = toQString(host);
|
||||||
|
|
||||||
|
if (context().socket &&
|
||||||
|
context().lastConnectedHost.toString() == qhost &&
|
||||||
|
context().lastConnectedPort == port) {
|
||||||
|
if (context().socket->state() == QAbstractSocket::ConnectedState) {
|
||||||
|
logNetworkEvent(std::string("[Socket] Connected to server: ") + host + ":" + std::to_string(port), INFO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalConnectToHost(host, port, timeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tcpSend(const std::string& data, int timeoutMs) {
|
||||||
|
if (!ensureInitialized()) {
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutexLocker locker(&context().sendMutex);
|
||||||
|
|
||||||
|
if (!context().socket || context().socket->state() != QAbstractSocket::ConnectedState) {
|
||||||
|
logNetworkEvent("[Socket] No connection avaliable, cannot send any data.", ERROR);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert string to UTF-8 bytes for transmission
|
||||||
|
QByteArray sendData = stringToUtf8Bytes(data);
|
||||||
|
|
||||||
|
qint64 bytesWritten = context().socket->write(sendData); // Send data
|
||||||
|
context().lastSendTime = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
context().sendCount++;
|
||||||
|
|
||||||
|
if (bytesWritten == -1) {
|
||||||
|
QString errorStr = context().socket->errorString();
|
||||||
|
logNetworkEvent("[Socket] Failed to send data: " + fromQString(errorStr), ERROR);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesWritten != sendData.size()) {
|
||||||
|
logNetworkEvent("[Socket] Data send not complete, expected to send " + std::to_string(sendData.size()) +
|
||||||
|
" bytes, " + std::to_string(bytesWritten) + " bytes sent", WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
logNetworkEvent("[Socket] " + std::to_string(bytesWritten) + " bytes has been sent to sevrer", DEBUG);
|
||||||
|
|
||||||
|
std::string response = waitForResponse(timeoutMs);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearSocket() {
|
||||||
|
QMutexLocker locker1(&context().connectMutex);
|
||||||
|
QMutexLocker locker2(&context().sendMutex);
|
||||||
|
|
||||||
|
if (context().socket) {
|
||||||
|
std::string serverInfo;
|
||||||
|
if (!context().lastConnectedHost.isNull()) {
|
||||||
|
serverInfo = fromQString(context().lastConnectedHost.toString()) + ":" +
|
||||||
|
std::to_string(context().lastConnectedPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
logNetworkEvent("[Socket] Disconnecting from server " + serverInfo + "...", INFO);
|
||||||
|
|
||||||
|
if (context().socket->state() != QAbstractSocket::UnconnectedState) {
|
||||||
|
context().socket->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
context().socket->disconnect();
|
||||||
|
|
||||||
|
// Reset connection info
|
||||||
|
context().lastConnectedHost.clear();
|
||||||
|
context().lastConnectedPort = 0;
|
||||||
|
context().lastSendTime = 0;
|
||||||
|
context().lastReceiveTime = 0;
|
||||||
|
context().sendCount = 0;
|
||||||
|
context().receiveCount = 0;
|
||||||
|
|
||||||
|
logNetworkEvent("[Socket] Disconnected.", INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isConnected() {
|
||||||
|
if (!context().socket) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return context().socket->state() == QAbstractSocket::ConnectedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getLastError() {
|
||||||
|
return context().lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Internal methods ====================
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
QString toQString(const std::string& str) {
|
||||||
|
return QString::fromStdString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fromQString(const QString& str) {
|
||||||
|
return str.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert string to UTF-8 bytes
|
||||||
|
QByteArray stringToUtf8Bytes(const std::string& str) {
|
||||||
|
// Use QString to convert to UTF-8
|
||||||
|
QString qstr = QString::fromStdString(str);
|
||||||
|
return qstr.toUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert UTF-8 bytes to string
|
||||||
|
std::string bytesToUtf8String(const QByteArray& bytes) {
|
||||||
|
// Convert from UTF-8 bytes to QString, then to std::string
|
||||||
|
QString qstr = QString::fromUtf8(bytes);
|
||||||
|
return qstr.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ensureInitialized() {
|
||||||
|
if (!context().isInitialized) {
|
||||||
|
logNetworkEvent("[Socket] Not initialized.", ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool internalConnectToHost(const std::string& host, quint16 port, int timeoutMs) {
|
||||||
|
if (context().socket) {
|
||||||
|
context().socket->abort();
|
||||||
|
context().socket.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
context().socket.reset(new QTcpSocket());
|
||||||
|
|
||||||
|
QString qhost = toQString(host);
|
||||||
|
|
||||||
|
QObject::connect(context().socket.get(), &QTcpSocket::connected, [host, port]() {
|
||||||
|
logNetworkEvent("[Socket] Connected to server " + host + ":" + std::to_string(port), INFO);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(context().socket.get(), QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred),
|
||||||
|
[](QAbstractSocket::SocketError error) {
|
||||||
|
handleSocketError(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
logNetworkEvent("[Socket] Connecting to server " + host + ":" + std::to_string(port) +
|
||||||
|
" (Timeout: " + std::to_string(timeoutMs) + "ms)...", INFO);
|
||||||
|
context().socket->connectToHost(qhost, port);
|
||||||
|
|
||||||
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
while (context().socket->state() == QAbstractSocket::ConnectingState) {
|
||||||
|
if (timer.elapsed() > timeoutMs) {
|
||||||
|
logNetworkEvent("[Socket] Connection to server " + host + ":" + std::to_string(port) + " timeout", WARNING);
|
||||||
|
context().socket->abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
QThread::msleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context().socket->state() != QAbstractSocket::ConnectedState) {
|
||||||
|
QString errorStr = context().socket->errorString();
|
||||||
|
logNetworkEvent("[Sockct] Failed to connect to server " + host + ":" + std::to_string(port) +
|
||||||
|
" Reason: " + fromQString(errorStr), ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
context().lastConnectedHost = context().socket->peerAddress();
|
||||||
|
context().lastConnectedPort = context().socket->peerPort();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string waitForResponse(int timeoutMs) {
|
||||||
|
if (!context().socket) {
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
while (context().socket->bytesAvailable() == 0) {
|
||||||
|
if (timer.elapsed() > timeoutMs) {
|
||||||
|
logNetworkEvent("[Socket] Timeout when waiting for reply (" + std::to_string(timeoutMs) + "ms)", WARNING);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context().socket->waitForReadyRead(100)) {
|
||||||
|
if (context().socket->state() != QAbstractSocket::ConnectedState) {
|
||||||
|
logNetworkEvent("[Socket] Connection lost.", ERROR);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray responseData = context().socket->readAll();
|
||||||
|
context().lastReceiveTime = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
context().receiveCount++;
|
||||||
|
|
||||||
|
// Convert UTF-8 bytes to string
|
||||||
|
std::string response = bytesToUtf8String(responseData);
|
||||||
|
|
||||||
|
int waitTime = timer.elapsed();
|
||||||
|
logNetworkEvent("[Socket] Reply from server " + std::to_string(responseData.size()) +
|
||||||
|
" bytes, Time: " + std::to_string(waitTime) + "ms", DEBUG);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logNetworkEvent(const std::string& message, LogLevel level) {
|
||||||
|
postLog(message, static_cast<int>(level));
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleSocketError(QAbstractSocket::SocketError error) {
|
||||||
|
std::string errorMsg;
|
||||||
|
LogLevel level = ERROR;
|
||||||
|
|
||||||
|
switch (error) {
|
||||||
|
case QAbstractSocket::ConnectionRefusedError:
|
||||||
|
errorMsg = "[Socket] Connection refused.";
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::RemoteHostClosedError:
|
||||||
|
errorMsg = "[Socket] Remote server closed connection.";
|
||||||
|
level = WARNING;
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::HostNotFoundError:
|
||||||
|
errorMsg = "[Socket] No host found.";
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::SocketAccessError:
|
||||||
|
errorMsg = "[Socket] Access error.";
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::SocketResourceError:
|
||||||
|
errorMsg = "[Socket] Resource error.";
|
||||||
|
level = WARNING;
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::SocketTimeoutError:
|
||||||
|
errorMsg = "[Socket] Timeout.";
|
||||||
|
level = WARNING;
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::NetworkError:
|
||||||
|
errorMsg = "[Socket] Network fatal.";
|
||||||
|
level = FATAL;
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::SslHandshakeFailedError:
|
||||||
|
errorMsg = "[Socket] TLS handshake error.";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorMsg = "[Socket] Unknown error.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context().socket) {
|
||||||
|
QString errorStr = context().socket->errorString();
|
||||||
|
errorMsg += ": " + fromQString(errorStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
logNetworkEvent(errorMsg, level);
|
||||||
|
context().lastError = errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetSocket() {
|
||||||
|
if (context().socket) {
|
||||||
|
context().socket->disconnect();
|
||||||
|
context().socket.reset();
|
||||||
|
}
|
||||||
|
context().lastError.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sockAct
|
||||||
76
Modules/socketactions.h
Normal file
76
Modules/socketactions.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#ifndef SOCKETACTIONS_H
|
||||||
|
#define SOCKETACTIONS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace sockAct {
|
||||||
|
|
||||||
|
// 日志级别枚举(与Logger.h保持一致)
|
||||||
|
enum LogLevel {
|
||||||
|
DEBUG = 0,
|
||||||
|
INFO = 1,
|
||||||
|
WARNING = 2,
|
||||||
|
ERROR = 3,
|
||||||
|
FATAL = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化Socket模块
|
||||||
|
*
|
||||||
|
* 初始化Qt网络模块,必须在使用其他socket函数前调用
|
||||||
|
* @return 初始化是否成功
|
||||||
|
*/
|
||||||
|
bool sockInit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 连接到TCP服务器
|
||||||
|
*
|
||||||
|
* @param host 服务器地址
|
||||||
|
* @param port 服务器端口
|
||||||
|
* @param timeoutMs 连接超时时间(毫秒)
|
||||||
|
* @return 连接是否成功
|
||||||
|
*/
|
||||||
|
bool connectToHost(const std::string& host, quint16 port, int timeoutMs = 3000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 发送TCP数据并接收响应
|
||||||
|
*
|
||||||
|
* 发送数据到已连接的服务器,并等待最多3秒接收响应
|
||||||
|
* 一旦收到数据立即返回,否则等待3秒后返回空字符串
|
||||||
|
*
|
||||||
|
* @param data 要发送的数据
|
||||||
|
* @param timeoutMs 接收超时时间(毫秒)
|
||||||
|
* @return 接收到的数据,如果超时或出错则返回空字符串
|
||||||
|
*/
|
||||||
|
std::string tcpSend(const std::string& data, int timeoutMs = 3000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 断开连接并清理Socket资源
|
||||||
|
*/
|
||||||
|
void clearSocket();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查是否已连接到服务器
|
||||||
|
* @return 连接状态
|
||||||
|
*/
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取最后一次的错误信息
|
||||||
|
* @return 错误描述
|
||||||
|
*/
|
||||||
|
std::string getLastError();
|
||||||
|
|
||||||
|
} // namespace sockAct
|
||||||
|
|
||||||
|
#endif // SOCKETACTIONS_H
|
||||||
35
TeacherSalaryMgmt_Qt.pro
Normal file
35
TeacherSalaryMgmt_Qt.pro
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
QT += core gui network
|
||||||
|
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
CONFIG += c++17
|
||||||
|
|
||||||
|
# You can make your code fail to compile if it uses deprecated APIs.
|
||||||
|
# In order to do so, uncomment the following line.
|
||||||
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
Modules/Logger.cpp \
|
||||||
|
Modules/methods.cpp \
|
||||||
|
Modules/socketactions.cpp \
|
||||||
|
dialoglogin.cpp \
|
||||||
|
main.cpp \
|
||||||
|
mainwindow.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
Modules/Logger.h \
|
||||||
|
Modules/global.h \
|
||||||
|
Modules/inicpp.hpp \
|
||||||
|
Modules/methods.h \
|
||||||
|
Modules/socketactions.h \
|
||||||
|
dialoglogin.h \
|
||||||
|
mainwindow.h
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
dialoglogin.ui \
|
||||||
|
mainwindow.ui
|
||||||
|
|
||||||
|
# Default rules for deployment.
|
||||||
|
qnx: target.path = /tmp/$${TARGET}/bin
|
||||||
|
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
|
!isEmpty(target.path): INSTALLS += target
|
||||||
115
dialoglogin.cpp
Normal file
115
dialoglogin.cpp
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include "dialoglogin.h"
|
||||||
|
#include "ui_dialoglogin.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "Modules/Logger.h"
|
||||||
|
#include "Modules/socketactions.h"
|
||||||
|
#include "Modules/methods.h"
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QString>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QIntValidator>
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
#pragma comment(lib, "user32.lib")
|
||||||
|
|
||||||
|
using std::to_string;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
structCheckBox checkBox;
|
||||||
|
structTextEdit textEdit;
|
||||||
|
structPushButton pushButton;
|
||||||
|
structLabel label;
|
||||||
|
structSession session;
|
||||||
|
|
||||||
|
extern string configPath;
|
||||||
|
extern structUserInfo userInfo;
|
||||||
|
|
||||||
|
DialogLogin::DialogLogin(QWidget *parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
, ui(new Ui::DialogLogin){
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
/*
|
||||||
|
* Place all elements handles here
|
||||||
|
*/
|
||||||
|
checkBox.rememberMe = findChild<QCheckBox*>("checkBox_rememberMe");
|
||||||
|
textEdit.username = findChild<QTextEdit*>("textEdit_username");
|
||||||
|
textEdit.passwd = findChild<QTextEdit*>("textEdit_passwd");
|
||||||
|
pushButton.ok = findChild<QPushButton*>("pushButton_ok");
|
||||||
|
pushButton.cancel = findChild<QPushButton*>("pushButton_cancel");
|
||||||
|
label.connStatus = findChild<QLabel*>("label_connStatus");
|
||||||
|
}
|
||||||
|
|
||||||
|
DialogLogin::~DialogLogin()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogLogin::enableAll() {
|
||||||
|
checkBox.rememberMe->setEnabled(true);
|
||||||
|
textEdit.username->setEnabled(true);
|
||||||
|
textEdit.passwd->setEnabled(true);
|
||||||
|
pushButton.ok->setEnabled(true);
|
||||||
|
pushButton.cancel->setEnabled(true);
|
||||||
|
label.connStatus->setText("Connected");
|
||||||
|
label.connStatus->setStyleSheet("QLabel { color: green; }");
|
||||||
|
if(userInfo.userName != "" && userInfo.passwd != ""){
|
||||||
|
tryLogin(userInfo.userName, userInfo.passwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogLogin::on_pushButton_ok_clicked()
|
||||||
|
{
|
||||||
|
QString username = textEdit.username->toPlainText();
|
||||||
|
QString passwd = textEdit.passwd->toPlainText();
|
||||||
|
|
||||||
|
if(username.isEmpty() && passwd.isEmpty()){
|
||||||
|
::MessageBoxA(NULL, "Username or Password can't be empty.", "Error", MB_OK|MB_ICONERROR);
|
||||||
|
}
|
||||||
|
if(!tryLogin(username.toStdString(), passwd.toStdString())){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DialogLogin::on_pushButton_cancel_clicked()
|
||||||
|
{
|
||||||
|
QApplication::quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DialogLogin::tryLogin(string userName, string passWd){
|
||||||
|
QString username = QString::fromStdString(userName);
|
||||||
|
QString passwd = QString::fromStdString(passWd);
|
||||||
|
|
||||||
|
if (username.isEmpty() || passwd.isEmpty()){
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
string resp = sockAct::tcpSend("[newUserEntry] <userName>" + username.toStdString() + "</userName> <userPasswd>" + passwd.toStdString() + "</userPasswd> <timeStamp>" + to_string(getUnixTimestamp()) + "</timeStamp>");
|
||||||
|
if(getTextMiddle(resp, "[", "]") == "Login_Accepted"){
|
||||||
|
session.userName = getTextMiddle(resp, "<userName>", "</userName>");
|
||||||
|
session.token = getTextMiddle(resp, "<token>", "</token>");
|
||||||
|
session.userID = getTextMiddle(resp, "<userID>", "</userID>");
|
||||||
|
is.loggedIn = true;
|
||||||
|
|
||||||
|
if(checkBox.rememberMe->isChecked()){
|
||||||
|
setKeyText(configPath, "userInfo", "userName", username.toStdString());
|
||||||
|
setKeyText(configPath, "userInfo", "passwd", passwd.toStdString());
|
||||||
|
}
|
||||||
|
userInfo.userName = username.toStdString();
|
||||||
|
userInfo.passwd = passwd.toStdString();
|
||||||
|
emit loadMainWindow();
|
||||||
|
this->close();
|
||||||
|
return true;
|
||||||
|
} else if (getTextMiddle(resp, "[", "]") == "Login_Rejected"){
|
||||||
|
::MessageBoxA(NULL, ("Login failed due to: " + resp.substr(resp.find_first_of(' '))).c_str(), "Login Failed", MB_OK|MB_ICONERROR);
|
||||||
|
postLog("[userLogin] Login rejected due to: " + resp, 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
69
dialoglogin.h
Normal file
69
dialoglogin.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#ifndef DIALOGLOGIN_H
|
||||||
|
#define DIALOGLOGIN_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "Modules/global.h"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
// struct structCheckBox {
|
||||||
|
// QCheckBox *rememberMe = nullptr;
|
||||||
|
// };
|
||||||
|
// extern structCheckBox checkBox;
|
||||||
|
|
||||||
|
// struct structTextEdit {
|
||||||
|
// QTextEdit *username = nullptr;
|
||||||
|
// QTextEdit *passwd = nullptr;
|
||||||
|
// };
|
||||||
|
// extern structTextEdit textEdit;
|
||||||
|
|
||||||
|
// struct structPushButton {
|
||||||
|
// QPushButton *ok = nullptr;
|
||||||
|
// QPushButton *cancel = nullptr;
|
||||||
|
// };
|
||||||
|
// extern structPushButton pushButton;
|
||||||
|
|
||||||
|
// struct structLabel {
|
||||||
|
// QLabel *connStatus = nullptr;
|
||||||
|
// };
|
||||||
|
// extern structLabel label;
|
||||||
|
|
||||||
|
// namespace Ui {
|
||||||
|
// class DialogLogin;
|
||||||
|
// }
|
||||||
|
|
||||||
|
class DialogLogin : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DialogLogin(QWidget *parent = nullptr);
|
||||||
|
~DialogLogin();
|
||||||
|
void enableAll();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loadMainWindow();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void on_pushButton_ok_clicked();
|
||||||
|
|
||||||
|
void on_pushButton_cancel_clicked();
|
||||||
|
|
||||||
|
bool tryLogin(string userName, string passWd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::DialogLogin *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
// struct structCheckBox{} dialogLogin_checkBox;
|
||||||
|
// struct structTextEdit{} dialogLogin_textEdit;
|
||||||
|
// struct structPushButton{} dialogLogin_pushButton;
|
||||||
|
// struct structLabel{} dialogLogin_label;
|
||||||
|
|
||||||
|
#endif // DIALOGLOGIN_H
|
||||||
217
dialoglogin.ui
Normal file
217
dialoglogin.ui
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DialogLogin</class>
|
||||||
|
<widget class="QDialog" name="DialogLogin">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>634</width>
|
||||||
|
<height>396</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>634</width>
|
||||||
|
<height>396</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>634</width>
|
||||||
|
<height>396</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Login to server</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>20</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>591</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Microsoft YaHei</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p>登录到 简单教师工资管理系统</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>50</x>
|
||||||
|
<y>130</y>
|
||||||
|
<width>101</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Username</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTextEdit" name="textEdit_username">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>150</x>
|
||||||
|
<y>130</y>
|
||||||
|
<width>411</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="tabChangesFocus">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::LineWrapMode::WidgetWidth</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTextEdit" name="textEdit_passwd">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>150</x>
|
||||||
|
<y>190</y>
|
||||||
|
<width>411</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="tabChangesFocus">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>50</x>
|
||||||
|
<y>190</y>
|
||||||
|
<width>101</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Password</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QCheckBox" name="checkBox_rememberMe">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>50</x>
|
||||||
|
<y>240</y>
|
||||||
|
<width>191</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Remember me on this device</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_connStatus">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>370</y>
|
||||||
|
<width>311</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="mouseTracking">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="acceptDrops">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Connecting...</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pushButton_ok">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>450</x>
|
||||||
|
<y>360</y>
|
||||||
|
<width>80</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>OK</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pushButton_cancel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>540</x>
|
||||||
|
<y>360</y>
|
||||||
|
<width>80</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
89
main.cpp
Normal file
89
main.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include "mainwindow.h"
|
||||||
|
#include "dialoglogin.h"
|
||||||
|
#include "Modules/inicpp.hpp"
|
||||||
|
#include "Modules/socketactions.h"
|
||||||
|
#include "Modules/Logger.h"
|
||||||
|
#include "Modules/global.h"
|
||||||
|
#include "Modules/methods.h"
|
||||||
|
#include <QApplication>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::to_string;
|
||||||
|
|
||||||
|
|
||||||
|
SOCKET clientSock;
|
||||||
|
//static bool isRunning = true;
|
||||||
|
structUserInfo userInfo;
|
||||||
|
|
||||||
|
string serverAddr;
|
||||||
|
int serverPort;
|
||||||
|
string configPath = ".\\Config.ini";
|
||||||
|
string debug_configPath = ".\\debug.ini";
|
||||||
|
|
||||||
|
struct globalAppInfo {
|
||||||
|
string appName = "Simple Teacher Salary Management";
|
||||||
|
string version = "0.0.0.1";
|
||||||
|
int buildVer = 0;
|
||||||
|
string buildDate = "2025-12-22";
|
||||||
|
string developer = "Madobi Nanami";
|
||||||
|
string buildType = "debug";
|
||||||
|
} appInfo;
|
||||||
|
|
||||||
|
void clientInit_loadConfig();
|
||||||
|
int str_toint(const string& str); // Convert string to int
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
postLog(appInfo.appName + " Ver." + appInfo.version + "." + to_string(appInfo.buildVer) + "." + appInfo.buildType, 1);
|
||||||
|
postLog("Developed by " + appInfo.developer + " on " + appInfo.buildDate, 1);
|
||||||
|
clientInit_loadConfig();
|
||||||
|
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
DialogLogin *p_DialogLogin = new DialogLogin;
|
||||||
|
MainWindow *p_MainWindow = nullptr;
|
||||||
|
p_DialogLogin->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
p_DialogLogin->show();
|
||||||
|
QObject::connect(p_DialogLogin, &DialogLogin::loadMainWindow, [&](){
|
||||||
|
p_MainWindow = new MainWindow;
|
||||||
|
p_MainWindow->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
p_MainWindow->show();
|
||||||
|
});
|
||||||
|
|
||||||
|
sockAct::sockInit();
|
||||||
|
postLog("[System] Trying to connect to " + serverAddr + ":" + to_string(serverPort), 1);
|
||||||
|
if(sockAct::connectToHost(serverAddr, serverPort)){
|
||||||
|
postLog("[Socket] Connected successfully to " + serverAddr + ":" + to_string(serverPort), 1);
|
||||||
|
p_DialogLogin->enableAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clientInit_loadConfig(){
|
||||||
|
if(is.debug == 1){
|
||||||
|
serverAddr = getKeyText(debug_configPath, "Main", "serverAddr");
|
||||||
|
serverPort = str_toint(getKeyText(debug_configPath, "Main", "serverPort"));
|
||||||
|
} else {
|
||||||
|
// <TODO>: Add formal serverAddr && serverPort
|
||||||
|
serverAddr = "localhost";
|
||||||
|
serverPort = 50010;
|
||||||
|
}
|
||||||
|
postLog("[System] Target server address has been set to: " + serverAddr + ":" + to_string(serverPort), 0);
|
||||||
|
userInfo.userName = getKeyText(configPath, "userInfo", "userName");
|
||||||
|
userInfo.passwd = getKeyText(configPath, "userInfo", "passwd");
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_toint(const string& str) {
|
||||||
|
try {
|
||||||
|
return stoi(str);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return 0; // or handle error as needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
371
mainwindow.cpp
Normal file
371
mainwindow.cpp
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
#include "mainwindow.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
#include "Modules/global.h"
|
||||||
|
#include "Modules/socketactions.h"
|
||||||
|
#include "Modules/Logger.h"
|
||||||
|
#include "Modules/methods.h"
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QTableWidget>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
structTableWidget tableWidget;
|
||||||
|
structComboBox comboBox;
|
||||||
|
extern structUserInfo userInfo;
|
||||||
|
extern structLabel label;
|
||||||
|
extern structPushButton pushButton;
|
||||||
|
extern structTextEdit textEdit;
|
||||||
|
extern structUserInfo userInfo;
|
||||||
|
extern structSession session;
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::to_string;
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
|
: QMainWindow(parent)
|
||||||
|
, ui(new Ui::MainWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
QLabel *sb_label_currentUser = new QLabel(("Current User: " + userInfo.userName).c_str(), this);
|
||||||
|
sb_label_currentUser->setMinimumWidth(100);
|
||||||
|
label.salaryActual = findChild<QLabel*>("label_salaryActual");
|
||||||
|
label.salaryDiscount = findChild<QLabel*>("label_salaryDiscount");
|
||||||
|
label.salaryShould = findChild<QLabel*>("label_salaryShould");
|
||||||
|
textEdit.search = findChild<QTextEdit*>("textEdit_search");
|
||||||
|
pushButton.clear = findChild<QPushButton*>("pushButton_clear");
|
||||||
|
pushButton.seacrh = findChild<QPushButton*>("pushButton_search");
|
||||||
|
pushButton.submit = findChild<QPushButton*>("pushButton_submit");
|
||||||
|
pushButton.remove = findChild<QPushButton*>("pushButton_remove");
|
||||||
|
comboBox.findBy = findChild<QComboBox*>("comboBox_findBy");
|
||||||
|
tableWidget.teacherInfo = findChild<QTableWidget*>("tableWidget_teacherInfo");
|
||||||
|
tableWidget.teacherSalary = findChild<QTableWidget*>("tableWidget_teacherSalary");
|
||||||
|
|
||||||
|
ui->statusbar->addWidget(sb_label_currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_search_clicked()
|
||||||
|
{
|
||||||
|
struct structSearch{
|
||||||
|
QString method;
|
||||||
|
QString content;
|
||||||
|
} search;
|
||||||
|
|
||||||
|
struct structTeacherInfo{
|
||||||
|
string id;
|
||||||
|
string name;
|
||||||
|
string gender;
|
||||||
|
string company;
|
||||||
|
string address;
|
||||||
|
string tel;
|
||||||
|
} teacherInfo;
|
||||||
|
|
||||||
|
struct structSalaryInfo{
|
||||||
|
string id;
|
||||||
|
string basicSalary;
|
||||||
|
string allowances;
|
||||||
|
string livingAllowances;
|
||||||
|
string phoneCost;
|
||||||
|
string waterPowerCost;
|
||||||
|
string incomeTax;
|
||||||
|
string houseRent;
|
||||||
|
string cleaningCost;
|
||||||
|
string houseingFund;
|
||||||
|
} salaryInfo;
|
||||||
|
|
||||||
|
struct structSalary{
|
||||||
|
int should;
|
||||||
|
int discount;
|
||||||
|
int actual;
|
||||||
|
} salary;
|
||||||
|
|
||||||
|
string searchResult = "";
|
||||||
|
search.method = comboBox.findBy->currentText();
|
||||||
|
search.content = textEdit.search->toPlainText();
|
||||||
|
if(search.method.isEmpty() && search.content.isEmpty()){
|
||||||
|
MessageBoxA(NULL, "Search method or context can't be empty.", "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if(search.method == "ID"){
|
||||||
|
searchResult = sockAct::tcpSend("[userGet] <userID>" + session.userID + "</userID> <userName>" + session.userName + "</userName> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp()) + "</timeStamp> <table>teacherInfo</table> <itemID>" + search.content.toStdString() + "</itemID> <valueType>all</valueType>");
|
||||||
|
postLog("[method.search] " + searchResult, 0);
|
||||||
|
if(getTextMiddle(searchResult, "[", "]") == "Get_Rejected"){
|
||||||
|
::MessageBoxA(NULL, ("Failed to get data. Reason: " + searchResult.substr(searchResult.find_first_of(' '))).c_str(), "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
teacherInfo.id = getTextMiddle(searchResult, "<itemID>", "</itemID>");
|
||||||
|
teacherInfo.name = getTextMiddle(searchResult, "<teacherName>", "</teacherName>");
|
||||||
|
teacherInfo.gender = getTextMiddle(searchResult, "<gender>", "</gender>");
|
||||||
|
teacherInfo.company = getTextMiddle(searchResult, "<companyName>", "</companyName>");
|
||||||
|
teacherInfo.address = getTextMiddle(searchResult, "<address>", "</address>");
|
||||||
|
teacherInfo.tel = getTextMiddle(searchResult, "<tel>", "</tel>");
|
||||||
|
|
||||||
|
tableWidget.teacherInfo->setItem(0, 0, new QTableWidgetItem(QString::fromStdString(teacherInfo.id)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 1, new QTableWidgetItem(QString::fromStdString(teacherInfo.name)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 2, new QTableWidgetItem(QString::fromStdString(teacherInfo.gender)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 3, new QTableWidgetItem(QString::fromStdString(teacherInfo.company)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 4, new QTableWidgetItem(QString::fromStdString(teacherInfo.address)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 5, new QTableWidgetItem(QString::fromStdString(teacherInfo.tel)));
|
||||||
|
}
|
||||||
|
|
||||||
|
searchResult = sockAct::tcpSend("[userGet] <userID>" + session.userID + "</userID> <userName>" + session.userName + "</userName> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp()) + "</timeStamp> <table>salaryForm</table> <itemID>" + search.content.toStdString() + "</itemID> <valueType>all</valueType>");
|
||||||
|
postLog("[method.search] " + searchResult, 0);
|
||||||
|
if(getTextMiddle(searchResult, "[", "]") == "Get_Rejected"){
|
||||||
|
::MessageBoxA(NULL, ("Failed to get data. Reason: " + searchResult.substr(searchResult.find_first_of(' '))).c_str(), "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
salaryInfo.id = getTextMiddle(searchResult, "<itemID>", "</itemID>");
|
||||||
|
salaryInfo.basicSalary = getTextMiddle(searchResult, "<basicSalary>", "</basicSalary>");
|
||||||
|
salaryInfo.allowances = getTextMiddle(searchResult, "<allowances>", "</allowances>");
|
||||||
|
salaryInfo.cleaningCost = getTextMiddle(searchResult, "<cleaningCost>", "</cleaningCost>");
|
||||||
|
salaryInfo.phoneCost = getTextMiddle(searchResult, "<phoneCost>", "</phoneCost>");
|
||||||
|
salaryInfo.waterPowerCost = getTextMiddle(searchResult, "<waterPowerCost>", "</waterPowerCost>");
|
||||||
|
salaryInfo.houseRent = getTextMiddle(searchResult, "<houseRent>", "</houseRent>");
|
||||||
|
salaryInfo.incomeTax = getTextMiddle(searchResult, "<incomeTax>", "</incomeTax>");
|
||||||
|
salaryInfo.livingAllowances = getTextMiddle(searchResult, "<livingAllowances>", "</livingAllowances>");
|
||||||
|
salaryInfo.houseingFund = getTextMiddle(searchResult, "<housingFund>", "</housingFund>");
|
||||||
|
|
||||||
|
tableWidget.teacherSalary->setItem(0, 0, new QTableWidgetItem(QString::fromStdString(salaryInfo.basicSalary)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 1, new QTableWidgetItem(QString::fromStdString(salaryInfo.allowances)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 2, new QTableWidgetItem(QString::fromStdString(salaryInfo.livingAllowances)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 3, new QTableWidgetItem(QString::fromStdString(salaryInfo.phoneCost)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 4, new QTableWidgetItem(QString::fromStdString(salaryInfo.waterPowerCost)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 5, new QTableWidgetItem(QString::fromStdString(salaryInfo.houseRent)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 6, new QTableWidgetItem(QString::fromStdString(salaryInfo.incomeTax)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 7, new QTableWidgetItem(QString::fromStdString(salaryInfo.cleaningCost)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 8, new QTableWidgetItem(QString::fromStdString(salaryInfo.houseingFund)));
|
||||||
|
|
||||||
|
salary.should = stoi(salaryInfo.basicSalary) + stoi(salaryInfo.allowances) + stoi(salaryInfo.livingAllowances);
|
||||||
|
salary.discount = stoi(salaryInfo.phoneCost) + stoi(salaryInfo.waterPowerCost) + stoi(salaryInfo.houseRent) + stoi(salaryInfo.incomeTax) + stoi(salaryInfo.cleaningCost) + stoi(salaryInfo.houseingFund);
|
||||||
|
salary.actual = salary.should - salary.discount;
|
||||||
|
label.salaryShould->setText(QString::fromStdString("应发工资: " + to_string(salary.should)));
|
||||||
|
label.salaryDiscount->setText(QString::fromStdString("合计扣款: " + to_string(salary.discount)));
|
||||||
|
label.salaryActual->setText(QString::fromStdString("实发工资: " + to_string(salary.actual)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(search.method == "Name"){
|
||||||
|
searchResult = sockAct::tcpSend("[userGet] <userID>" + session.userID + "</userID> <userName>" + session.userName + "</userName> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp()) + "</timeStamp> <table>teacherInfo</table> <itemID>" + search.content.toStdString() + "</itemID> <valueType>all</valueType>");
|
||||||
|
postLog("[method.search] " + searchResult, 0);
|
||||||
|
if(searchResult == "[Get_Rejected] ItemID does not exist."){
|
||||||
|
MessageBoxA(NULL, "Target item not found.", "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if(getTextMiddle(searchResult, "[", "]") == "Get_Rejected"){
|
||||||
|
::MessageBoxA(NULL, ("Failed to get data. Reason: " + searchResult.substr(searchResult.find_first_of(' '))).c_str(), "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
teacherInfo.id = getTextMiddle(searchResult, "<itemID>", "</itemID>");
|
||||||
|
teacherInfo.name = getTextMiddle(searchResult, "<teacherName>", "</teacherName>");
|
||||||
|
teacherInfo.gender = getTextMiddle(searchResult, "<gender>", "</gender>");
|
||||||
|
teacherInfo.company = getTextMiddle(searchResult, "<companyName>", "</companyName>");
|
||||||
|
teacherInfo.address = getTextMiddle(searchResult, "<address>", "</address>");
|
||||||
|
teacherInfo.tel = getTextMiddle(searchResult, "<tel>", "</tel>");
|
||||||
|
|
||||||
|
tableWidget.teacherInfo->setItem(0, 0, new QTableWidgetItem(QString::fromStdString(teacherInfo.id)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 1, new QTableWidgetItem(QString::fromStdString(teacherInfo.name)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 2, new QTableWidgetItem(QString::fromStdString(teacherInfo.gender)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 3, new QTableWidgetItem(QString::fromStdString(teacherInfo.company)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 4, new QTableWidgetItem(QString::fromStdString(teacherInfo.address)));
|
||||||
|
tableWidget.teacherInfo->setItem(0, 5, new QTableWidgetItem(QString::fromStdString(teacherInfo.tel)));
|
||||||
|
}
|
||||||
|
|
||||||
|
searchResult = sockAct::tcpSend("[userGet] <userID>" + session.userID + "</userID> <userName>" + session.userName + "</userName> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp()) + "</timeStamp> <table>salaryForm</table> <itemID>" + search.content.toStdString() + "</itemID> <valueType>all</valueType>");
|
||||||
|
postLog("[method.search] " + searchResult, 0);
|
||||||
|
if(getTextMiddle(searchResult, "[", "]") == "Get_Rejected"){
|
||||||
|
::MessageBoxA(NULL, ("Failed to get data. Reason: " + searchResult.substr(searchResult.find_first_of(' '))).c_str(), "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
salaryInfo.basicSalary = getTextMiddle(searchResult, "<basicSalary>", "</basicSalary>");
|
||||||
|
salaryInfo.cleaningCost = getTextMiddle(searchResult, "<cleaningCost>", "</cleaningCost>");
|
||||||
|
salaryInfo.phoneCost = getTextMiddle(searchResult, "<phoneCost>", "</phoneCost>");
|
||||||
|
salaryInfo.waterPowerCost = getTextMiddle(searchResult, "<waterPowerCost>", "</waterPowerCost>");
|
||||||
|
salaryInfo.houseRent = getTextMiddle(searchResult, "<houseRent>", "</houseRent>");
|
||||||
|
salaryInfo.incomeTax = getTextMiddle(searchResult, "<incomeTax>", "</incomeTax>");
|
||||||
|
salaryInfo.allowances = getTextMiddle(searchResult, "<allowances>", "</allowances>");
|
||||||
|
salaryInfo.livingAllowances = getTextMiddle(searchResult, "<livingAllowances>", "</livingAllowances>");
|
||||||
|
salaryInfo.houseingFund = getTextMiddle(searchResult, "<housingFund>", "</housingFund>");
|
||||||
|
|
||||||
|
tableWidget.teacherSalary->setItem(0, 0, new QTableWidgetItem(QString::fromStdString(salaryInfo.basicSalary)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 1, new QTableWidgetItem(QString::fromStdString(salaryInfo.allowances)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 2, new QTableWidgetItem(QString::fromStdString(salaryInfo.livingAllowances)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 3, new QTableWidgetItem(QString::fromStdString(salaryInfo.phoneCost)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 4, new QTableWidgetItem(QString::fromStdString(salaryInfo.waterPowerCost)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 5, new QTableWidgetItem(QString::fromStdString(salaryInfo.houseRent)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 6, new QTableWidgetItem(QString::fromStdString(salaryInfo.incomeTax)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 7, new QTableWidgetItem(QString::fromStdString(salaryInfo.cleaningCost)));
|
||||||
|
tableWidget.teacherSalary->setItem(0, 8, new QTableWidgetItem(QString::fromStdString(salaryInfo.houseingFund)));
|
||||||
|
|
||||||
|
salary.should = stoi(salaryInfo.basicSalary) + stoi(salaryInfo.allowances) + stoi(salaryInfo.livingAllowances);
|
||||||
|
salary.discount = stoi(salaryInfo.phoneCost) + stoi(salaryInfo.waterPowerCost) + stoi(salaryInfo.houseRent) + stoi(salaryInfo.incomeTax) + stoi(salaryInfo.cleaningCost) + stoi(salaryInfo.houseingFund);
|
||||||
|
salary.actual = salary.should - salary.discount;
|
||||||
|
label.salaryShould->setText(QString::fromStdString("应发工资: " + to_string(salary.should)));
|
||||||
|
label.salaryDiscount->setText(QString::fromStdString("合计扣款: " + to_string(salary.discount)));
|
||||||
|
label.salaryActual->setText(QString::fromStdString("实发工资: " + to_string(salary.actual)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_submit_clicked()
|
||||||
|
{
|
||||||
|
struct structTeacherInfo{
|
||||||
|
string id = tableWidget.teacherInfo->item(0, 0)->text().toStdString();
|
||||||
|
string name = tableWidget.teacherInfo->item(0, 1)->text().toStdString();
|
||||||
|
string gender = tableWidget.teacherInfo->item(0, 2)->text().toStdString();
|
||||||
|
string company = tableWidget.teacherInfo->item(0, 3)->text().toStdString();
|
||||||
|
string address = tableWidget.teacherInfo->item(0, 4)->text().toStdString();
|
||||||
|
string tel = tableWidget.teacherInfo->item(0, 5)->text().toStdString();
|
||||||
|
} teacherInfo;
|
||||||
|
|
||||||
|
struct structSalaryInfo{
|
||||||
|
string id = tableWidget.teacherInfo->item(0, 0)->text().toStdString();
|
||||||
|
string basicSalary = tableWidget.teacherSalary->item(0, 0)->text().toStdString();
|
||||||
|
string allowances = tableWidget.teacherSalary->item(0, 1)->text().toStdString();
|
||||||
|
string livingAllowances = tableWidget.teacherSalary->item(0, 2)->text().toStdString();
|
||||||
|
string phoneCost = tableWidget.teacherSalary->item(0, 3)->text().toStdString();
|
||||||
|
string waterPowerCost = tableWidget.teacherSalary->item(0, 4)->text().toStdString();
|
||||||
|
string incomeTax = tableWidget.teacherSalary->item(0, 6)->text().toStdString();
|
||||||
|
string houseRent = tableWidget.teacherSalary->item(0, 5)->text().toStdString();
|
||||||
|
string cleaningCost = tableWidget.teacherSalary->item(0, 7)->text().toStdString();
|
||||||
|
string houseingFund = tableWidget.teacherSalary->item(0, 8)->text().toStdString();
|
||||||
|
} salaryInfo;
|
||||||
|
|
||||||
|
if(teacherInfo.id == "" && teacherInfo.name == ""){
|
||||||
|
MessageBoxA(NULL, "Name or ID can't be empty.", "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < 6; i++){
|
||||||
|
string nowColumn;
|
||||||
|
string nowItem;
|
||||||
|
switch (i){
|
||||||
|
case 0:
|
||||||
|
nowColumn = "teacherID";
|
||||||
|
nowItem = teacherInfo.id;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
nowColumn = "teacherName";
|
||||||
|
nowItem = teacherInfo.name;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
nowColumn = "gender";
|
||||||
|
nowItem = teacherInfo.gender;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
nowColumn = "companyName";
|
||||||
|
nowItem = teacherInfo.company;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
nowColumn = "address";
|
||||||
|
nowItem = teacherInfo.address;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
nowColumn = "tel";
|
||||||
|
nowItem = teacherInfo.tel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
string resp = sockAct::tcpSend("[userSet] <userID>" + session.userID + "</userID> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp())+ "</timeStamp> <table>teacherInfo</table> <itemID>" + teacherInfo.id + "</itemID> <valueType>" + nowColumn + "</valueType> <value>" + nowItem + "</value>");
|
||||||
|
}
|
||||||
|
for(int i = 0; i < 11; i++){
|
||||||
|
string nowColumn;
|
||||||
|
string nowItem;
|
||||||
|
switch (i){
|
||||||
|
case 0:
|
||||||
|
nowColumn = "teacherID";
|
||||||
|
nowItem = teacherInfo.id;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
nowColumn = "teacherName";
|
||||||
|
nowItem = teacherInfo.name;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
nowColumn = "basicSalary";
|
||||||
|
nowItem = salaryInfo.basicSalary;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
nowColumn = "allowances";
|
||||||
|
nowItem = salaryInfo.allowances;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
nowColumn = "livingAllowances";
|
||||||
|
nowItem = salaryInfo.livingAllowances;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
nowColumn = "phoneCost";
|
||||||
|
nowItem = salaryInfo.phoneCost;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
nowColumn = "waterPowerCost";
|
||||||
|
nowItem = salaryInfo.waterPowerCost;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
nowColumn = "houseRent";
|
||||||
|
nowItem = salaryInfo.houseRent;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
nowColumn = "incomeTax";
|
||||||
|
nowItem = salaryInfo.incomeTax;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
nowColumn = "cleaningCost";
|
||||||
|
nowItem = salaryInfo.cleaningCost;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
nowColumn = "housingFund";
|
||||||
|
nowItem = salaryInfo.houseingFund;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
string resp = sockAct::tcpSend("[userSet] <userID>" + session.userID + "</userID> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp())+ "</timeStamp> <table>salaryForm</table> <itemID>" + teacherInfo.id + "</itemID> <valueType>" + nowColumn + "</valueType> <value>" + nowItem + "</value>");
|
||||||
|
}
|
||||||
|
MessageBoxA(NULL, "Submitted.", "Info", MB_OK|MB_ICONINFORMATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_remove_clicked()
|
||||||
|
{
|
||||||
|
struct structTeacherInfo{
|
||||||
|
string id = tableWidget.teacherInfo->item(0, 0)->text().toStdString();
|
||||||
|
string name = tableWidget.teacherInfo->item(0, 1)->text().toStdString();
|
||||||
|
string gender = tableWidget.teacherInfo->item(0, 2)->text().toStdString();
|
||||||
|
string company = tableWidget.teacherInfo->item(0, 3)->text().toStdString();
|
||||||
|
string address = tableWidget.teacherInfo->item(0, 4)->text().toStdString();
|
||||||
|
string tel = tableWidget.teacherInfo->item(0, 5)->text().toStdString();
|
||||||
|
} teacherInfo;
|
||||||
|
string resp = sockAct::tcpSend("[userDel] <userID>" + session.userID + "</userID> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp())+ "</timeStamp> <table>teacherInfo</table> <itemID>" + teacherInfo.id + "</itemID>");
|
||||||
|
if (getTextMiddle(resp, "[", "]") == "Del_Rejected"){
|
||||||
|
postLog("[method.del] Failed to remove due to " + resp.substr(resp.find_first_of(' ')), 3);
|
||||||
|
::MessageBoxA(NULL, ("Failed to remove item. Reason: " + resp.substr(resp.find_first_of(' '))).c_str(), "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
string resp = sockAct::tcpSend("[userDel] <userID>" + session.userID + "</userID> <token>" + session.token + "</token> <timeStamp>" + to_string(getUnixTimestamp())+ "</timeStamp> <table>salaryForm</table> <itemID>" + teacherInfo.id + "</itemID>");
|
||||||
|
if (getTextMiddle(resp, "[", "]") == "Del_Rejected"){
|
||||||
|
postLog("[method.del] Failed to remove due to " + resp.substr(resp.find_first_of(' ')), 3);
|
||||||
|
::MessageBoxA(NULL, ("Failed to remove item. Reason: " + resp.substr(resp.find_first_of(' '))).c_str(), "Error", MB_OK|MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MessageBoxA(NULL, "Remove successfully.", "Info", MB_OK|MB_ICONINFORMATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_clear_clicked()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 6; i++){
|
||||||
|
tableWidget.teacherInfo->setItem(0, i, new QTableWidgetItem(""));
|
||||||
|
}
|
||||||
|
for(int i = 0; i < 10; i++){
|
||||||
|
tableWidget.teacherSalary->setItem(0, i, new QTableWidgetItem(""));
|
||||||
|
}
|
||||||
|
label.salaryShould->setText(QString::fromStdString("应发工资: "));
|
||||||
|
label.salaryDiscount->setText(QString::fromStdString("合计扣款: "));
|
||||||
|
label.salaryActual->setText(QString::fromStdString("实发工资: "));
|
||||||
|
}
|
||||||
|
|
||||||
33
mainwindow.h
Normal file
33
mainwindow.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MainWindow(QWidget *parent = nullptr);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_pushButton_search_clicked();
|
||||||
|
|
||||||
|
void on_pushButton_submit_clicked();
|
||||||
|
|
||||||
|
void on_pushButton_remove_clicked();
|
||||||
|
|
||||||
|
void on_pushButton_clear_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
};
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
376
mainwindow.ui
Normal file
376
mainwindow.ui
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>953</width>
|
||||||
|
<height>395</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>953</width>
|
||||||
|
<height>395</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>953</width>
|
||||||
|
<height>395</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<kerning>true</kerning>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Simple Teacher Salary Management System</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>54245225</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTipDuration">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dockOptions">
|
||||||
|
<set>QMainWindow::DockOption::AllowTabbedDocks|QMainWindow::DockOption::AnimatedDocks</set>
|
||||||
|
</property>
|
||||||
|
<property name="unifiedTitleAndToolBarOnMac">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<widget class="QPushButton" name="pushButton_submit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>819</x>
|
||||||
|
<y>320</y>
|
||||||
|
<width>121</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Submit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>61</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<kerning>true</kerning>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Find by</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QComboBox" name="comboBox_findBy">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>70</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>72</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>ID</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pushButton_search">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>860</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>80</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Search</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pushButton_clear">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>320</y>
|
||||||
|
<width>121</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>931</width>
|
||||||
|
<height>271</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Info Center</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>20</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>191</width>
|
||||||
|
<height>231</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Personal Info</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTableWidget" name="tableWidget_teacherInfo">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>220</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>691</width>
|
||||||
|
<height>71</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Microsoft YaHei UI</family>
|
||||||
|
<kerning>true</kerning>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<row/>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>ID</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>姓名</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>性别</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>单位名称</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>家庭住址</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>联系电话</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTableWidget" name="tableWidget_teacherSalary">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>220</x>
|
||||||
|
<y>130</y>
|
||||||
|
<width>691</width>
|
||||||
|
<height>71</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Microsoft YaHei UI</family>
|
||||||
|
<kerning>true</kerning>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<row/>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>基本工资</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>津贴</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>生活补贴</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>电话费</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>水电费</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>房租</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>所得税</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>卫生费</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>公积金</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_salaryShould">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>220</x>
|
||||||
|
<y>220</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Microsoft YaHei</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<kerning>true</kerning>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>应发工资: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_salaryDiscount">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>500</x>
|
||||||
|
<y>220</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Microsoft YaHei</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<kerning>true</kerning>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>合计扣款: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label_salaryActual">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>780</x>
|
||||||
|
<y>220</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Microsoft YaHei</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<kerning>true</kerning>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>实发工资: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTextEdit" name="textEdit_search">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>150</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>701</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="tabChangesFocus">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pushButton_remove">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>409</x>
|
||||||
|
<y>320</y>
|
||||||
|
<width>121</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<zorder>pushButton_submit</zorder>
|
||||||
|
<zorder>label</zorder>
|
||||||
|
<zorder>comboBox_findBy</zorder>
|
||||||
|
<zorder>pushButton_search</zorder>
|
||||||
|
<zorder>groupBox</zorder>
|
||||||
|
<zorder>textEdit_search</zorder>
|
||||||
|
<zorder>pushButton_remove</zorder>
|
||||||
|
<zorder>pushButton_clear</zorder>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>953</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user