docs: 添加涉密文件自检工具实施计划
This commit is contained in:
49
UmiOCR-data/qt_res/qml/MainWindow/AsynFilesLoader.qml
Normal file
49
UmiOCR-data/qt_res/qml/MainWindow/AsynFilesLoader.qml
Normal file
@@ -0,0 +1,49 @@
|
||||
// =============================================
|
||||
// =============== 异步文件加载器 ===============
|
||||
// =============================================
|
||||
// 用于全局任意模块加载大量文件
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
Item {
|
||||
property string tips: qsTr("正在载入 %1 个文件:\n%2")
|
||||
property real updateTime: 0.2 // 刷新事件时间间隔
|
||||
property var callback_: undefined // 缓存最近一次回调函数
|
||||
|
||||
Component.onCompleted: {
|
||||
// 订阅事件
|
||||
qmlapp.pubSub.subscribeGroup("<<fileLoadComplete>>", this,
|
||||
"fileLoadComplete", "FilesLoader")
|
||||
qmlapp.pubSub.subscribeGroup("<<fileLoadUpdate>>", this,
|
||||
"fileLoadUpdate", "FilesLoader")
|
||||
}
|
||||
|
||||
function run(
|
||||
urls, // 初始路径列表
|
||||
sufType, // 后缀类型,image / doc
|
||||
isRecurrence, // 若为True,则递归搜索
|
||||
callback // 加载完成后,向此回调函数传入路径列表
|
||||
) {
|
||||
callback_ = callback
|
||||
qmlapp.popup.showMask(tips.arg(1).arg(""), "LoadingFiles")
|
||||
qmlapp.utilsConnector.asynFindFiles(
|
||||
urls,
|
||||
sufType,
|
||||
isRecurrence,
|
||||
"<<fileLoadComplete>>",
|
||||
"<<fileLoadUpdate>>",
|
||||
updateTime
|
||||
)
|
||||
}
|
||||
// 文件扫描结束,获取合法文件列表
|
||||
function fileLoadComplete(paths) {
|
||||
qmlapp.popup.hideMask("LoadingFiles")
|
||||
callback_(paths)
|
||||
callback_ = undefined
|
||||
}
|
||||
// 文件扫描更新,刷新提示文本
|
||||
function fileLoadUpdate(filesCount, lastPath) {
|
||||
qmlapp.popup.showMask(tips.arg(filesCount).arg(lastPath),
|
||||
"LoadingFiles")
|
||||
}
|
||||
}
|
||||
160
UmiOCR-data/qt_res/qml/MainWindow/MainWindowManager.qml
Normal file
160
UmiOCR-data/qt_res/qml/MainWindow/MainWindowManager.qml
Normal file
@@ -0,0 +1,160 @@
|
||||
// ===========================================
|
||||
// =============== 主窗口管理器 ===============
|
||||
// ===========================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
|
||||
Item {
|
||||
property var mainWin // 主窗口的引用
|
||||
property var screens: Qt.application.screens // 屏幕属性的引用
|
||||
|
||||
property var mScreen: mainWin.screen
|
||||
property int mx: mainWin.x
|
||||
property int my: mainWin.y
|
||||
property int mw: mainWin.width
|
||||
property int mh: mainWin.height
|
||||
// 最小宽高
|
||||
property int minW: 300
|
||||
property int minH: 300
|
||||
|
||||
// ========================= 【保存量】 =========================
|
||||
|
||||
// 主窗口属性初始化
|
||||
Component.onCompleted: {
|
||||
loadGeometry(true) // 恢复上次大小位置
|
||||
// 启动时可见
|
||||
const visi = !qmlapp.globalConfigs.getValue("window.startupInvisible")
|
||||
setVisibility(visi)
|
||||
if(!visi) {
|
||||
qmlapp.popup.simple(qsTr("欢迎使用 Umi-OCR"), qsTr("已启用后台模式,可通过快捷键使用功能。"))
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= 【记录窗口位置大小】 =========================
|
||||
|
||||
|
||||
Connections {
|
||||
target: mainWin
|
||||
function onClosing() {
|
||||
saveGeometry()
|
||||
}
|
||||
}
|
||||
// 保存
|
||||
function saveGeometry() {
|
||||
let xywh = [mx, my, mw, mh]
|
||||
xywh = xywh.join(",")
|
||||
qmlapp.globalConfigs.setValue("window.geometry", xywh, false, true)
|
||||
console.log("保存窗口位置", xywh)
|
||||
}
|
||||
// 读取。isCheck==true时进行位置安全检查,避免窗口出现在屏幕外
|
||||
function loadGeometry(isCheck=false) {
|
||||
let xywh = qmlapp.globalConfigs.getValue("window.geometry")
|
||||
xywh = xywh.split(",")
|
||||
if(xywh.length < 4) {
|
||||
console.log("未能读取窗口位置", xywh)
|
||||
return
|
||||
}
|
||||
for(let i=0; i<4; i++)
|
||||
xywh[i] = parseInt(xywh[i])
|
||||
let [x, y, w, h] = xywh
|
||||
// 安全检查,避免窗口出现在屏幕外
|
||||
if(isCheck)
|
||||
[x, y, w, h] = checkGeometry(xywh[0], xywh[1], xywh[2], xywh[3])
|
||||
mainWin.x = x
|
||||
mainWin.y = y
|
||||
mainWin.width = w
|
||||
mainWin.height = h
|
||||
let screenIndex = 0
|
||||
for(let i=0, l=Qt.application.screens.length; i<l; i++) {
|
||||
let s = Qt.application.screens[i]
|
||||
if(x >= s.virtualX && x <= s.virtualX+s.width
|
||||
&& y >= s.virtualY && y <= s.virtualY+s.height) {
|
||||
screenIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
mainWin.screen = Qt.application.screens[screenIndex]
|
||||
console.log("读取窗口位置", x, y, w, h, screenIndex, isCheck)
|
||||
}
|
||||
// 检查窗口位置,返回检查后的值
|
||||
function checkGeometry(x, y, w, h) {
|
||||
// 检查宽高
|
||||
if(w > mScreen.desktopAvailableWidth)
|
||||
w = mScreen.desktopAvailableWidth
|
||||
else if(w < minW)
|
||||
w = minW
|
||||
if(h > mScreen.desktopAvailableHeight)
|
||||
h = mScreen.desktopAvailableHeight
|
||||
else if(h < minH)
|
||||
h = minH
|
||||
// 检查位置
|
||||
if(x < mScreen.virtualX)
|
||||
x = mScreen.virtualX
|
||||
else if(x > mScreen.virtualX+mScreen.desktopAvailableWidth-w)
|
||||
x = mScreen.virtualX+mScreen.desktopAvailableWidth-w
|
||||
if(y < mScreen.virtualY+30) // +30防止标题栏出界
|
||||
y = mScreen.virtualY+30
|
||||
else if(y > mScreen.virtualY+mScreen.desktopAvailableHeight-h)
|
||||
y = mScreen.virtualY+mScreen.desktopAvailableHeight-h
|
||||
return [x, y, w, h]
|
||||
}
|
||||
|
||||
|
||||
// ========================= 【接口】 =========================
|
||||
|
||||
// 返回主窗口是否可见
|
||||
function getVisibility() {
|
||||
return mainWin.visibility==2||mainWin.visibility==4||mainWin.visibility==5
|
||||
}
|
||||
|
||||
// 设置主窗口可见性。 false 隐藏, true 恢复。
|
||||
function setVisibility(flag) {
|
||||
if(flag) {
|
||||
mainWin.visibility = Window.Windowed // 状态为可见
|
||||
mainWin.requestActivate() // 激活窗口
|
||||
mainWin.raise() // 弹到顶层
|
||||
}
|
||||
else {
|
||||
mainWin.visibility = Window.Hidden
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭主窗口
|
||||
function close() {
|
||||
// 隐藏
|
||||
if(qmlapp.globalConfigs.getValue("window.closeWin2Hide")) {
|
||||
setVisibility(false)
|
||||
}
|
||||
// 关闭
|
||||
else {
|
||||
quit()
|
||||
}
|
||||
}
|
||||
|
||||
// 退出主窗口
|
||||
function quit() {
|
||||
saveGeometry()
|
||||
Qt.quit()
|
||||
}
|
||||
|
||||
// 检查主窗口初始化屏幕位置,防止出界及过大
|
||||
function checkScreen() {
|
||||
if(mw > mScreen.desktopAvailableWidth)
|
||||
mw = mScreen.desktopAvailableWidth
|
||||
if(mh > mScreen.desktopAvailableHeight)
|
||||
mh = mScreen.desktopAvailableHeight
|
||||
if(mx < mScreen.virtualX) {
|
||||
mainWin.x = mScreen.virtualX
|
||||
}
|
||||
else if(mx > mScreen.virtualX+mScreen.desktopAvailableWidth-mainWin.width) {
|
||||
mainWin.x = mScreen.virtualX+mScreen.desktopAvailableWidth-mainWin.width
|
||||
}
|
||||
if(my < mScreen.virtualY+30) {
|
||||
mainWin.y = mScreen.virtualY+30
|
||||
}
|
||||
else if(my > mScreen.virtualY+mScreen.desktopAvailableHeight-mainWin.height) {
|
||||
mainWin.y = mScreen.virtualY+mScreen.desktopAvailableHeight-mainWin.height
|
||||
}
|
||||
}
|
||||
}
|
||||
61
UmiOCR-data/qt_res/qml/MainWindow/Size_.qml
Normal file
61
UmiOCR-data/qt_res/qml/MainWindow/Size_.qml
Normal file
@@ -0,0 +1,61 @@
|
||||
// ===========================================
|
||||
// =============== 组件尺寸相关 ===============
|
||||
// ===========================================
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
Item {
|
||||
// ========================= 【尺寸】 =========================
|
||||
|
||||
// 全局缩放值,适配分辨率
|
||||
property real scale: 1
|
||||
|
||||
// 行高
|
||||
// 主要文字
|
||||
property int line: 16 * scale
|
||||
// 较小的文字
|
||||
property int smallLine: 13 * scale
|
||||
// 较大的文字
|
||||
property int largeLine: 20 * scale
|
||||
|
||||
// 文字缩放值
|
||||
property real textScale: 1 // 由下列 languageScale 控制
|
||||
// 主要文字大小
|
||||
property int text: line * textScale
|
||||
// 较小的文字大小
|
||||
property int smallText: smallLine * textScale
|
||||
// 较大的文字大小
|
||||
property int largeText: largeLine * textScale
|
||||
|
||||
// 窗口圆角
|
||||
property real windowRadius: 0
|
||||
// 基础圆角
|
||||
property real baseRadius: 6 * scale
|
||||
// 按钮圆角
|
||||
property real btnRadius: baseRadius
|
||||
// 面板圆角
|
||||
property real panelRadius: baseRadius * 1.7
|
||||
|
||||
// 水平标签栏高度
|
||||
property real hTabBarHeight: line * 1.8
|
||||
|
||||
// 常用间距
|
||||
property real spacing: 7 * scale
|
||||
// 小间距
|
||||
property real smallSpacing: 4 * scale
|
||||
|
||||
// 语言缩放系数
|
||||
// 在相同的行高内,有些语言经过缩放可以表现更好。如英文可以比汉字的字号更小。
|
||||
// 通过在翻译文件中定义 languageScale 可以单独修改这种语言的缩放。
|
||||
property string languageScale: qsTr("1.0")
|
||||
|
||||
Component.onCompleted: {
|
||||
const s = parseFloat(languageScale)
|
||||
if(!isNaN(s)) {
|
||||
textScale = s
|
||||
}
|
||||
else {
|
||||
console.warn("语言缩放系数无法应用:", languageScale)
|
||||
}
|
||||
}
|
||||
}
|
||||
116
UmiOCR-data/qt_res/qml/MainWindow/SystemTray.qml
Normal file
116
UmiOCR-data/qt_res/qml/MainWindow/SystemTray.qml
Normal file
@@ -0,0 +1,116 @@
|
||||
// =======================================
|
||||
// =============== 系统托盘 ===============
|
||||
// =======================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQml.Models 2.15
|
||||
import Qt.labs.platform 1.1
|
||||
|
||||
SystemTrayIcon {
|
||||
|
||||
// ========================= 【接口】 =========================
|
||||
|
||||
// 添加一项菜单。如果只传入 eventTitle ,则发送事件。如果传入回调函数 func ,则调用函数,不发送事件。
|
||||
function addMenuItem(eventTitle, text, func=undefined) {
|
||||
// 检查重复
|
||||
const index = findMenuEvent(eventTitle)
|
||||
if(index >= 0) {
|
||||
console.warn(`注册系统托盘菜单重复! ${eventTitle} - ${text}`)
|
||||
return
|
||||
}
|
||||
const argv = {eventTitle: eventTitle, text_:text, isFunc:func?true:false}
|
||||
if(func) funcDict[eventTitle] = func // 不能将函数塞进ListModel,故放进单独的函数字典
|
||||
menuModel.append(argv)
|
||||
|
||||
}
|
||||
|
||||
// 移除一项菜单
|
||||
function delMenuItem(eventTitle) {
|
||||
console.log(`删除系统托盘菜单 ${eventTitle}`)
|
||||
const index = findMenuEvent(eventTitle)
|
||||
if(index < 0) {
|
||||
console.warn(`删除系统托盘菜单,找不到对应项! ${eventTitle} - ${text}`)
|
||||
return
|
||||
}
|
||||
const argd = menuModel.get(index)
|
||||
if(argd.isFunc) { // 删除回调函数
|
||||
delete funcDict[argd.eventTitle]
|
||||
}
|
||||
// 删除菜单项
|
||||
menuModel.remove(index)
|
||||
|
||||
}
|
||||
|
||||
// ========================= 【控制】 =========================
|
||||
|
||||
// 在 menuModel 中寻找 eventTitle 对应的项,返回下标,找不到返回-1
|
||||
function findMenuEvent(eventTitle) {
|
||||
const len = menuModel.count
|
||||
let index = len-1
|
||||
for(; index >= 0; index--) {
|
||||
const d = menuModel.get(index)
|
||||
if(d.eventTitle === eventTitle)
|
||||
break
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
// 点击菜单项
|
||||
function menuCall(index) {
|
||||
const argd = menuModel.get(index)
|
||||
if(argd.isFunc) { // 执行函数
|
||||
funcDict[argd.eventTitle]()
|
||||
}
|
||||
else { // 发布事件
|
||||
qmlapp.pubSub.publish(argd.eventTitle)
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= 【布局】 =========================
|
||||
|
||||
id: systemTrayRoot
|
||||
visible: false
|
||||
icon.source: "../../images/icons/umiocr.ico"
|
||||
tooltip: "Umi-OCR"
|
||||
property var funcDict: {} // 存放函数的字典
|
||||
Component.onCompleted: funcDict = {}
|
||||
|
||||
onVisibleChanged: {
|
||||
// 隐藏/显示托盘图标时,重新挂载菜单
|
||||
systemTrayRoot.menu = visible ? trayMenu : null
|
||||
}
|
||||
|
||||
// 右键菜单
|
||||
menu: Menu {
|
||||
id: trayMenu
|
||||
ListModel{ id:menuModel } // 自定义菜单的模型
|
||||
property alias menuModel: menuModel
|
||||
|
||||
// Menu { title: qsTr("所有功能") }
|
||||
|
||||
Instantiator {
|
||||
model: trayMenu.menuModel
|
||||
delegate: MenuItem {
|
||||
text: text_
|
||||
onTriggered: systemTrayRoot.menuCall(index)
|
||||
}
|
||||
|
||||
onObjectAdded: trayMenu.insertItem(index, object)
|
||||
onObjectRemoved: trayMenu.removeItem(object)
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("打开主窗口")
|
||||
onTriggered: qmlapp.mainWin.setVisibility(true)
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("退出 Umi-OCR")
|
||||
onTriggered: qmlapp.mainWin.quit()
|
||||
}
|
||||
}
|
||||
|
||||
onActivated: {
|
||||
if(reason == SystemTrayIcon.DoubleClick)
|
||||
qmlapp.mainWin.setVisibility(true) // 主窗可见
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user