commit 5c04a7368c1e4e12005925ae79a9ab0a3b7a91b3 Author: taynpg Date: Sun May 5 22:55:58 2024 +0800 初版转成cmake工程版本 diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..18fbbc4 --- /dev/null +++ b/.clang-format @@ -0,0 +1,38 @@ +# .clang-format + +# 风格格式化 +BasedOnStyle: LLVM +# 4 空格缩进 +IndentWidth: 4 +# 连续对齐变量的声明 +AlignConsecutiveDeclarations: true +# 指针左侧对齐 +PointerAlignment: Left +# 访问说明符(public、private等)的偏移 +AccessModifierOffset: -4 +# 大括号 +BreakBeforeBraces: Custom +BraceWrapping: + # 函数定义后面大括号在新行 + AfterFunction: true + # class定义后面 + AfterClass: true + +# 去除C++11的列表初始化的大括号{后和}前的空格 +Cpp11BracedListStyle: true +# 允许重新排版注释 +ReflowComments: true +# 允许排序#include +SortIncludes: true +# 在尾随的评论前添加的空格数(只适用于//) +SpacesBeforeTrailingComments: 3 +# tab宽度 +TabWidth: 4 +# 构造函数的初始化列表要么都在同一行,要么都各自一行 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +# 每行字符的限制,0表示没有限制 +ColumnLimit: 150 +# 允许短的块放在同一行 +AllowShortBlocksOnASingleLine: false +# 是否允许短函数在一行 +AllowShortFunctionsOnASingleLine: InlineOnly \ No newline at end of file diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..11d6e06 --- /dev/null +++ b/.clangd @@ -0,0 +1,12 @@ +Hover: + ShowAKA: Yes +Diagnostics: + UnusedIncludes: None # 禁用未使用头文件提示 + Suppress: [ + anon_type_definition, # 禁用匿名的typedef提示 + unused-variable, # 禁用未使用变量提示 + unused-function, # 禁用未使用函数提示 + unused-includes, # 禁用未使用的头文件提示 + ] + ClangTidy: + Remove: misc-unused-alias-decls diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ff8bda6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +.vs +.cache \ No newline at end of file diff --git a/.vscode/qt5.natvis b/.vscode/qt5.natvis new file mode 100644 index 0000000..7d18567 --- /dev/null +++ b/.vscode/qt5.natvis @@ -0,0 +1,814 @@ + + + + + + + {{{data1,Xb}-{data2,Xb}-{data3,Xb}-{(data4[0]),nvoXb}{(data4[1]),nvoXb}-{(data4[2]),nvoXb}{(data4[3]),nvoXb}{(data4[4]),nvoXb}{(data4[5]),nvoXb}{(data4[6]),nvoXb}{(data4[7]),nvoXb}}} + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {x1}, y = {y1}, width = {x2 - x1 + 1}, height = {y2 - y1 + 1} }} + + x1 + y1 + x2 - x1 + 1 + y2 - y1 + 1 + + + + + {{ x = {xp}, y = {yp}, width = {w}, height = {h} }} + + xp + yp + w + h + + + + + + {{ width = {wd}, height = {ht} }} + + wd + ht + + + + + + {{ start point = {pt1}, end point = {pt2} }} + + + {pt1} + + pt1 + + + + {pt2} + + pt2 + + + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + (QPoint*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ size = {d->size} }} + + + d->size > 0 + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).xp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).xp) + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).yp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).yp) + + d->ref.atomic._q_value + + d->size + (QPointF*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {xp}, y = {yp}, z = {zp} }} + + xp + yp + zp + + + + + {{ x = {xp}, y = {yp}, z = {zp}, w = {wp} }} + + xp + yp + zp + wp + + + + + + {{ m11 = {_m11}, m12 = {_m12}, m21 = {_m21}, m22 = {_m22}, ... }} + + + _m11 + _m12 + _m21 + _m22 + _dx + _dy + + + + + + {{ m11 = {m[0][0]}, m12 = {m[1][0]}, m13 = {m[2][0]}, m14 = {m[3][0]}, ... }} + + + m[0][0] + m[1][0] + m[2][0] + m[3][0] + m[0][1] + m[1][1] + m[2][1] + m[3][1] + m[0][2] + m[1][2] + m[2][2] + m[3][2] + m[0][3] + m[1][3] + m[2][3] + m[3][3] + + + + + + {{ horizontal = {static_cast<Policy>(bits.horPolicy)}, vertical = {static_cast<Policy>(bits.verPolicy)}, type = {ControlType(1 << bits.ctype)} }} + + + + QSizePolicy::Policy::{static_cast<Policy>(bits.verPolicy)} + + + QSizePolicy::Policy::{static_cast<Policy>(bits.horPolicy)} + + + QSizePolicy::ControlType::{ControlType(1 << bits.ctype)} + + + + Qt::Vertical (2) + + + Qt::Horizontal (1) + + + static_cast<int>(bits.verStretch) + static_cast<int>(bits.horStretch) + bits.hfw == 1 + bits.wfh == 1 + + + + + {ucs,c} + ucs,c + + ucs > 0xff ? '\0' : char(ucs),c + ucs,c + + + + + {((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),sub} + ((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),sub + + d->size + d->ref.atomic._q_value + + d->size + ((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),c + + + + + + + {m_string,[m_size]} u"" + {offset() + m_position,[m_size]} + + m_position + m_size + + m_size + offset()+m_position + + + + + + {m_data,[m_size]} + m_data,[m_size] + + m_size + + m_size + m_data + + + + + + {((reinterpret_cast<char*>(d)) + d->offset),sb} + ((reinterpret_cast<char*>(d)) + d->offset),sb + + d->size + d->ref.atomic._q_value + + d->size + ((reinterpret_cast<char*>(d)) + d->offset),c + + + + + + + + + + + + + + + + + + + + {scheme()}://{host()}{path()} + {path()} + + scheme() + username() + password() + host() + path() + query() + fragment() + + + + + {{ size = {(d.d->size << 3) - *((reinterpret_cast<char*>(d.d)) + d.d->offset)} }} + + d.d->ref.atomic._q_value + + (d.d->size << 3) - *((reinterpret_cast<char*>(d.d)) + d.d->offset) + + (*(reinterpret_cast<const unsigned char*>((reinterpret_cast<char*>(d.d)) + d.d->offset) + 1 + + ($i >> 3)) & (1 << ($i & 7))) != 0 + + + + + + + + {{ size = {s} }} + + a + + s + ptr + + + + + + {{ julian day = {jd} }} + + + + + {{ millisecond = {mds} }} + {{ milliseconds = {mds} }} + + mds / 3600000, d + mds / 3600000, d + (mds % 3600000) / 60000, d + (mds % 3600000) / 60000, d + (mds / 1000) % 60, d + (mds / 1000) % 60, d + mds % 1000, d + mds % 1000, d + + + + + {d.pattern} + + + + + ref._q_value + + + + + strong reference to shared pointer of type {"$T1"} + + value == 0 + d->weakref._q_value + d->strongref._q_value + + + + + pointer to implicit shared object of type {"$T1"} + + d + + + + + pointer to explicit shared object of type {"$T1"} + + d + + + + + guarded pointer to subclass of QObject of type {"$T1"} + + wp.d == 0 || wp.d->strongref._q_value == 0 || wp.value == 0 + + + + + weak reference to shared pointer of type {"$T1"} + + d == 0 || d->strongref._q_value == 0 || value == 0 + d->weakref._q_value + d->strongref._q_value + + + + + scoped pointer to a dynamically allocated object of type {"$T1"} + + !d + + + + + scoped pointer to dynamically allocated array of objects of type {"$T1"} + + !d + + + + + ({first}, {second}) + + first + second + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + ($T1*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + + {{ size = {d->end - d->begin} }} + + d->ref.atomic._q_value + + d->end - d->begin + *reinterpret_cast<$T1*>((sizeof($T1) > sizeof(void*)) + ? reinterpret_cast<Node*>(d->array + d->begin + $i)->v + : reinterpret_cast<$T1*>(d->array + d->begin + $i)) + + + + + + + {{ size = {d->end - d->begin} }} + + d->ref.atomic._q_value + + d->end - d->begin + + *reinterpret_cast<QString*>((sizeof(QString) > sizeof(void*)) + ? reinterpret_cast<Node*>(d->array + d->begin + $i)->v + : reinterpret_cast<QString*>(d->array + d->begin + $i)) + + + + + + + {{ size = {d->end - d->begin} }} + + d->ref.atomic._q_value + + d->end - d->begin + + *reinterpret_cast<QVariant*>((sizeof(QVariant) > sizeof(void*)) + ? reinterpret_cast<Node*>(d->array + d->begin + $i)->v + : reinterpret_cast<QVariant*>(d->array + d->begin + $i)) + + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + d->n + n + (*(QLinkedListNode<$T1>*)this).t + + + + + + ({key}, {value}) + + key + value + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + d->header.left + left + right + *((QMapNode<$T1,$T2>*)this) + + + + + + (empty) + ({key}, {value}) + + key + value + next + + + + + + {{ size = {d->size} }} + + + d->numBuckets + reinterpret_cast<Node **>(d->buckets) + + + + + + + d->size + + + node = *(bucket++) + --n + + + keyValuePair = reinterpret_cast<Node *>(node) + keyValuePair->value + node = node->next + + + + + + + + (empty) + ({key}) + + key + + + + + {{ size = {q_hash.d->size} }} + + q_hash + + + + + ({*keyPtr}, {*t}) + + *keyPtr + *t + + + + + {{ size = {hash.d->size} }} + + mx + total + hash.d->ref.atomic._q_value + + hash.d->size + f + n + *((Node*)this) + + + + + + + + + + + + + + {{ row count = {(*d_ptr.d).rows()}, column count = {(*d_ptr.d).columns()} }} + + d_ptr.d,! + (*d_ptr.d).rows() + (*d_ptr.d).columns() + + + + + + + Invalid + {d.data.b} + {d.data.i} + {d.data.u} + {d.data.ll} + {d.data.ull} + {d.data.d} + {d.data.c} + + {*((QMap<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QList<QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QString*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QStringList*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QByteArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QBitArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QDate*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QTime*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + DateTime + Url + Locale + + {*((QRect*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QRectF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QSize*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QSizeF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QLine*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QLineF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QPoint*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QPointF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + RegExp + RegularExpression + + {*((QHash<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + EasingCurve + Uuid + ModelIndex + LastCoreType + Font + Pixmap + Brush + Color + Palette + Image + Polygon + Region + Bitmap + Cursor + KeySequence + Pen + TextLength + TextFormat + Matrix + Transform + Matrix4x4 + Vector2D + Vector3D + Vector4D + Quaternion + PolygonF + Icon + LastGuiType + SizePolicy + UserType + LastType + + + + + + d.data.c + + + *((QString*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + + *((QByteArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + + + + + + + *((QMap<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QList<QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QString*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QStringList*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QByteArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QBitArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QDate*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QTime*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QRect*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QRectF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QSize*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QSizeF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QLine*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QLineF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QPoint*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QPointF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QHash<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + + + + + diff --git a/.vscode/qt6.natvis b/.vscode/qt6.natvis new file mode 100644 index 0000000..94c2260 --- /dev/null +++ b/.vscode/qt6.natvis @@ -0,0 +1,735 @@ + + + + + + + {val} + + val + + + + + + + + {{ x = {x,g}, y = {y,g}, z = {_extraData().z,g}, width = {width,g}, height = {height,g} }} + {{ x = {x,g}, y = {y,g}, width = {width,g}, height = {height,g} }} + + x + y + _extraData().z + _extraData().scale + _extraData().rotation + _extraData().opacity + width + height + implicitWidth + implicitHeight + effectiveVisible + explicitEnable + _objectName(),na + parentItem + childItems, nr + + + + + {d_ptr.d,na} + + d_ptr.d + + + + + {{{data1,Xb}-{data2,Xb}-{data3,Xb}-{(data4[0]),nvoXb}{(data4[1]),nvoXb}-{(data4[2]),nvoXb}{(data4[3]),nvoXb}{(data4[4]),nvoXb}{(data4[5]),nvoXb}{(data4[6]),nvoXb}{(data4[7]),nvoXb}}} + + + + {val} + + val + + + + + {_q_value} + + _q_value + + + + + + + empty + {_q_value} + + *value() + + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {x1}, y = {y1}, width = {x2 - x1 + 1}, height = {y2 - y1 + 1} }} + + x1 + y1 + x2 - x1 + 1 + y2 - y1 + 1 + + + + + {{ x = {xp}, y = {yp}, width = {w}, height = {h} }} + + xp + yp + w + h + + + + + + {{ width = {wd}, height = {ht} }} + + wd + ht + + + + + + {{ start point = {pt1}, end point = {pt2} }} + + + {pt1} + + pt1 + + + + {pt2} + + pt2 + + + + + + + + {{ size={d->size} }} + + d->ref.atomic._q_value + + d->size + (QPoint*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ size={d->size} }} + + + d->size > 0 + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).xp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).xp) + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).yp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).yp) + + d->ref.atomic._q_value + + d->size + (QPointF*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {xp}, y = {yp}, z = {zp} }} + + xp + yp + zp + + + + + {{ x = {xp}, y = {yp}, z = {zp}, w = {wp} }} + + xp + yp + zp + wp + + + + + + {{ m11 = {_m11}, m12 = {_m12}, m21 = {_m21}, m22 = {_m22}, ... }} + + + _m11 + _m12 + _m21 + _m22 + _dx + _dy + + + + + + {{ m11 = {m[0][0]}, m12 = {m[1][0]}, m13 = {m[2][0]}, m14 = {m[3][0]}, ... }} + + + m[0][0] + m[1][0] + m[2][0] + m[3][0] + m[0][1] + m[1][1] + m[2][1] + m[3][1] + m[0][2] + m[1][2] + m[2][2] + m[3][2] + m[0][3] + m[1][3] + m[2][3] + m[3][3] + + + + + + {{ horizontal = {static_cast<Policy>(bits.horPolicy)}, vertical = {static_cast<Policy>(bits.verPolicy)}, type = {ControlType(1 << bits.ctype)} }} + + + + QSizePolicy::Policy::{static_cast<Policy>(bits.verPolicy)} + + + QSizePolicy::Policy::{static_cast<Policy>(bits.horPolicy)} + + + QSizePolicy::ControlType::{ControlType(1 << bits.ctype)} + + + + Qt::Vertical (2) + + + Qt::Horizontal (1) + + + static_cast<int>(bits.verStretch) + static_cast<int>(bits.horStretch) + bits.hfw == 1 + bits.wfh == 1 + + + + + {ucs,c} + ucs,c + + ucs > 0xff ? '\0' : char(ucs),c + ucs,c + + + + + "{(reinterpret_cast<unsigned short*>(d.ptr)),sub}" + (reinterpret_cast<unsigned short*>(d.ptr)),sub + + d.size + + d.size + d.ptr + + + + + + {m_string,[m_size]} u"" + {m_string->d.ptr+m_position,[m_size]} + "" + m_string,[m_position+m_size] + + m_position + m_size + + m_size + m_string->d.ptr+m_position + + + + + + {m_data,[m_size]} + m_data,[m_size] + + m_size + + m_size + m_data + + + + + + "{((reinterpret_cast<char*>(d.ptr))),sb}" + ((reinterpret_cast<char*>(d.ptr))),sb + + d.size + + d.size + d.ptr + + + + + + + + + + + + + + + + + + + + {scheme()}://{host()}{path()} + {path()} + + scheme() + username() + password() + host() + path() + query() + fragment() + + + + + {{ julian day = {jd} }} + + + + + + + + {{ millisecond = {mds} }} + {{ milliseconds = {mds} }} + + hour(), d + hour(), d + minute(), d + minute(), d + second(), d + second(), d + millisecond(), d + millisecond(), d + + + + + ({first}, {second}) + + first + second + + + + + + {{ size={d.size} }} + + + d.size + reinterpret_cast<$T1*>(d.ptr) + + + + + + {{ size={s} }} + + a + + s + ptr + + + + + + + {{ size={d.d->m._Mypair._Myval2._Myval2._Mysize} }} + + + d.d->m._Mypair._Myval2._Myval2._Mysize + d.d->m._Mypair._Myval2._Myval2._Myhead->_Parent + _Left + _Right + _Myval,view(MapHelper) + + + + + + {second} + + + + {value} + + key + value + + + + + {value->value} + ({value->value}, {value->next->value}) + ({value->value}, {value->next->value}, ...) + + + value + next + value + + + + + + + + + + + + + + + + + + + + {{ size={d->size} }} + + + + + d->size + + + getNode(iSpan, 0) + getNode(iSpan, 1) + getNode(iSpan, 2) + getNode(iSpan, 3) + getNode(iSpan, 4) + getNode(iSpan, 5) + getNode(iSpan, 6) + getNode(iSpan, 7) + getNode(iSpan, 8) + getNode(iSpan, 9) + getNode(iSpan, 10) + getNode(iSpan, 11) + getNode(iSpan, 12) + getNode(iSpan, 13) + getNode(iSpan, 14) + getNode(iSpan, 15) + getNode(iSpan, 16) + getNode(iSpan, 17) + getNode(iSpan, 18) + getNode(iSpan, 19) + getNode(iSpan, 20) + getNode(iSpan, 21) + getNode(iSpan, 22) + getNode(iSpan, 23) + getNode(iSpan, 24) + getNode(iSpan, 25) + getNode(iSpan, 26) + getNode(iSpan, 27) + getNode(iSpan, 28) + getNode(iSpan, 29) + getNode(iSpan, 30) + getNode(iSpan, 31) + getNode(iSpan, 32) + getNode(iSpan, 33) + getNode(iSpan, 34) + getNode(iSpan, 35) + getNode(iSpan, 36) + getNode(iSpan, 37) + getNode(iSpan, 38) + getNode(iSpan, 39) + getNode(iSpan, 40) + getNode(iSpan, 41) + getNode(iSpan, 42) + getNode(iSpan, 43) + getNode(iSpan, 44) + getNode(iSpan, 45) + getNode(iSpan, 46) + getNode(iSpan, 47) + getNode(iSpan, 48) + getNode(iSpan, 49) + getNode(iSpan, 50) + getNode(iSpan, 51) + getNode(iSpan, 52) + getNode(iSpan, 53) + getNode(iSpan, 54) + getNode(iSpan, 55) + getNode(iSpan, 56) + getNode(iSpan, 57) + getNode(iSpan, 58) + getNode(iSpan, 59) + getNode(iSpan, 60) + getNode(iSpan, 61) + getNode(iSpan, 62) + getNode(iSpan, 63) + getNode(iSpan, 64) + getNode(iSpan, 65) + getNode(iSpan, 66) + getNode(iSpan, 67) + getNode(iSpan, 68) + getNode(iSpan, 69) + getNode(iSpan, 70) + getNode(iSpan, 71) + getNode(iSpan, 72) + getNode(iSpan, 73) + getNode(iSpan, 74) + getNode(iSpan, 75) + getNode(iSpan, 76) + getNode(iSpan, 77) + getNode(iSpan, 78) + getNode(iSpan, 79) + getNode(iSpan, 80) + getNode(iSpan, 81) + getNode(iSpan, 82) + getNode(iSpan, 83) + getNode(iSpan, 84) + getNode(iSpan, 85) + getNode(iSpan, 86) + getNode(iSpan, 87) + getNode(iSpan, 88) + getNode(iSpan, 89) + getNode(iSpan, 90) + getNode(iSpan, 91) + getNode(iSpan, 92) + getNode(iSpan, 93) + getNode(iSpan, 94) + getNode(iSpan, 95) + getNode(iSpan, 96) + getNode(iSpan, 97) + getNode(iSpan, 98) + getNode(iSpan, 99) + getNode(iSpan, 100) + getNode(iSpan, 101) + getNode(iSpan, 102) + getNode(iSpan, 103) + getNode(iSpan, 104) + getNode(iSpan, 105) + getNode(iSpan, 106) + getNode(iSpan, 107) + getNode(iSpan, 108) + getNode(iSpan, 109) + getNode(iSpan, 110) + getNode(iSpan, 111) + getNode(iSpan, 112) + getNode(iSpan, 113) + getNode(iSpan, 114) + getNode(iSpan, 115) + getNode(iSpan, 116) + getNode(iSpan, 117) + getNode(iSpan, 118) + getNode(iSpan, 119) + getNode(iSpan, 120) + getNode(iSpan, 121) + getNode(iSpan, 122) + getNode(iSpan, 123) + getNode(iSpan, 124) + getNode(iSpan, 125) + getNode(iSpan, 126) + getNode(iSpan, 127) + iSpan++ + + + + + + + + {{ size={q_hash.d->size} }} + + q_hash + + + + + + + + + + + + (null) + + + QObject* + + + {*(QMap<QString,QVariant>*) sharedDataStar()} + {*(QList<QVariant>*) sharedDataStar()} + {*(QHash<QString,QVariant>*) sharedDataStar()} + QVariantPair + {*(QList<QByteArray>*) sharedDataStar()} + {*(QList<QString>*) sharedDataStar()} + + + {*(bool*) dataStar()} + {*(int*) dataStar()} + {*(unsigned int*) dataStar()} + {*(long long*) dataStar()} + {*(unsigned long long*) dataStar()} + {*(double*) dataStar()} + {*(void**) dataStar()} + {*(long*) dataStar()} + {*(short*) dataStar()} + {*(char*) dataStar()} + {*(char16_t*) dataStar()} + {*(char32_t*) dataStar()} + {*(unsigned long*) dataStar()} + {*(unsigned short*) dataStar()} + {*(unsigned char*) dataStar()} + {*(float*) dataStar()} + {*(signed char*) dataStar()} + + + {*(QChar*) sharedDataStar()} + {*(QString*) sharedDataStar()} + {*(QByteArray*) sharedDataStar()} + {*(QDate*) sharedDataStar()} + {*(QTime*) sharedDataStar()} + QDateTime + QUrl + QLocale + {*(QRect*) sharedDataStar()} + {*(QRectF*) sharedDataStar()} + {*(QSize*) sharedDataStar()} + {*(QSizeF*) sharedDataStar()} + {*(QLine*) sharedDataStar()} + {*(QLineF*) sharedDataStar()} + {*(QPoint*) sharedDataStar()} + {*(QPointF*) sharedDataStar()} + EasingCurve + Uuid + RegularExpression + QJsonValue + QJsonObject + QJsonArray + QJsonDocument + QCborValue + QCborArray + QCborMap + ModelIndex + QPersistentModelIndex + + + QFont + QPixmap + QBrush + QColor + QPalette + QIcon + QImage + QPolygon + QRegion + QBitmap + QCursor + QKeySequence + QPen + QTextLength + QTextFormat + QTransform + QMatrix4x4 + QVector2D + QVector3D + QVector4D + QQuaternion + QPolygonF + QColorSpace + + + QSizePolicy + + + QMetaType::Type ({typeId()}) + + + *(QString*) sharedDataStar() + *(QByteArray*) sharedDataStar() + *(QDate*) sharedDataStar() + *(QTime*) sharedDataStar() + *(QRect*) sharedDataStar() + *(QRectF*) sharedDataStar() + *(QSize*) sharedDataStar() + *(QSizeF*) sharedDataStar() + *(QLine*) sharedDataStar() + *(QLineF*) sharedDataStar() + *(QPoint*) sharedDataStar() + *(QPointF*) sharedDataStar() + + *(QMap<QString,QVariant>*) sharedDataStar() + *(QList<QVariant>*) sharedDataStar() + *(QHash<QString,QVariant>*) sharedDataStar() + *(QList<QByteArray>*) sharedDataStar() + *(QList<QString>*) sharedDataStar() + + + + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..067b8fd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,38 @@ +{ + "files.autoSave": "onFocusChange", + "editor.fontSize": 15, + "editor.fontFamily": "'Operator Mono Lig', 'Operator Mono Lig', 'Operator Mono Lig'", + "cmake.configureOnOpen": true, + "cmake.debugConfig": { + "console": "integratedTerminal", + "visualizerFile": "${workspaceRoot}/.vscode/qt5.natvis" + }, + "cmake.environment": { + "PATH": "${env:PATH};/bin" + }, + "cmake.configureSettings": { + "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + }, + "cmake.options.statusBarVisibility": "visible", + "cmake.generator": "Ninja", + "C_Cpp.intelliSenseEngine": "disabled", + "clangd.arguments": [ + "--header-insertion=never", + "--all-scopes-completion", + "--completion-style=detailed", + "--clang-tidy", + "-j=4", + "--pch-storage=memory", + "--compile-commands-dir=build", + "--background-index", + "--ranking-model=heuristics", + "--function-arg-placeholders=false", + "--query-driver=repaceE" + ], + "editor.inlayHints.enabled": "off", + "editor.unicodeHighlight.allowedLocales": { + "ja": true, + "zh-hant": true, + "zh-hans": true + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5172148 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,83 @@ +cmake_minimum_required(VERSION 3.5) + +project(FTPTrans VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) +find_package(CURL REQUIRED) +find_path(SIMPLEINI_INCLUDE_DIRS ")ConvertUTF.c") + +if (MSVC) + if(${QT_VERSION_MAJOR} LESS 6) + add_compile_options(/source-charset:utf-8) + endif() + add_compile_options(/EHsc) + add_compile_options(-D_CRT_SECURE_NO_WARNINGS) +endif() + +set(PROJECT_SOURCES + src/main.cpp + src/ConfigOpr.cpp src/ConfigOpr.h + src/FTPTrans.h src/FTPTrans.cpp + src/FTPTrans.qrc src/FTPTrans.rc + src/FTPTrans.ui +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(FTPTrans + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET FTPTrans APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(FTPTrans SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(FTPTrans + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries(FTPTrans PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) +target_link_libraries(FTPTrans PRIVATE CURL::libcurl) +#target_include_directories(FTPTrans PRIVATE ${SIMPLEINI_INCLUDE_DIRS}) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +if(${QT_VERSION} VERSION_LESS 6.1.0) + set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.FTPTrans) +endif() +set_target_properties(FTPTrans PROPERTIES + ${BUNDLE_ID_OPTION} + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +include(GNUInstallDirs) +install(TARGETS FTPTrans + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(FTPTrans) +endif() diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1770a61 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# FTPTrans + +## 介绍 + +传输文件的FTP工具。 + +## 构建说明 + +- 使用VCPKG,使用`cmake`生成时指定`CMAKE_TOOLCHAIN_FILE`。 + +使用组件有:`curl(8.7.1)`、`simpleini(4.22)`、`qt(5.15.13)`,括号版本是实际在用的版本。 + +```shell +-DCMAKE_TOOLCHAIN_FILE=${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake +``` + +或者 + +```shell +-DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake +``` diff --git a/src/ConfigOpr.cpp b/src/ConfigOpr.cpp new file mode 100644 index 0000000..48de184 --- /dev/null +++ b/src/ConfigOpr.cpp @@ -0,0 +1,161 @@ +#include "ConfigOpr.h" +#include + +constexpr const char* KEY_PWD = "Password"; +constexpr const char* KEY_IP = "IP"; +constexpr const char* KEY_ITEMCNT = "ItemCnt"; +constexpr const char* KEY_USERNAME = "Username"; +constexpr const char* KEY_PORT = "Port"; +constexpr const char* HEAD_BASIC = "Basic"; +constexpr const char* HEAD_ITEM = "Item"; +constexpr const char* KEY_SOURCE = "Source"; +constexpr const char* KEY_DES = "Des"; +constexpr const char* KEY_ENABLE = "Enable"; + +ConfigOpr::ConfigOpr() +{ + std::string home = get_home(); + fs::path config_dir = fs::path(home).append(".config").append("FTPTrans"); + auto ini_path = fs::path(config_dir).append("config.ini"); + std::snprintf(ini_path_, sizeof(ini_path_), "%s", ini_path.string().c_str()); + + if (!fs::exists(config_dir)) { + fs::create_directories(config_dir); + } + if (!fs::exists(ini_path_)) { + generate_default(); + return; + } +} + +void ConfigOpr::push(const ItemContent& item) +{ + check_open(); + + std::string new_name(HEAD_ITEM); + new_name += std::to_string(item.id); + + ini_.SetValue(new_name.c_str(), KEY_SOURCE, item.source.c_str()); + ini_.SetValue(new_name.c_str(), KEY_DES, item.des.c_str()); + ini_.SetBoolValue(new_name.c_str(), KEY_ENABLE, true); + + save(); +} + +bool ConfigOpr::update(int id, const ItemContent* ptem, bool enable) +{ + check_open(); + + long cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + if (id > cnt) { + return false; + } + + std::string new_name(HEAD_ITEM); + new_name += std::to_string(id); + + if (!enable) { + bool ret = ini_.SetBoolValue(new_name.c_str(), KEY_ENABLE, false) == SI_UPDATED; + assert(ret); + save(); + return true; + } + + if (!ptem) { + return false; + } + + ini_.SetValue(new_name.c_str(), KEY_SOURCE, ptem->source.c_str()); + ini_.SetValue(new_name.c_str(), KEY_DES, ptem->des.c_str()); + ini_.SetBoolValue(new_name.c_str(), KEY_ENABLE, true); + + save(); + + return true; +} + +long ConfigOpr::get_count() +{ + check_open(); + + long cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + return cnt; +} + +bool ConfigOpr::get_content(int id, ItemContent& item) +{ + check_open(); + + long cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + if (id > cnt) { + return false; + } + std::string new_name(HEAD_ITEM); + new_name += std::to_string(id); + + item.enable = ini_.GetBoolValue(new_name.c_str(), KEY_ENABLE); + item.des = ini_.GetValue(new_name.c_str(), KEY_DES); + item.source = ini_.GetValue(new_name.c_str(), KEY_SOURCE); + item.id = id; + return true; +} + +bool ConfigOpr::get_base(ItemBase& base) +{ + check_open(); + base.cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + base.ip.append(ini_.GetValue(HEAD_BASIC, KEY_IP)); + base.port = std::stoi(ini_.GetValue(HEAD_BASIC, KEY_PORT)); + base.pwd.append(ini_.GetValue(HEAD_BASIC, KEY_PWD)); + base.user.append(ini_.GetValue(HEAD_BASIC, KEY_USERNAME)); + return true; +} + +bool ConfigOpr::set_base(const ItemBase& base) +{ + check_open(); + ini_.SetLongValue(HEAD_BASIC, KEY_ITEMCNT, base.cnt); + ini_.SetValue(HEAD_BASIC, KEY_IP, base.ip.c_str()); + ini_.SetLongValue(HEAD_BASIC, KEY_PORT, base.port); + ini_.SetValue(HEAD_BASIC, KEY_USERNAME, base.user.c_str()); + ini_.SetValue(HEAD_BASIC, KEY_PWD, base.pwd.c_str()); + save(); + return true; +} + +std::string ConfigOpr::get_home() +{ +#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) + return std::getenv("USERPROFILE"); +#else + const char* homedir = getenv("HOME"); + if (homedir) { + return std::string(homedir); + } + return ""; +#endif +} + +void ConfigOpr::generate_default() +{ + ini_.SetLongValue(HEAD_BASIC, KEY_ITEMCNT, 0); + ini_.SetValue(HEAD_BASIC, KEY_IP, "192.168.0.9"); + ini_.SetLongValue(HEAD_BASIC, KEY_PORT, 21); + ini_.SetValue(HEAD_BASIC, KEY_USERNAME, "lebo"); + ini_.SetValue(HEAD_BASIC, KEY_PWD, "123456"); + ini_.SaveFile(ini_path_); +} + +void ConfigOpr::check_open() +{ + if (ini_.IsEmpty()) { + bool ret = (ini_.LoadFile(ini_path_) == SI_OK); + assert(ret); + } +} + +void ConfigOpr::save() +{ + bool ret = ini_.SaveFile(ini_path_) == SI_OK; + assert(ret); +} diff --git a/src/ConfigOpr.h b/src/ConfigOpr.h new file mode 100644 index 0000000..2a67b47 --- /dev/null +++ b/src/ConfigOpr.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +namespace fs = std::filesystem; + +struct ItemBase { + std::string ip{}; + int port{}; + long cnt{}; + std::string user{}; + std::string pwd{}; +}; + +struct ItemContent +{ + int id{}; + bool enable{ false }; + std::string source{}; + std::string des{}; + std::string des_full{}; +}; + +class ConfigOpr +{ +public: + ConfigOpr(); + ~ConfigOpr() = default; + +public: + void push(const ItemContent& item); + bool update(int id, const ItemContent* ptem, bool enable = true); + long get_count(); + bool get_content(int id, ItemContent& item); + bool get_base(ItemBase& base); + bool set_base(const ItemBase& base); + +private: + std::string get_home(); + void generate_default(); + void check_open(); + void save(); + +private: + char ini_path_[512]{}; + CSimpleIniA ini_{}; +}; + diff --git a/src/FTPTrans.cpp b/src/FTPTrans.cpp new file mode 100644 index 0000000..5bdb817 --- /dev/null +++ b/src/FTPTrans.cpp @@ -0,0 +1,232 @@ +#include "FTPTrans.h" +#include + +FTPTrans::FTPTrans(QWidget* parent) : QWidget(parent) +{ + ui.setupUi(this); + + ini_opr_ = new ConfigOpr(); + + setWindowTitle("FTPTrans v1.0.2"); + + init(); + + connect(ui.btnSave, &QPushButton::clicked, this, [&]() { save(true); }); + connect(ui.btnAdd, &QPushButton::clicked, [&]() { handle_table_add(); }); + connect(ui.btnUpdate, &QPushButton::clicked, [&]() { Trans(); }); + connect(ui.btnDown, &QPushButton::clicked, [&]() { Trans(false); }); +} + +void FTPTrans::save(bool is_notify) +{ + ini_base_.ip = ui.edIP->text().toStdString(); + ini_base_.port = ui.edPort->text().toInt(); + ini_base_.pwd = ui.edPwd->text().toStdString(); + ini_base_.user = ui.edUserName->text().toStdString(); + ini_base_.cnt = ui.tableWidget->rowCount(); + + ini_opr_->set_base(ini_base_); + + for (int i = 0; i < ini_base_.cnt; ++i) { + ItemContent content; + content.id = ui.tableWidget->item(i, 0)->text().toInt(); + content.source.append(ui.tableWidget->item(i, 1)->text().toLocal8Bit()); + content.des.append(ui.tableWidget->item(i, 2)->text().toLocal8Bit()); + ini_opr_->update(content.id, &content); + } + + if (is_notify) { + QMessageBox::information(this, u8"提示", u8"已存储"); + } +} + +FTPTrans::~FTPTrans() +{ + delete ini_opr_; +} + +size_t readFunc(void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + return fread(ptr, size, nmemb, stream); +} + +size_t writeFunc(void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + return fwrite(ptr, size, nmemb, stream); +} + +void FTPTrans::Trans(bool is_up) +{ + if (is_up) { + if (!is_ok(this, u8"确认上传同步吗?")) { + return; + } + } else { + if (!is_ok(this, u8"确认下载同步吗?")) { + return; + } + } + + CURL* curl = nullptr; + + QList selectedItems = ui.tableWidget->selectedItems(); + if (selectedItems.size() != 3) { + QMessageBox::information(this, u8"提示", u8"未有选中数据"); + return; + } + + std::string source(selectedItems[1]->text().toLocal8Bit()); + std::string des(selectedItems[2]->text().toLocal8Bit()); + std::string user(ui.edUserName->text().toStdString()); + std::string pwd(ui.edPwd->text().toStdString()); + + try { + curl_global_init(CURL_GLOBAL_ALL); + + std::uintmax_t file_size{}; + if (is_up) { + fs::path source_file(source); + if (!fs::exists(source_file)) { + QMessageBox::information(this, u8"提示", QString::fromStdString(u8"文件不存在:" + source_file.string())); + return; + } + file_size = fs::file_size(source_file); + } + + curl = curl_easy_init(); + if (curl == nullptr) { + QMessageBox::information(this, u8"提示", u8"curl_easy_init 初始化失败"); + return; + } + + FILE* fd = nullptr; + if (is_up) { + fd = fopen(source.c_str(), "rb"); + } else { + fd = fopen(source.c_str(), "wb"); + } + + if (!fd) { + QMessageBox::information(this, u8"提示", QString::fromStdString(u8"文件打开失败:" + source)); + return; + } + + if (is_up) { + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + } + + curl_easy_setopt(curl, CURLOPT_URL, des.c_str()); + curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); + curl_easy_setopt(curl, CURLOPT_PASSWORD, pwd.c_str()); + + if (is_up) { + curl_easy_setopt(curl, CURLOPT_READFUNCTION, readFunc); + curl_easy_setopt(curl, CURLOPT_READDATA, fd); + } else { + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fd); + } + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + if (is_up) { + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, file_size); + } + + if (10) { + curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, 10); + } + + CURLcode r = curl_easy_perform(curl); + fclose(fd); + + if (r != CURLE_OK) { + QMessageBox::information(this, u8"错误提示", QString::fromLocal8Bit(curl_easy_strerror(r))); + return; + } + } catch (...) { + QMessageBox::information(this, u8"异常", u8"产生了异常"); + return; + } + + if (curl) { + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + save(false); + QMessageBox::information(this, u8"提示", u8"完成"); +} + +void FTPTrans::init() +{ + ini_opr_->get_base(ini_base_); + ui.edIP->setText(QString::fromStdString(ini_base_.ip)); + ui.edPort->setText(QString::number(ini_base_.port)); + ui.edPwd->setText(QString::fromStdString(ini_base_.pwd)); + ui.edUserName->setText(QString::fromStdString(ini_base_.user)); + + QStringList headers; + headers << u8"标识号" << u8"源位置(本地)" << u8"目的位置(FTP位置)"; + ui.tableWidget->setColumnCount(headers.size()); + ui.tableWidget->setHorizontalHeaderLabels(headers); + + ui.tableWidget->setColumnWidth(0, 80); + ui.tableWidget->setColumnWidth(1, 450); + ui.tableWidget->horizontalHeader()->setStretchLastSection(true); + ui.tableWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); + ui.tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + ui.tableWidget->verticalHeader()->setVisible(false); + + ui.btnAdd->setMinimumHeight(35); + ui.btnDown->setMinimumHeight(35); + ui.btnSave->setMinimumHeight(35); + ui.btnUpdate->setMinimumHeight(35); + + handle_table_read(); +} + +void FTPTrans::handle_table_read() +{ + int cnt = ini_opr_->get_count(); + for (int i = 1; i < cnt + 1; ++i) { + ItemContent content; + ini_opr_->get_content(i, content); + int rowCnt = ui.tableWidget->rowCount(); + ui.tableWidget->insertRow(rowCnt); + QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(content.id)); + item0->setFlags(item0->flags() & ~Qt::ItemIsEditable); + ui.tableWidget->setItem(rowCnt, 0, item0); + QTableWidgetItem* item1 = new QTableWidgetItem(QString::fromLocal8Bit(content.source.c_str())); + ui.tableWidget->setItem(rowCnt, 1, item1); + QTableWidgetItem* item2 = new QTableWidgetItem(QString::fromLocal8Bit(content.des.c_str())); + ui.tableWidget->setItem(rowCnt, 2, item2); + } +} + +void FTPTrans::handle_table_add() +{ + int rowCnt = ui.tableWidget->rowCount(); + ui.tableWidget->insertRow(rowCnt); + QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(rowCnt + 1)); + item0->setFlags(item0->flags() & ~Qt::ItemIsEditable); + ui.tableWidget->setItem(rowCnt, 0, item0); + QTableWidgetItem* item1 = new QTableWidgetItem(""); + ui.tableWidget->setItem(rowCnt, 1, item1); + QTableWidgetItem* item2 = new QTableWidgetItem(""); + ui.tableWidget->setItem(rowCnt, 2, item2); +} + +bool FTPTrans::is_ok(QWidget* parent, const QString& content) +{ + QMessageBox questionBox(parent); + questionBox.setText(content); + questionBox.setWindowTitle(u8"提示"); + questionBox.setIcon(QMessageBox::Question); + questionBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + int result = questionBox.exec(); + if (result != QMessageBox::Yes) { + return false; + } else { + return true; + } +} diff --git a/src/FTPTrans.h b/src/FTPTrans.h new file mode 100644 index 0000000..0667d5e --- /dev/null +++ b/src/FTPTrans.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "ui_FTPTrans.h" +#include "ConfigOpr.h" +#include + +class FTPTrans : public QWidget +{ + Q_OBJECT + +public: + FTPTrans(QWidget *parent = nullptr); + ~FTPTrans(); + +public: + void Trans(bool is_up = true); + void init(); + void handle_table_read(); + void handle_table_add(); + void save(bool is_notify = false); + +private: + bool is_ok(QWidget* parent, const QString& content); +private: + Ui::FTPTransClass ui; + ConfigOpr* ini_opr_{}; + ItemBase ini_base_{}; +}; diff --git a/src/FTPTrans.ico b/src/FTPTrans.ico new file mode 100644 index 0000000..1c4fb80 Binary files /dev/null and b/src/FTPTrans.ico differ diff --git a/src/FTPTrans.qrc b/src/FTPTrans.qrc new file mode 100644 index 0000000..c62a9e9 --- /dev/null +++ b/src/FTPTrans.qrc @@ -0,0 +1,4 @@ + + + + diff --git a/src/FTPTrans.rc b/src/FTPTrans.rc new file mode 100644 index 0000000..24a265a --- /dev/null +++ b/src/FTPTrans.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "FTPTrans.ico" diff --git a/src/FTPTrans.ui b/src/FTPTrans.ui new file mode 100644 index 0000000..af21ecd --- /dev/null +++ b/src/FTPTrans.ui @@ -0,0 +1,156 @@ + + + FTPTransClass + + + + 0 + 0 + 1461 + 605 + + + + FTPTrans + + + + + + FTP基本信息 + + + + + + + + + 用户名: + + + + + + + IP: + + + + + + + 端口: + + + + + + + + + + 密码: + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 文件传输(远端暂不支持中文路径) + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 添加 + + + + + + + 上传同步 + + + + + + + 下载同步 + + + + + + + 保存 + + + + + + + + + + + + + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..84db3dc --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,14 @@ +#include "FTPTrans.h" +#include + +int main(int argc, char *argv[]) +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif + QApplication a(argc, argv); + a.setStyle("windows xp"); + FTPTrans w; + w.show(); + return a.exec(); +}