diff --git a/build2/qt/HGSolution.pro b/build2/qt/HGSolution.pro index 25937264..c539b13c 100644 --- a/build2/qt/HGSolution.pro +++ b/build2/qt/HGSolution.pro @@ -6,6 +6,7 @@ SUBDIRS += \ HGImgProc \ HGSaneUI \ HGSaneUser \ + HGTwainUI \ HGTwainUser \ HGVersion \ HGScannerLib \ @@ -30,11 +31,14 @@ HGSaneUI.depends = \ HGSaneUser.depends = \ HGBase \ HGSaneUI - + +HGTwainUI.depends = \ + HGBase + HGTwainUser.depends = \ HGBase \ HGSaneUI - + HGVersion.depends = \ HGBase diff --git a/build2/qt/HGTwainUI/HGTwainUI.def b/build2/qt/HGTwainUI/HGTwainUI.def new file mode 100644 index 00000000..a80af44e --- /dev/null +++ b/build2/qt/HGTwainUI/HGTwainUI.def @@ -0,0 +1,9 @@ +LIBRARY + +EXPORTS + +choose_scanner +apply_current_config +twain_ui_free +show_setting_ui +show_progress_ui \ No newline at end of file diff --git a/build2/qt/HGTwainUI/HGTwainUI.pro b/build2/qt/HGTwainUI/HGTwainUI.pro new file mode 100644 index 00000000..c8270531 --- /dev/null +++ b/build2/qt/HGTwainUI/HGTwainUI.pro @@ -0,0 +1,222 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets gui-private + +TEMPLATE = lib +DEFINES += UNTITLED_LIBRARY + +CONFIG += c++11 +CONFIG += dll + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS +DEFINES += QT_NO_VERSION_TAGGING + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +include($$PWD/../HGOEM.pri) + +CONFIG(debug, debug|release) { + MY_CONFIGURE = Debug +} +CONFIG(release, debug|release) { + MY_CONFIGURE = Release +} + +win32 { + + SOURCES += ../../../modules/twainui/qmfcapp.cpp + SOURCES += ../../../modules/twainui/qwinhost.cpp + SOURCES += ../../../modules/twainui/qwinwidget.cpp + SOURCES += ../../../modules/twainui/twainui.cpp + SOURCES += ../../../modules/twainui/hg_settingdialog.cpp + + HEADERS += ../../../modules/twainui/qmfcapp.hpp + HEADERS += ../../../modules/twainui/qwinhost.hpp + HEADERS += ../../../modules/twainui/qwinwidget.hpp + HEADERS += ../../../modules/twainui/twainui.h + HEADERS += ../../../modules/twainui/hg_settingdialog.h + + MY_OS = windows + TARGET = $${OEM_PREFIX}TwainUI + + contains(QT_ARCH, i386) { + MY_ARCH = x86 + } + contains(QT_ARCH, x86_64) { + MY_ARCH = x64 + } + + CONFIG(release, debug|release) { + QMAKE_LFLAGS_RELEASE += /MAP + QMAKE_CFLAGS_RELEASE += /Zi + QMAKE_LFLAGS_RELEASE += /debug /opt:ref + } + + DEF_FILE = HGTwainUI.def + LIBS += -lgdi32 -lgdiplus -ldbghelp -luser32 + LIBS += -L$$PWD/../../build/$${MY_OS}/$${OEM_NAME}/$${MY_ARCH}/$${MY_CONFIGURE} -l$${OEM_PREFIX}Base + LIBS += -L$$PWD/../../../../sdk/lib/win/$${MY_ARCH}/OEM/$${OEM_NAME} -llang +} + +unix { + + DISTRIBUTION = $$system(cat /etc/issue | cut -d\' \' -f1) + contains(DISTRIBUTION, UnionTech) { + MY_OS = uos + } else { + MY_OS = kylin + } + TARGET = $${OEM_PREFIX2}TwainUI + + contains(QT_ARCH, x86_64) { + MY_ARCH = amd64 + MY_ARCH2 = x86_64 + } + contains(QT_ARCH, arm64) { + MY_ARCH = aarch64 + MY_ARCH2 = aarch64 + } + contains(QT_ARCH, mips64) { + MY_ARCH = mips64 + MY_ARCH2 = mips64 + } + contains(QT_ARCH, loongarch64) { + MY_ARCH = loongarch64 + MY_ARCH2 = loongarch64 + } + + CONFIG += unversioned_libname unversioned_soname + QMAKE_CXXFLAGS += -fvisibility=hidden + QMAKE_LFLAGS += -static-libstdc++ -static-libgcc + QMAKE_LFLAGS += -Wl,-rpath,\'\$\$ORIGIN\' -Wl,--exclude-libs,ALL + QMAKE_LFLAGS += -z defs -B direct + + LIBS += -lpthread -ldl + LIBS += -L$$PWD/../../build/$${MY_OS}/$${OEM_NAME}/$${MY_ARCH}/$${MY_CONFIGURE} -l$${OEM_PREFIX2}Base + LIBS += -L$$PWD/../../../../release/$${MY_OS}/$${MY_ARCH2} -llang +} + +INCLUDEPATH += $$PWD/../../../modules +INCLUDEPATH += $$PWD/../../../utility +INCLUDEPATH += $$PWD/../../../modules/saneui +INCLUDEPATH += $$PWD/../../../modules/twainui +INCLUDEPATH += $$PWD/../../../../sdk/include + +DESTDIR = $$PWD/../../build/$${MY_OS}/$${OEM_NAME}/$${MY_ARCH}/$${MY_CONFIGURE} +UI_DIR = $$PWD/../../temp/$${MY_OS}/$${OEM_NAME}/$${MY_ARCH}/$${MY_CONFIGURE}/$${TARGET} +MOC_DIR = $$PWD/../../temp/$${MY_OS}/$${OEM_NAME}/$${MY_ARCH}/$${MY_CONFIGURE}/$${TARGET} +OBJECTS_DIR = $$PWD/../../temp/$${MY_OS}/$${OEM_NAME}/$${MY_ARCH}/$${MY_CONFIGURE}/$${TARGET} +RCC_DIR = $$PWD/../../temp/$${MY_OS}/$${OEM_NAME}/$${MY_ARCH}/$${MY_CONFIGURE}/$${TARGET} + +message(MY_OS: $$MY_OS) +message(MY_ARCH: $$MY_ARCH) +message(OEM_PREFIX: $$OEM_PREFIX) +message(OEM_PREFIX2: $$OEM_PREFIX2) +message(OEM_NAME: $$OEM_NAME) +message(MY_CONFIGURE: $$MY_CONFIGURE) +message(TARGET: $$TARGET) +message(DESTDIR: $$DESTDIR) +message(UI_DIR: $$UI_DIR) +message(MOC_DIR: $$MOC_DIR) +message(OBJECTS_DIR: $$OBJECTS_DIR) +message(RCC_DIR: $$RCC_DIR) + +win32 { + + CONFIG(release, debug|release) { + DESTLIB_PATH = $${PWD}/../../../../sdk/lib/win/$${MY_ARCH}/$${MY_CONFIGURE}/ + DESTLIB_PATH = $$replace(DESTLIB_PATH, /, \\) + message(DESTLIB_PATH: $$DESTLIB_PATH) + DESTDLL_PATH = $${PWD}/../../../../release/win/$${MY_ARCH}/$${MY_CONFIGURE}/ + DESTDLL_PATH = $$replace(DESTDLL_PATH, /, \\) + message(DESTDLL_PATH: $$DESTDLL_PATH) + DESTHEADER_PATH = $${PWD}/../../../../sdk/include/twainui/ + DESTHEADER_PATH = $$replace(DESTHEADER_PATH, /, \\) + message(DESTHEADER_PATH: $$DESTHEADER_PATH) + + SRCLIB_FILE = $${DESTDIR}/$${TARGET}.lib + SRCLIB_FILE = $$replace(SRCLIB_FILE, /, \\) + message(SRCLIB_FILE: $$SRCLIB_FILE) + SRCDLL_FILE = $${DESTDIR}/$${TARGET}.dll + SRCDLL_FILE = $$replace(SRCDLL_FILE, /, \\) + message(SRCDLL_FILE: $$SRCDLL_FILE) + SRCHEADER_FILE = $${PWD}/../../../modules/twainui/HGTwainUI.h + SRCHEADER_FILE = $$replace(SRCHEADER_FILE, /, \\) + message(SRCHEADER_FILE: $$SRCHEADER_FILE) + SRCPDB_FILE = $${DESTDIR}/$${TARGET}.pdb + SRCPDB_FILE = $$replace(SRCPDB_FILE, /, \\) + message(SRCPDB_FILE: $$SRCPDB_FILE) + + QMAKE_POST_LINK += xcopy /y $$SRCLIB_FILE $$DESTLIB_PATH && xcopy /y $$SRCDLL_FILE $$DESTDLL_PATH \ + && xcopy /y $$SRCHEADER_FILE $$DESTHEADER_PATH && xcopy /y $$SRCPDB_FILE $$DESTDLL_PATH + } +} + +unix { + + CONFIG(release, debug|release) { + DESTDLL_PATH = $$PWD/../../../../release/$${MY_OS}/$${MY_ARCH2}/ + message(DESTDLL_PATH: $$DESTDLL_PATH) + DESTHEADER_PATH = $${PWD}/../../../../sdk/include/twainui/ + message(DESTHEADER_PATH: $$DESTHEADER_PATH) + + SRCDLL_FILE = $${DESTDIR}/lib$${TARGET}.so + message(SRCDLL_FILE: $$SRCDLL_FILE) + SRCHEADER_FILE = $${PWD}/../../../modules/twainui/*.h + message(SRCHEADER_FILE: $$SRCHEADER_FILE) + + QMAKE_POST_LINK += cp $$SRCDLL_FILE $$DESTDLL_PATH && cp $$SRCHEADER_FILE $$DESTHEADER_PATH + } +} + +SOURCES += \ + ../../../modules/twainui/cfg/cJSON.c \ + ../../../modules/twainui/cfg/gb_json.cpp \ + ../../../modules/twainui/cutdialog.cpp \ + ../../../modules/twainui/cutpapertool.cpp \ + ../../../modules/twainui/device_menu.cpp \ + ../../../modules/twainui/dialog_input.cpp \ + ../../../modules/twainui/dllmain.cpp \ + ../../../modules/twainui/gaosixy.cpp \ + ../../../modules/twainui/setpicclrtool.cpp \ + ../../../utility/HGString.cpp \ + ../../../modules/twainui/widget.cpp \ + ../../../modules/twainui/dialog_progress_ui.cpp \ + ../../../modules/twainui/dialog_device_select.cpp +HEADERS += \ + ../../../modules/twainui/cfg/cJSON.h \ + ../../../modules/twainui/cfg/gb_json.h \ + ../../../modules/twainui/cutdialog.h \ + ../../../modules/twainui/cutpapertool.h \ + ../../../modules/twainui/device_menu.h \ + ../../../modules/twainui/dialog_input.h \ + ../../../modules/twainui/gaosixy.h \ + ../../../modules/twainui/setpicclrtool.h \ + ../../../utility/HGString.h \ + ../../../modules/twainui/widget.h \ + ../../../modules/twainui/dialog_progress_ui.h \ + ../../../modules/twainui/dialog_device_select.h + +FORMS += \ + ../../../modules/twainui/cutdialog.ui \ + ../../../modules/twainui/cutpapertool.ui \ + ../../../modules/twainui/dialog_input.ui \ + ../../../modules/twainui/setpicclrtool.ui \ + ../../../modules/twainui/widget.ui \ + ../../../modules/twainui/dialog_progress_ui.ui \ + ../../../modules/twainui/dialog_device_select.ui + +RESOURCES += \ + ../../../modules/twainui/TwainUI_resource.qrc + +TRANSLATIONS += \ + ../../../modules/twainui/TwainUI_zh_CN.ts \ + ../../../modules/twainui/TwainUI_zh_EN.ts \ + ../../../modules/twainui/qt_zh_CN.ts diff --git a/modules/twainui/TwainUI_resource.qrc b/modules/twainui/TwainUI_resource.qrc new file mode 100644 index 00000000..c8ef91ce --- /dev/null +++ b/modules/twainui/TwainUI_resource.qrc @@ -0,0 +1,7 @@ + + + TwainUI_zh_CN.qm + TwainUI_zh_EN.qm + qt_zh_CN.qm + + diff --git a/modules/twainui/TwainUI_zh_CN.qm b/modules/twainui/TwainUI_zh_CN.qm new file mode 100644 index 00000000..c1518ba7 Binary files /dev/null and b/modules/twainui/TwainUI_zh_CN.qm differ diff --git a/modules/twainui/TwainUI_zh_CN.ts b/modules/twainui/TwainUI_zh_CN.ts new file mode 100644 index 00000000..927b1025 --- /dev/null +++ b/modules/twainui/TwainUI_zh_CN.ts @@ -0,0 +1,3052 @@ + + + + + CutPaperTool + + + 自定义扫描区域 + + + + + 纸张尺寸: + + + + + A4 + + + + + (210*297) + + + + + DPI(像素/英寸): + + + + + 200 + 0×0×0 {200?} + + + + 单位: + + + + + 毫米(mm) + + + + + 英寸(in) + + + + + 像素(px) + + + + + 初始化选择区域 + + + + + x: + + + + + + + + mm + + + + + y: + + + + + w: + + + + + h: + + + + + Dialog_Admin + + Account sign in + 用户登录 + + + Account: + 用户: + + + Administrator + 管理员 + + + password: + 密码: + + + Show password + 显示密码 + + + Sign In + 登录 + + + Cancel + 取消 + + + Type password + 输入密码 + + + Warning + 警告 + + + Password incorrect. Please try again. + 密码错误,请再次输入 + + + + Dialog_AquireInto + + Batch scanning + 批量扫描 + + + configuration scheme management + 配置方案管理 + + + existing configuration scheme + existing configuration scheme: + 现有配置方案: + + + delete all configurations + 删除所有配置方案 + + + confgiuration information: + 配置信息: + + + change name + 重命名配置方案 + + + delete + 删除配置方案 + + + apply + 应用 + + + found scheme + 新建配置方案 + + + Restore Defaults + 恢复默认配置 + + + Directory + 目录 + + + Use subfolder based on current date + 使用当前日期建立子文件夹 + + + Use subfolder based on blank pages + 按照空白页建立子文件夹 + + + Use subfolder based on image color type + 按照图片颜色类型建立子文件夹 + + + File name + 文件名 + + + File name index + 文件索引 + + + Start index + 开始索引 + + + Digit(s) + 数字 + + + e.g. 'HGScan001' + 例如 “HGScan001” + + + Even and odd pages + 偶数和奇数页 + + + Odd pages + 奇数页 + + + Even pages + 偶数页 + + + Format + 格式 + + + Compression option + 压缩选项 + + + Save as multipages (TIFF/PDF/OFD/GIF) + 多页保存(TIFF/PDF/OFD/GIF) + + + 用户自定义页数 + 用户自定义页数 + + + Save as multipages (TIFF/PDF/OFD) + 多页保存(TIFF/PDF/OFD) + + + 所有页 + 所有页 + + + defaultCfg + 默认配置 + + + default scheme + 默认配置方案 + + + e.g. '%1%2' + 例如.“%1%2” + + + ok + 确定 + + + cancel + 取消 + + + Browse directory + 文件夹路径 + + + tips + 提示 + + + The configuration scheme already exists + 配置方案已存在 + + + + Dialog_ClrCache + + Dialog + 缓存设置 + + + Cache path: + 缓存路径: + + + setCachePath + 确认设置 + + + Cache occupied space: + 缓存占用空间: + + + 0 + 0×0×0 {0?} + + + B + B + + + (0 Byte) + (0 Byte) + + + Number of files: + 文件数量: + + + Clear Cache + 清除缓存 + + + ok + 确定 + + + cancel + 取消 + + + Close + 关闭 + + + Question + 询问 + + + Main window contains temporary files, clear cache would remove all of them. +Continue to clear? + 主窗口中包含临时文件,清除缓存将会移除这些文件。 +继续清除? + + + Main window contains temporary files, clear cache would remove all of them. + Continue to clear? + 主窗口中包含临时文件,清除缓存将会移除这些文件。 +继续清除? + + + yes + 确定 + + + no + 取消 + + + Information + 消息 + + + No cached file is available + 暂无缓存文件 + + + Cache clear successfully. + 缓存清除成功。 + + + Warning + 警告 + + + Cache clear failed or incompletely clear. + 缓存清除失败或者未清除干净。 + + + Browse directory + 文件夹路径 + + + tips + 提示 + + + directory can not be empty + 文件目录不能为空 + + + create cachePath failed: + 创建缓存路径失败: + + + + Dialog_Device_Scan + + Dialog + 对话框 + + + SANE_STATUS_NO_DOCS + 无纸 + + + Continue scan + 继续扫描 + + + Cancel scan + 取消扫描 + + + Complete scan + 完成扫描 + + + Out of memory + 内存不足 + + + Start scan + 开始扫描... + + + Warning + 警告 + + + Scanning in progress, closing not allowed + 扫描中,不允许退出 + + + Scan complete + 扫描完成 + + + + Dialog_Device_Select + + Select device + 选择设备 + + + OK + 确定 + + + Cancel + 取消 + + + tips + 提示 + + + + Dialog_Export + + ok + 确定 + + + cancel + 取消 + + + Export + 导出 + + + +Input is not valid. +Page range will be "Chosen Pages". + + 非法输入。 +页面范围将是“所选页面。默认切换“被选页码 + + + Ocr type: + OCR类型: + + + Compression Option + 压缩选项 + + + Page Range + 页码范围 + + + Chosen Pages + 被选页码 + + + All Pages + 所有页码 + + + Nominate Pages(example:1,3,6 or 3-6) + 指定页码(例如:1,3,6 或者3-6) + + + Page: + 页码 + + + Save as multipages (TIFF/PDF/OFD/GIF) + Save as multipages (TIFF/PDF/OFD) + 多页保存(TIFF/PDF/OFD/GIF) + + + Input is not valid. +Page range will be 'Chosen Pages'. + 输入无效。 +页码范围将是“被选页码” + + + English + 英语 + + + Simplified Chinese + 中文(简体) + + + Traditional Chinese + 中文(繁体) + + + Japanese + 日文 + + + Korean + 韩文 + + + + Dialog_ExportImageFile + + Dialog + 导出进度 + + + stop + 停止导出 + + + export failed: + 导出失败: + + + tip + 提示 + + + export succeed + 导出完成 + + + Insufficient access rights + 文件访问权限不足 + + + Ocr processing failed + OCR功能处理失败 + + + ok + 确定 + + + + Dialog_Feedback + + feedback: + 意见反馈: + + + contact: + 联系方式: + + + submit + 提交 + + + cancel + 取消 + + + feedback + 意见反馈 + + + Please leave your valuable comments and suggestions (required field). + 请留下您的意见与建议(必填)。 + + + Please leave your phone number, QQ or email address (required field). + 请留下您的电话、QQ或者邮箱等联系方式(必填)。 + + + error + 错误 + + + Comments and suggestions cannot be empty. + 意见与建议不能为空哦 + + + The contact information column cannot be empty. + 联系方式一栏不能为空哦 + + + tip + 提示 + + + submit succeed. + 提交成功 + + + submit failed. + 提交失败 + + + + Dialog_FullScreen + + Full Screen + 全屏显示 + + + Exit fullscreen + 按ESC退出全屏 + + + + Dialog_ImageEditor + + Dialog_ImageEditor + 图像编辑 + + + rect + 矩形 + + + Rect + 矩形 + + + ellipse + 椭圆 + + + Ellipse + 椭圆 + + + line + 直线 + + + Line + 直线 + + + Pen + 画笔 + + + arrow + 箭头 + + + Arrow + 箭头 + + + text + 文字 + + + Text + 文字 + + + zoomIn + 放大 + + + 1:1 + 1比1 + + + zoomOut + 缩小 + + + Color + 彩色 + + + color + 彩色 + + + LineWidth + 线宽 + + + 1 pix + 1 像素 + + + 3 pix + 3 像素 + + + 5 pix + 5 像素 + + + 8 pix + 8 像素 + + + TextSize + 文字大小 + + + 6 + 6 + + + 7 + 7 + + + 8 + 8 + + + 9 + 9 + + + 72 + 10 + 72 + + + 96 + 11 + 96 + + + 128 + 12 + 128 + + + 160 + 14 + 160 + + + 16 + 16 + + + 18 + 18 + + + 20 + 20 + + + 22 + 22 + + + 24 + 24 + + + 26 + 26 + + + 28 + 28 + + + 36 + 36 + + + 48 + 48 + + + 200 + 200 + + + Zoomin + 放大 + + + Fit + 还原 + + + 100% + 0×0×0 {100%?} + + + Zoomout + 缩小 + + + undo + 撤销 + + + Undo + 撤销 + + + ok + 确定 + + + Ok + 确定 + + + cancel + 取消 + + + Cancel + 取消 + + + + Dialog_ImageInfo + + Image information + 图像信息 + + + ok + 确定 + + + File + 文件 + + + Image + 图像 + + + None + + + + + Dialog_ImgProc_Adjust + + Adjust + 亮度/对比度/伽马 + + + Show preview + 显示缩略图 + + + Before + 处理前 + + + After + 处理后 + + + Apply to image + 应用到图像 + + + ok + 确定 + + + cancel + 取消 + + + restore default + 恢复默认 + + + + Dialog_ImgProc_AutoCrop + + Auto crop + 自动裁剪 + + + Auto correct skew + 歪斜校正 + + + Fill black frame type + 背景填充方式 + + + Convex polygon + 凸多边形 + + + Concave polygon + 凹多边形 + + + Auto Color + 自适应文稿底色 + + + Default Color + 白色 + + + Advanced parameters + 高级参数设置 + + + Threshold + 阈值 + + + Anti background noise + 背景抗噪 + + + Edge indent + 边缘缩进 + + + before + 处理前 + + + after + 处理后 + + + Image crop + 裁剪/纠偏/消除黑框 + + + ok + 确定 + + + cancel + 取消 + + + restore default + 恢复默认 + + + + Dialog_Input + + + Dialog + + + + + 输入: + + + + + Ok + 确定 + + + + Cancel + 取消 + + + configuration scheme name change + 配置改名 + + + tips + 提示 + + + The content can not be empty + 内容不能为空 + + + new name can not be empty + 新命名不可为空 + + + + Dialog_InsertIndex + + Insert index selection + 插入所选项 + + + Insert location + 插入位置 + + + Before first page + 第一页之前 + + + Before current page + 当前页之前 + + + After current page + 当前页之后 + + + After last page + 最后一页之后 + + + ok + 确定 + + + cancel + 取消 + + + + Dialog_LogManager + + Dialog + 日志导出 + + + Directory... + 目录... + + + File Type: + 文件类型: + + + All(*.*) + 所有文件(*.*) + + + Image(*.jpg,*.bmp,*.png,*.tif) + 图像文件(*.jpg,*.bmp,*.png,*.tif) + + + PDF(*.pdf) + PDF(*.pdf) + + + Text(*.txt) + 文本(*.txt) + + + Config(*.ini,*.xml) + 配置文件(*.ini,*.xml) + + + Website(*.html) + 网页(*.html) + + + HGlog(*.HGLog) + 华高日志(*.HGLog) + + + Clear + 清空 + + + Export... + 导出... + + + Cancel + 取消 + + + Warning + 警告 + + + Please select file in the list. + 请选择列表中的文件。 + + + Choose saving path + 选择保存路径 + + + Information + 消息 + + + Log files export finished. + 日志文件导出完成。 + + + Question + 询问 + + + All log files will be cleared. +Continue to clear? + 所有日志文件将被清除。 +继续清空吗? + + + All log files cleared. + 已清除所有日志文件。 + + + + Dialog_MoveTo + + move to + 移动到 + + + target index: + 目标位置: + + + insert pos: + 插入位置: + + + + Dialog_MultiRotate + + Multiple rotation + 多页旋转 + + + Rotation + 旋转 + + + 90° + 旋转90° + + + 180° + 旋转180° + + + -90° + 旋转-90° + + + Pages + 页码 + + + Current page + 当前页 + + + Selected pages + 所选页 + + + All odd pages + 所有奇数页 + + + All even pages + 所有偶数页 + + + All pages + 所有页 + + + Attentions: +This operation will NOT rotate the files that may contain multiple pages, such as .pdf, .tif, etc. + 注意: +此操作不会旋转可能包含多页的文件,例如PDF、TIFF等。 + + + ok + 确定 + + + cancel + 取消 + + + + Dialog_MultiRotateImageFile + + Dialog + 多页旋转进度 + + + stop + 停止多页旋转 + + + operation success + 操作成功 + + + multirotate operation failed: + 多页旋转操作失败: + + + tip + 提示 + + + ok + 确定 + + + + Dialog_OpenImageIndex + + Open Page + 跳转至 + + + pageIndex: + 页数: + + + ok + 确定 + + + cancel + 取消 + + + + Dialog_PasswordChange + + Change password + 用户密码修改 + + + Old password: + 旧密码: + + + New password: + 新密码: + + + Confirm new password: + 确认新密码: + + + Show password + 显示密码 + + + Password only allowed to use numbers, English and special characters. +Password length should between 8-20 charactors. + 密码只允许使用数字、英文和特殊字符。 +密码长度应在8-20个字符之间。 + + + OK + 确定 + + + Cancel + 取消 + + + Type old password + 输入旧密码 + + + Type new password + 输入新密码 + + + Retype new password + 确认新密码 + + + Warning + 警告 + + + Old password incorrect. +Please try again. + 旧密码错误。请重试。 + + + New password and confirm password are not matched. +Please make sure the two passwords are the same. + 新密码和确认密码不匹配。 +请确保两个密码相同。 + + + Password only allowed to use numbers, English and special characters. + 新密码只允许使用数字、英文和特殊字符。 + + + + Dialog_SaveAs + + Save As + 另存为 + + + Compression Option + 压缩选项 + + + Use subfolder based on current date + 使用当前日期建立子文件夹 + + + Ocr type: + OCR类型: + + + English + 英语 + + + Simplified Chinese + 中文(简体) + + + Traditional Chinese + 中文(繁体) + + + Japanese + 日文 + + + Korean + 韩文 + + + + Dialog_SaveMessageBox + + Dialog + 询问 + + + Yes + + + + No + + + + save, do not remind again + 保存并不再提醒 + + + modified, save it? + 图像已被修改,是否保存修改? + + + + Dialog_SaveQuality + + Save Option + 压缩质量设置 + + + ok + 确定 + + + cancel + 取消 + + + + Dialog_Source_Select + + Select source + 选择源 + + + OK + 确定 + + + Cancel + 取消 + + + tips + 提示 + + + Load library failed + 加载库失败 + + + Find function failed + 查找函数失败 + + + + Dialog_Twain_Source_Select + + Select source + 选择源 + + + OK + 确定 + + + Cancel + 取消 + + + + Dialog_WriteSettings + + Write Settings + 写入设置 + + + Compression for black&white picture + 黑白图片 + + + None + + + + LZW + LZW + + + CCITT G4 + CCITT G4 + + + Compression for color picture + 彩色图片 + + + JPEG + JPEG + + + Quality + 质量 + + + Lowest + + + + Best + + + + + Dialog_device_select + + + Dialog + 设备选择 + + + + Ok + 确定 + + + + Cancel + 取消 + + + + Dialog_progress_ui + + + Dialog + 扫描状态 + + + + Cancel Scan + 取消扫描 + + + + Dialog_updateProgress + + Dialog + 安装包下载中... + + + stop + 停止 + + + + Dialog_upgrade + + upgrade the latest version + 升级到最新版本 + + + select version + 选择其他版本 + + + Detected installable versions: + 检测到可安装版本: + + + install + 安装 + + + cancel + 取消 + + + upgrade online + 检查更新 + + + upgrade contents: + 升级内容: + + + bug description: + 错误描述: + + + bug description: + + 错误描述: + + + + upgrade contents: + + 更新内容: + + + + +bug description: + + +错误描述: + + + + The current version is the latest! The current version number is : + 当前为最新版本!版本号为: + + + Discover the new version : + 发现新版本: + + + ,the current version is : + ,当前版本为: + + + tip + 提示 + + + Already in current version + 当前版本已安装! + + + + Dialog_upgradeFirmware + + text + 文字 + + + upgrade + 更新升级 + + + firmware upgrade in progress, please wait... + 设备固件自动更新升级中,请稍候... + + + + GraphicsScene + + SongTi + 宋体 + + + + HGImgThumb + + tips + 提示 + + + unsupported file format + 拖拽仅支持jpg、bmp、png、pnm、tif/tiff、gif、pdf和ofd格式 + + + file have been loaded + 文件已经加载! + + + file have been loaded, do you want to move to end? + 文件已经加载,是否将其移动到末尾? + + + file have been loaded, do you want to move to specified location? + 文件已经加载,是否将其移动到指定位置? + + + Question + 提示 + + + some files have been loaded, do you want to move to end? + 有文件已经加载,是否将其移动到末尾? + + + some files have been loaded, do you want to move to specified location? + 有文件已经加载,是否将其移动到指定位置? + + + some files have been loaded, do you want to move? + 有图片已经被打开,是否移动这些图片的位置? + + + yes + + + + no + + + + + HGImgView + + tips + 提示 + + + unsupported file format + 拖拽仅支持jpg、bmp、png、tif/tiff、pdf和ofd格式 + + + + MainWindow + + MainWindow + 华高扫描软件 + + + menu_file + 文件 + + + menu_scan + 扫描 + + + menu_view + 视图 + + + menu_Auto_Image_Size + menuAuto_Image_Size + 自动图片尺寸 + + + menu_page + 页面 + + + menu_multiPages + 多页 + + + menu_image + 图像 + + + menuRotate + 旋转 + + + menu_user + 用户 + + + menu_info + 信息 + + + menu_device + 设备 + + + toolBar + 工具栏 + + + act_open + 打开... + + + act_insert + 插入本地文件... + + + act_save + 保存 + + + act_saveAs + 另存为... + + + act_Export + 导出... + + + act_closeFile + 关闭选中项 + + + act_closeAll + 关闭所有项 + + + act_imageInfo + 图像信息 + + + act_exit + 退出 + + + act_scannerSettings + 扫描设置... + + + act_acquire + 扫描 + + + act_acquireSingle + 扫描单张 + + + act_acquireInto + 扫描至... + + + act_fullscreen + 全屏显示 + + + act_fitWindowSize + 适应视图框尺寸 + + + act_fitWindowWidth + 适应视图框宽度 + + + act_realSize + 真实大小 + + + act_zoomIn + 放大 + + + act_zoomOut + 缩小 + + + act_toolBar + 工具栏 + + + act_statusBar + 状态栏 + + + act_thumbnailBar + 缩略图栏 + + + act_colorInfo + 色彩信息 + + + act_previous + 上一张 + + + act_next + 下一张 + + + act_first + 第一张 + + + act_last + 最后一张 + + + act_openPageNum + 跳转至... + + + act_previousPage + 上一页 + + + act_nextPage + 下一页 + + + act_firstPage + 第一页 + + + act_lastPage + 最后一页 + + + act_adjust + 亮度/对比度/伽马... + + + act_90Left + 左旋转90度 + + + act_90Right + 右旋转90度 + + + act_180 + 旋转180度 + + + act_multiRotate + 多页旋转... + + + act_autoCrop + 裁剪/纠偏/消除黑框... + + + act_signIn + 登录... + + + act_passwordChange + 密码修改... + + + act_signOut + 登出 + + + act_log + 日志管理... + + + act_clrCache + 缓存设置... + + + act_consume + 耗材状态... + + + act_help + 帮助 + + + act_about + 关于... + + + act_insertFromScanner + 从扫描插入... + + + act_clearRoller + 清除滚轴计数 + + + act_imageEdit + 图像编辑... + + + act_sortPages + 书籍排序 + + + act_autoSave + 自动保存 + + + act_update + 检查更新... + + + act_feedback + 意见反馈... + + + act_device_log + 导出设备日志 + + + act_driver_log + 导出驱动日志 + + + act_deleteFile + 删除选中项 + + + HuaGoScan + 华高扫描软件 + + + Grid + 多列显示 + + + Move To... + 移动到... + + + Insert files + 插入文件 + + + nodevice + 没有发现扫描仪 + + + Question + 询问 + + + modified, save it? + 图像已被修改。 +是否保存修改? + + + file lost, remove it? + 文件已丢失,是否删除? + + + already connected + 已连接 + + + disconnected + 已断开连接 + + + %1/%2%3.%4 + %1/%2%3.%4 + + + scan starting... + 开始扫描... + + + scan finished + 扫描完成 + + + Clear, then start scan + 清空并启动扫描 + + + Do NOT clear, then start scan + 不清空并启动扫描 + + + Already exist images in image list. +Do you want to clear? + 图像列表中已存在图像。 +是否清空? + + + Information + 消息 + + + Insufficient disk space + 磁盘空间不足,请删除不需要的文件,以保证有足够的空间 + + + Open images + 打开图片 + + + Insert images + 插入图片 + + + info + 信息 + + + save failed + 保存失败 + + + binary + 黑白 + + + gray + 256级灰度 + + + rgb + 24位彩色 + + + Please wake up the device manually + 请手动唤醒设备 + + + UniScan + 紫光扫描软件 + + + default scheme + 默认配置方案 + + + thumbnailBar enabled + 显示缩略图栏 + + + thumbnailBar hidden + 隐藏缩略图栏 + + + cancel + 取消 + + + save succeed + 保存成功 + + + find savePath in thumbnail + 图片名在列表中已存在 + + + Please select at least one picture before export + 请至少选中一张图片再进行导出 + + + File name + 文件名 + + + File path + 文件路径 + + + File size + 文件大小 + + + Creation date/time + 创建时间 + + + Modified date/time + 修改时间 + + + Accessed date/time + 访问时间 + + + Format + 格式 + + + Width + 宽度 + + + Height + 高度 + + + depth + 深度 + + + Color model + 色彩模式 + + + DPI + 每英寸像素点 + + + Print size + 打印尺寸 + + + Frame + + + + None + + + + Mono + 黑白 + + + Gray + 灰度 + + + Color + 彩色 + + + Not supported + 不支持 + + + Warning + + +警告 + + + Device is Running! +Please finish scanning first. + 设备正在运行! +请先结束扫描。 + + + cache path folder limit:%1 + 无法访问当前缓存路径:%1 +请尝试在【用户】菜单登录管理员账户,前往【缓存设置】更改缓存路径。 + + + aquireinto folder limit:%1 + 无法访问当前缓存路径:%1 +请尝试在【扫描到】更改缓存路径。 + + + Image processing failed + 图像处理失败 + + + Ocr init failed + OCR初始化错误 + + + Ocr failed + OCR错误 + + + File does not exist + 文件不存在 + + + Failed to load dynamic library + 加载动态库失败 + + + File data error + 文件数据错误 + + + Image format processing error + 图像格式处理错误 + + + Out of memory + 内存不足 + + + Failed + 错误 + + + The language switch is successful and takes effect the next time the software is started! + 语言切换成功,下次启动软件时生效! + + + Are you sure to delete selected file? + 您确定彻底删除选中项文件? + + + already waked up device + 已唤醒设备 + + + be ready + 就绪 + + + folder limit + 无法访问当前缓存路径 +请尝试在【用户】菜单登录管理员账户,前往【缓存设置】更改缓存路径 + + + Insufficient access rights + 文件访问权限不足 + + + export succeed + 导出完成 + + + Ocr processing failed + 图像处理失败 + + + Are you sure to close + 您确定要断开设备: + + + ? + 吗? + + + close + 关闭 + + + tip + 提示 + + + Other versions not available + 未获取到其他版本 + + + The device does not support this operation + 设备不支持该操作 + + + IO error + IO错误 + + + error + 错误 + + + get versionlist failed + 获取版本列表错误 + + + Application is about to close.Make sure all needed files are saved. +Continue to close? + 应用程序即将关闭。请确认所有需要的文件已被保存。 +是否继续关闭? + + + Sure to sign out administrator account? + 是否确定登出管理员账户? + + + confirm the operation + 确认操作 + + + Are you sure to clear the rollor acount? + 你确定要清除滚轴计数吗 + + + Please re-enter the Abount screen to obtain the latest value + 请重新进入关于界面以获取最新值 + + + roller number + 滚轴张数 + + + open scanner + 打开扫描仪 + + + app name + 华高扫描软件 + + + success + 成功 + + + apply setting + 应用配置 + + + success + 成功 + + + failed + 失败 + + + failed + 失败 + + + warning + 警告 + + + the disk space in the current path is unsufficient, please select a new path or clear the disk space in time. + 当前路径磁盘空间不足, +请重新选择路径或及时清理磁盘空间。 + + + lost config + 配置丢失 + + + apply setting + 应用配置 + + + start failed + 启动失败 + + + HanvonScan + 汉王扫描软件 + + + LanxumScan + 立思辰扫描软件 + + + CumtennScan + 沧田扫描软件 + + + MicrotekScan + Microtek DocWizard EX 扫描软件 + + + menu_language + 语言 + + + act_simpCN + 简体中文 + + + act_English + English + + + auto save + 自动保存 + + + when switching pictures, save the edited pictures directly without reminding + 切换图片时,不提醒,直接保存编辑过的图片 + + + statusBar displayed + 显示状态栏 + + + statusBar hidden + 隐藏状态栏 + + + toolBar displayed + 显示工具栏 + + + toolBar hidden + 隐藏工具栏 + + + colorInfo enabled + 启用图像信息 + + + colorInfo disenabled + 关闭图像信息 + + + enabling automatic saving + 启用自动保存 + + + cancel auto save + 取消自动保存 + + + Automatically save the edited the edited iamge when switching pictures. To cancel, uncheck the menu item: image-> automatically save + 切换图片时,自动保存编辑过的图像。若想取消,请取消勾选菜单项:图像->自动保存 + + + yes + 确定 + + + save, do not remind again + 保存,不再提醒 + + + no + 取消 + + + found device + 发现设备 + + + reconnected + 重新连接 + + + already connected, but open faild + 已经连接,但打开失败 + + + save image failed: + 存图失败: + + + create savepath failed: + 创建文件夹失败: + + + %1%2%3.%4 + %1%2%3.%4 + + + create image doc failed: + 创建图片文件失败: + + + save image doc failed: + 保存图片文件失败: + + + start failed! + 启动安装程序失败! + + + There are pictures that have not been saved. +Are you sure to close? + 有图像未保存,确定关闭? + + + found device : %1 + 发现设备 : %1 + + + tips + 提示 + + + Are you sure to close? + 确定关闭应用软件? + + + confirm operation + 确认操作 + + + are you sure to clear the roller count? + 您确定要清除滚轴计数吗 + + + hint + 提示 + + + Roller scanned count has been set to 0. + 辊轴计数已置零 + + + Roller scanned count reset failed. + 重置滚轴计数失败 + + + Error + 错误 + + + Document missing! It would be deleted or renamed. + 文档丢失!文档可能已被删除或被重命名。 + + + HuaGoScan Application + 华高扫描应用程序 + + + 2018-2022 HuaGoScan + 2018-2021 HUAGOSCAN + + + Manufacturer/Developer: Ningbo Huagao Info&Tech co.,ltd. + 制造商/开发商: 宁波华高信息科技有限公司 + + + <br>Company website: <a href='http://www.huagaochina.com/'>www.huagaochina.com</a> + <br>公司网址: <a href='http://www.huagaochina.com/'>www.huagaochina.com</a> + + + <br>Contact: +86 0574 27974866 + <br>联系电话: +86 0574 27974866 + + + <br>Company address: No.655,Xueshi Road,Yinzhou district,Ningbo,Zhejiang,China(PRC) + <br>地址: 浙江省宁波市鄞州区学士路655号 C栋211 + + + Navigation: <a href='https://j.map.baidu.com/7e/1TO'>Visit in Baidu map.</a> + <br>导航地址: <a href='https://j.map.baidu.com/7e/1TO'>百度地图访问</a> + + + About %1 + 关于 %1 + + + <p>%1</p><p>Version: %2<br>CopyRight: &#169; %3</p><p>%4%5%6%7%8%9</p> + <p>%1</p><p>版本: %2<br>版权: &#169; %3</p><p>%4%5%6%7%8%9</p> + + + about %1 + 关于 %1 + + + <p>Version: %1</p> + <p>版本: %1</p> + <p>版本: %1</p> + + + <p>CopyRight: &#169; %1</p> + <p>版权: &#169; %1</p> + <p>版权: &#169; %1</p> + + + <p>%1: <a href='%2'>%3</a></p> + <p>%1: <a href='%2'>%3</a></p> + + + <p>%1: %2</p> + <p>%1: %2</p> + + + + QObject + + error + 错误 + + + + default_setting + 默认设置 + + + &Save + 保存(&S) + + + + Widget + + + Widget + + + + + zuobiaozhou + 坐标轴 + + + + Widget_Imgproc_Base + + Brightness + 亮度 + + + Contrast + 对比度 + + + Gamma correction + Gamma校正 + + + + Widget_StatusBar + + 0/0 + 0/0 + + + 0*0*0 + 0×0×0 + + + page + 页码 + + + size + 分辨率 + + + mousePos + 坐标 + + + zoom + 缩放 + + + + cutDialog + + + cutDialog + + + + + device_menu + + + no device + 没有发现扫描仪 + + + + default setting + 默认设置 + + + + dialog_log + + 日志 + 扫描状态信息 + + + cancel scan + 取消扫描 + + + auto scroll + 自动滚动 + + + export images + 导出图片 + + + continue scan + 继续扫描 + + + finish scan + 完成扫描 + + + (epicycle scanning images %u picture) + (本轮共扫描 %u 幅) + + + fold + 收起 + + + unfold + 展开 + + + clear + 清空信息 + + + + hg_settingdialog + + set + 设置 + + + configuration management + 配置管理 + + + No configuration selected + 无配置选中 + + + No custom configuration was found + 无配置方案 + + + configuration name: + configuration name: + 配置名称: + + + configuration change name + 配置改名 + + + apply configuration--> + 应用配置--> + + + delete configuration + 删除配置 + + + + existing configuration scheme + 现有配置方案: + + + + change name + 改名 + + + + delete + 删除 + + + + apply + 应用 + + + + delete all configurations + 删除所有配置 + + + + confgiuration information: + 配置信息: + + + + scan + 扫描 + + + + + ok + 确定 + + + + cancel + 取消 + + + + configuration scheme management + 配置方案管理 + + + + regional crop + 区域裁剪 + + + + custom tone curve + 自定义色调曲线 + + + + Please select to overwrite the original configuration: + 请选择覆盖原来的配置: + + + + ,or add a new configuration + ,或者新增配置 + + + + save the configuration + 保存配置 + + + The Settings you just set are in the original configuration " + The Settings you just set are in the original configuration “ + 您刚才的设置是在原有配置 “ + + + " changed on the basis,Please select overwrite this configuration or add a new one? +Yes: cover " + ” changed on the basis,Please select overwrite this configuration or add a new one? +Yes: cover “ + ” 基础上更改的,请选择是覆盖这个配置,还是增加新的配置? +是: 覆盖 “ + + + " +No: add new configuration + ” +No: add new configuration + +否: 增加新的配置: + + + yes + + + + no + + + + + <h6><b> + <h6><b> + + + + cover original configuration: + 覆盖原来配置: + + + + add new configuration + 新增配置 + + + + rename: + 更名: + + + + + + tips + 提示 + + + + scheme name cannot be empty + 配置名不能为空 + + + + + scheme name: + 配置名: + + + + + already exists + 已存在 + + + + :</b></h6> + :</b></h6> + + + + <p> + <p> + + + + </p> + </p> + + + + configuration scheme name change + 配置改名 + + + + + be sure to delete the configuration + 确认删除配置 + + + + Are you sure you want to delete the configuration " + 您确认要删除配置 + + + + " ? + + + + Are you sure you want to delete the configuration ‘ + 您确认要删除配置 ‘ + + + ’ ? + ’ 吗? + + + + Are you sure you want to delete the configuration? + 您确认要删除所有配置吗? + + + + setPicClrTool + + + 自定义色调曲线 + + + + + 自定义 + 自定 + + + + + 负片(RGB) + + + + + 彩色负片(RGB) + + + + + 较暗(RGB) + + + + + 较亮(RGB) + + + + + RGB + + + + + 灰 + + + + + 红 + + + + + 蓝 + + + + + 绿 + + + + + 初始化 + + + + + 输入: + + + + + 输出: + + + + diff --git a/modules/twainui/TwainUI_zh_EN.qm b/modules/twainui/TwainUI_zh_EN.qm new file mode 100644 index 00000000..8a9a757d Binary files /dev/null and b/modules/twainui/TwainUI_zh_EN.qm differ diff --git a/modules/twainui/TwainUI_zh_EN.ts b/modules/twainui/TwainUI_zh_EN.ts new file mode 100644 index 00000000..95100c87 --- /dev/null +++ b/modules/twainui/TwainUI_zh_EN.ts @@ -0,0 +1,2681 @@ + + + + + CutPaperTool + + + 自定义扫描区域 + Custom scan area + + + + 纸张尺寸: + Paper size: + + + + A4 + + + + + (210*297) + + + + + DPI(像素/英寸): + DPI(Primitive / inches): + + + + 200 + + + + + 单位: + Unit: + + + + 毫米(mm) + Millimeter(mm) + + + + 英寸(in) + Inch(in) + + + + 像素(px) + Primitive(px) + + + + 初始化选择区域 + Initialize selected area + + + + x: + + + + + + + + mm + + + + + y: + + + + + w: + + + + + h: + + + + + Dialog_Admin + + Account sign in + User login + + + Account: + User: + + + Administrator + Administrator + + + password: + Password: + + + Show password + Show password + + + Sign In + Login + + + Cancel + Cancel + + + Type password + Enter password + + + Warning + Warning + + + Password incorrect. Please try again. + Password error; please enter again. + + + + Dialog_AquireInto + + Batch scanning + Batch scan + + + configuration scheme management + Configuration plan management + + + existing configuration scheme + existing configuration scheme: + Existing configuration plan: + + + delete all configurations + Delete all configurations + + + confgiuration information: + Configuration information: + + + change name + Rename + + + delete + Delete + + + apply + Apply + + + found scheme + Found scheme + + + Restore Defaults + Restore default configuration + + + Directory + Table of Contents + + + Use subfolder based on current date + Create a subfolder using the current date + + + Use subfolder based on blank pages + Create subfolders according to blank pages + + + Use subfolder based on image color type + Create a subfolder according to the image color type + + + File name + File name + + + File name index + File index + + + Start index + Start index + + + Digit(s) + Number + + + e.g. 'HGScan001' + For example HGScan001 + + + Even and odd pages + Even number and odd number pages + + + Odd pages + Odd number page + + + Even pages + Even number page + + + Format + Format + + + Compression option + Compression options + + + Save as multipages (TIFF/PDF/OFD/GIF) + Save multiple pages(TIFF/PDF/OFD/GIF) + + + 所有页 + All pages + + + 用户自定义页数 + User custom pages + + + default scheme + Default scheme + + + e.g. '%1%2' + For example"%1%2" + + + ok + OK + + + cancel + Cancel + + + Browse directory + Folder path + + + tips + Prompt + + + The configuration scheme already exists + The configuration scheme already exists + + + + Dialog_ClrCache + + Dialog + Cache settings + + + Cache path: + Cache path: + + + Cache occupied space: + Cache space used: + + + 0 + 0×0×0 {0?} + + + B + B + + + (0 Byte) + (0 Byte) + + + Number of files: + Number of files: + + + Clear Cache + Clear cache + + + ok + OK + + + cancel + Cancel + + + Information + Information + + + No cached file is available + Temporarily no cache files + + + Question + Ask + + + Main window contains temporary files, clear cache would remove all of them. + Continue to clear? + The main window contains temporary files; clearing the cache will remove these files. +Continue clearing? + + + yes + OK + + + no + Cancel + + + Cache clear successfully. + Cache cleared successfully. + + + Warning + Warning + + + Cache clear failed or incompletely clear. + Failed to clear cache or not cleared. + + + Browse directory + Folder path + + + tips + Prompt + + + directory can not be empty + File directory cannot be empty + + + create cachePath failed: + Failed to create cache path: + + + + Dialog_Device_Scan + + Dialog + Dialog + + + SANE_STATUS_NO_DOCS + No documents + + + Continue scan + Continue scan + + + Cancel scan + Cancel scan + + + Complete scan + Complete scan + + + Out of memory + Insufficient memory + + + Start scan + Start scan... + + + Warning + Warning + + + Scanning in progress, closing not allowed + Scanning in progress, closing not allowed + + + Scan complete + Scan complete + + + + Dialog_Device_Select + + Select device + Select device + + + OK + OK + + + Cancel + Cancel + + + tips + Tips + + + + Dialog_Export + + Export + Export + + + Page Range + Page range + + + Nominate Pages(example:1,3,6 or 3-6) + Specific page number (For example:1,3,6 or 3-6) + + + Chosen Pages + Selected pages + + + All Pages + All pages + + + Page: + Page number: + + + +Input is not valid. +Page range will be "Chosen Pages". + + Input invalid. +The page range will be “selected pages” + + + Save as multipages (TIFF/PDF/OFD/GIF) + Save multiple pages(TIFF/PDF/OFD/GIF) + + + Ocr type: + OCR type: + + + Compression Option + Compression options + + + ok + OK + + + cancel + Cancel + + + Input is not valid. +Page range will be 'Chosen Pages'. + Input invalid. +The page range will be “selected pages” + + + English + English + + + Simplified Chinese + Simplified Chinese + + + Traditional Chinese + Traditional Chinese + + + Japanese + Japanese + + + Korean + Korean + + + + Dialog_ExportImageFile + + Dialog + Export progress + + + stop + Stop exporting + + + export succeed + Export completed + + + export failed: + Export failed: + + + tip + Prompt + + + ok + OK + + + + Dialog_Feedback + + Dialog + Opinions and feedback + + + feedback: + Opinions and feedback: + + + contact: + Contact method: + + + submit + Submit + + + cancel + Cancel + + + feedback + Opinions and feedback + + + Please leave your valuable comments and suggestions (required field). + Please leave your opinions and suggestions (required). + + + Please leave your phone number, QQ or email address (required field). + Please leave a contact method, such as a phone number or E-mail address (required). + + + error + Error + + + Comments and suggestions cannot be empty. + Opinions and suggestions cannot be blank + + + The contact information column cannot be empty. + The contact method field cannot be blank + + + tip + Prompt + + + submit succeed. + Submitted successfully. + + + submit failed. + Submission failed. + + + + Dialog_FullScreen + + Full Screen + Fullscreen display + + + Exit fullscreen + Press ESC to exit full screen + + + + Dialog_ImageEditor + + Dialog_ImageEditor + Image edit + + + rect + Rectangle + + + Rect + Rectangle + + + ellipse + Oval + + + Ellipse + Oval + + + line + Straight line + + + Line + Straight line + + + Pen + Brush + + + arrow + Arrow + + + Arrow + Arrow + + + text + Text + + + Text + Text + + + Color + Color + + + color + Color + + + LineWidth + Line width + + + 1 pix + 1 Primitive + + + 3 pix + 3 Primitive + + + 5 pix + 5 Primitive + + + 8 pix + 8 Primitive + + + TextSize + Text size + + + zoomin + Zoom in + + + Zoomin + Zoom in + + + fit + Restore + + + Fit + Restore + + + 100% + 0×0×0 {100%?} + + + 1:1 + 1:1 + + + zoomout + Zoom out + + + Zoomout + Zoom out + + + undo + Revoke + + + Undo + Revoke + + + ok + OK + + + Ok + OK + + + cancel + Cancel + + + Cancel + Cancel + + + + Dialog_ImageInfo + + Image information + Image information + + + ok + OK + + + File + File + + + Image + Image + + + None + None + + + + Dialog_ImgProc_Adjust + + Adjust + Brightness/ contrast/ gamma + + + Show preview + Show thumbnails + + + Before + Before processing + + + After + After processing + + + Apply to image + Apply to image + + + ok + OK + + + cancel + Cancel + + + restore default + Restore defaults + + + + Dialog_ImgProc_AutoCrop + + Auto crop + Auto crop + + + Auto correct skew + Skew correction + + + Fill black frame type + Background filling method + + + Convex polygon + Convex polygon + + + Concave polygon + Concave polygon + + + Auto Color + Adaptive document background + + + Default Color + White + + + Advanced parameters + Advanced parameter settings + + + Threshold + Threshold + + + Anti background noise + Background anti-noise + + + Edge indent + Edge indent + + + before + Before processing + + + after + After processing + + + Image crop + Crop/ Deskew/ Remove black box + + + ok + OK + + + cancel + Cancel + + + restore default + Restore defaults + + + + Dialog_Input + + + Dialog + + + + + 输入: + Enter: + + + + Ok + OK + + + + Cancel + Cancel + + + configuration scheme name change + Rename configuration + + + tips + Prompt + + + The content can not be empty + The content can not be empty + + + + Dialog_InsertIndex + + Insert index selection + Insert selected items + + + Insert location + Insert position + + + Before first page + Before the first page + + + Before current page + Before current page + + + After current page + After current page + + + After last page + After the last page + + + ok + OK + + + cancel + Cancel + + + + Dialog_LogManager + + Dialog + Log export + + + Directory... + Table of Contents: + + + File Type: + File type: + + + All(*.*) + All files(*.*) + + + Image(*.jpg,*.bmp,*.png,*.tif) + Image file(*.jpg,*.bmp,*.png,*.tif) + + + PDF(*.pdf) + PDF(*.pdf) + + + Text(*.txt) + Text(*.txt) + + + Config(*.ini,*.xml) + Setting file(*.ini,*.xml) + + + Website(*.html) + Webpage(*.html) + + + HGlog(*.HGLog) + HUAGOSCAN log(*.HGLog) + + + Clear + Clear + + + Export... + Export... + + + Cancel + Cancel + + + Warning + Warning + + + Please select file in the list. + Please select files in the list. + + + Choose saving path + Select save path + + + Information + Information + + + Log files export finished. + Log file export completed. + + + Question + Ask + + + All log files will be cleared. +Continue to clear? + All log files will be cleared. +Continue clearing? + + + All log files cleared. + All log files cleared. + + + + Dialog_MoveTo + + move to + Move to + + + target index: + Target location: + + + + Dialog_MultiRotate + + Multiple rotation + Batch rotate + + + Rotation + Rotate + + + 90° + Rotate 90° + + + 180° + Rotate 180° + + + -90° + Rotate -90° + + + Pages + Pages + + + Current page + Current page + + + Selected pages + Selected page + + + All odd pages + All odd pages + + + All even pages + All even pages + + + All pages + All pages + + + Attentions: +This operation will NOT rotate the files that may contain multiple pages, such as .pdf, .tif, etc. + Note: +This operation will not rotate files that may include multiple pages. + + + ok + OK + + + cancel + Cancel + + + + Dialog_MultiRotateImageFile + + Dialog + Batch rotate progress + + + stop + Stop batch rotate + + + operation success + Operation successful + + + multirotate operation failed: + Multi-stream rotation operation failed: + + + tip + Prompt + + + ok + OK + + + + Dialog_OpenImageIndex + + Open Page + Jump to... + + + pageIndex: + Page number: + + + ok + OK + + + cancel + Cancel + + + + Dialog_PasswordChange + + Change password + Change user password + + + Old password: + Old password: + + + New password: + New password: + + + Confirm new password: + Confirm new password: + + + Show password + Show password + + + Password only allowed to use numbers, English and special characters. +Password length should between 8-20 charactors. + Only numbers, English and special characters are allowed for the password. +The password length should be within characters. + + + OK + OK + + + Cancel + Cancel + + + Type old password + Enter old password + + + Type new password + Enter new password + + + Retype new password + Confirm new password + + + Warning + Warning + + + Old password incorrect. +Please try again. + Old password error. Please try again. + + + New password and confirm password are not matched. +Please make sure the two passwords are the same. + New password and confirm password do not match. + + + Password only allowed to use numbers, English and special characters. + Please make sure the two passwords are the same. + + + + Dialog_SaveAs + + Save As + Save as + + + Compression Option + Compression options + + + Use subfolder based on current date + Create a subfolder using the current date + + + Ocr type: + OCR type: + + + English + English + + + Simplified Chinese + Simplified Chinese + + + Traditional Chinese + Traditional Chinese + + + Japanese + Japanese + + + Korean + Korean + + + + Dialog_SaveMessageBox + + Dialog + Ask + + + Yes + Yes + + + No + No + + + save, do not remind again + Save and do not prompt again + + + modified, save it? + Image modified, save changes? + + + + Dialog_Source_Select + + Select source + Select source + + + OK + OK + + + Cancel + Cancel + + + tips + Tips + + + Load library failed + Load library failed + + + Find function failed + Find function failed + + + + Dialog_Twain_Source_Select + + Select source + Select source + + + OK + OK + + + Cancel + Cancel + + + + Dialog_WriteSettings + + Write Settings + Write into settings + + + Compression for black&white picture + Black and white image + + + None + None + + + LZW + LZW + + + CCITT G4 + CCITT G4 + + + Compression for color picture + Colored image + + + JPEG + JPEG + + + Quality + Quality + + + Lowest + Low + + + Best + High + + + + Dialog_device_select + + + Dialog + Select device + + + + Ok + OK + + + + Cancel + Cancel + + + + Dialog_progress_ui + + + Dialog + Scan status + + + + Cancel Scan + 取消扫描 + + + + Dialog_updateProgress + + Dialog + Downloading installation package... + + + stop + Stop + + + + Dialog_upgrade + + upgrade the latest version + Update to the latest version + + + upgrade online + Check for updates + + + The current version is the latest! The current version number is : + Currently the latest version! The version number is: + + + Discover the new version : + New version discovered: + + + ,the current version is : + , the current version is: + + + upgrade contents: + + Update content: + + + + + Dialog_upgradeFirmware + + upgrade + Update and upgrade + + + firmware upgrade in progress, please wait... + Device firmware currently updating; please wait... + + + + GraphicsScene + + SongTi + Song + + + + HGImgThumb + + tips + Prompt + + + unsupported file format + Drag and drop only supports jpg, bmp, png, pnm, tif/tiff, gif, pdf and ofd format + + + file have been loaded + File loaded! + + + file have been loaded, do you want to move to end? + File loaded; move it to the end? + + + file have been loaded, do you want to move to specified location? + File loaded; move it to the specified location? + + + Question + Ask + + + yes + Yes + + + no + No + + + some files have been loaded, do you want to move to end? + A file is loaded; move it to the end? + + + some files have been loaded, do you want to move to specified location? + A file is loaded; move it to the specified location? + + + + MainWindow + + MainWindow + HUAGOSCAN scanning software + + + menu_file + File + + + menu_scan + Scan + + + menu_view + View + + + menu_Auto_Image_Size + Automatic image size + + + menu_page + Page + + + menu_multiPages + Multiple pages + + + menu_image + Image + + + menuRotate + Rotate + + + menu_user + User + + + menu_info + Information + + + menu_device + Device + + + toolBar + Toolbar + + + act_open + Open... + + + act_insert + Insert local file... + + + act_save + Save + + + act_saveAs + Save as... + + + act_Export + Export... + + + act_closeFile + Close selected item + + + act_closeAll + Close all items + + + act_imageInfo + Image information... + + + act_exit + Exit + + + act_scannerSettings + Scan settings + + + act_acquire + Scan + + + act_acquireSingle + Scan single page + + + act_acquireInto + Scan to... + + + act_fullscreen + Fullscreen display + + + act_fitWindowSize + Fit view box size + + + act_fitWindowWidth + Fit view box width + + + act_realSize + Real size + + + act_zoomIn + Zoom in + + + act_zoomOut + Zoom out + + + act_toolBar + ToolBar + + + act_statusBar + Status bar + + + act_thumbnailBar + Thumbnail bar + + + act_colorInfo + Color information + + + act_previous + Previous + + + act_next + Next + + + act_first + First + + + act_last + Last + + + act_openPageNum + Jump to... + + + act_previousPage + Previous page + + + act_nextPage + Next page + + + act_firstPage + First page + + + act_lastPage + Last page + + + act_adjust + Brightness/ contrast/ gamma... + + + act_90Left + Rotate 90 degrees left + + + act_90Right + Rotate 90 degrees right + + + act_180 + Rotate 180 degrees + + + act_multiRotate + Rotate multiple pages... + + + act_autoCrop + Crop/ Deskew/ Remove black box... + + + act_signIn + Login... + + + act_passwordChange + Change password... + + + act_signOut + Logout + + + act_log + Log management... + + + act_clrCache + Cache settings... + + + act_consume + Consumable status... + + + act_help + Help + + + act_about + About... + + + act_insertFromScanner + Insert from scan... + + + act_clearRoller + Clear roller count + + + act_imageEdit + Image edit... + + + act_sortPages + Book sorting + + + act_autoSave + Auto save + + + act_update + Check for updates... + + + act_feedback + Opinions and feedback... + + + act_device_log + Export device log... + + + act_driver_log + Export drive log... + + + act_deleteFile + Delete selected item + + + HanvonScan + Hanvon scanning software + + + LanxumScan + LANXUM scanning software + + + CumtennScan + CUMTENN scanning software + + + MicrotekScan + Microtek DocWizard EX V1.0 + + + HuaGoScan + HUAGOSCAN scanning software + + + menu_language + Language + + + act_simpCN + 简体中文 + + + act_English + English + + + Grid + Multi-column display + + + Move To... + Move to... + + + Insert files + Insert file + + + nodevice + No scanner detected + + + auto save + Auto save + + + when switching pictures, save the edited pictures directly without reminding + Do not show prompt and save the edited images directly when switching images. + + + statusBar displayed + Show status bar + + + statusBar hidden + Hide status bar + + + toolBar displayed + Show toolbar + + + toolBar hidden + Hide toolbar + + + colorInfo enabled + Enable image information + + + colorInfo disenabled + Disable image information + + + enabling automatic saving + Enable auto save + + + cancel auto save + Cancel auto save + + + Automatically save the edited the edited iamge when switching pictures. To cancel, uncheck the menu item: image-> automatically save + Save edited images automatically when switching images. If you want to cancel, please deselect the menu item: Auto save images. + + + Question + Ask + + + modified, save it? + Image modified, save changes? + + + yes + Yes + + + save, do not remind again + Save, do not prompt again + + + no + No + + + file lost, remove it? + File lost; delete? + + + found device + Device discovered + + + found device : %1 + Device discovered: %1 + + + reconnected + reconnect + + + already connected, but open faild + connected, but failed to open + + + disconnected + disconnected + + + the disk space in the current path is unsufficient, please select a new path or clear the disk space in time. + Insufficient disk space for the current path. +Please reselect a path or clear disk space immediately. + + + warning + Warning + + + save image failed: + Failed to save image: + + + create savepath failed: + Failed to create folder: + + + create image doc failed: + Failed to create image file: + + + save image doc failed: + Failed to save image: + + + binary + Black and white + + + gray + Grayscale + + + rgb + Color + + + start failed + Failed to start + + + UniScan + UNI scanning software + + + default scheme + Default scheme + + + Please wake up the device manually + Please wake up the device manually + + + already waked up device + Device is awake + + + thumbnailBar enabled + Show thumbnail bar + + + thumbnailBar hidden + Hide thumbnail bar + + + Clear, then start scan + Clear and start scan + + + Do NOT clear, then start scan + Do not clear and start scan + + + cancel + Cancel + + + Already exist images in image list. +Do you want to clear? + Image already exists in the list of images. +Clear? + + + Open images + Open image + + + Insert images + Insert image + + + tips + prompt + + + save succeed + Saved successfully + + + find savePath in thumbnail + Image name already exists in the list + + + Please select at least one picture before export + Please select at least one image and then export + + + File name + File name + + + File path + File path + + + File size + File size + + + Creation date/time + Creation time + + + Modified date/time + Modification time + + + Accessed date/time + Access time + + + Format + Format + + + Width + Width + + + Height + Height + + + depth + Depth + + + Color model + Color mode + + + DPI + Pixels per inch + + + Print size + Print size + + + Frame + Frame + + + None + None + + + Mono + Black and white + + + Gray + Gray scale + + + Color + Color + + + Not supported + Not supported + + + Warning + Warning + + + Device is Running! +Please finish scanning first. + Device is currently running! +Please stop scanning first. + + + There are pictures that have not been saved. +Are you sure to close? + There are unsaved images; are you sure you want to close? + + + Are you sure to close? + Are you sure you want to close? + + + Sure to sign out administrator account? + Are you sure you want to log out of the administrator account? + + + confirm operation + Confirm operation + + + are you sure to clear the roller count? + Are you sure you want to clear the roller count? + + + hint + Prompt + + + Roller scanned count has been set to 0. + Roller count reset to zero. + + + Roller scanned count reset failed. + Failed to reset roller count. + + + Error + Error + + + Document missing! It would be deleted or renamed. + File lost! File may be deleted or renamed. + + + confirm the operation + Confirm operation + + + Are you sure to clear the rollor acount? + Are you sure you want to clear the roller count? + + + cache path folder limit:%1 + Unable to access the current path:%1 +Please try to log in to the administrator account in the [User] menu and go to the [Cache settings] to change the cache path. + + + aquireinto folder limit:%1 + Unable to access the current path:%1 +Please try to change the cache path in [Scan to]. + + + About %1 + About %1 + + + <p>%1</p><p>Version: %2<br>CopyRight: &#169; %3</p><p>%4%5%6%7%8%9</p> + <p>%1</p><p>Version: %2<br>Copyright: &#169; %3</p><p>%4%5%6%7%8%9</p> + + + about %1 + About %1 + + + <p>Version: %1</p> + <p>Version: %1</p> + + + <p>CopyRight: &#169; %1</p> + <p>Copyright: &#169; %1</p> + + + <p>%1: <a href='%2'>%3</a> + <p>%1: <a href='%2'>%3</a> + + + <p>%1: %2 + <p>%1: %2 + + + roller number + Number of rollers + + + open scanner + Open scanner + + + app name + HUAGOSCAN scanning software + + + success + successfully + + + be ready + Ready + + + failed + failed + + + error + Error + + + start failed! + Failed to start! + + + folder limit + Cannot access “My Documents”. +Please go to “Scan to” and change the accessible scan folder and then perform the scan. + + + Insufficient access rights + Insufficient file access permissions + + + Image processing failed + Image processing failed + + + Ocr init failed + OCR initialization error + + + Ocr failed + OCR failed + + + File does not exist + File does not exist + + + Failed to load dynamic library + Failed to load dynamic library + + + File data error + File data error + + + Image format processing error + Image format processing error + + + Out of memory + Insufficient memory + + + Failed + Failed + + + apply setting + Apply configuration + + + Are you sure to close + Are you sure you want to disconnect device: + + + ? + ? + + + close + Close + + + tip + Prompt + + + Other versions not available + No other versions obtained + + + The device does not support this operation + Device does not support this operation + + + IO error + IO error + + + The language switch is successful and takes effect the next time the software is started! + The language switch is successful and takes effect the next time the software is started! + + + Are you sure to delete selected file? + Are you sure to delete the selected file completely? + + + + QObject + + + default_setting + Default setting + + + &Save + &Save + + + + Widget + + + Widget + + + + + zuobiaozhou + Coordinate axis + + + + Widget_Imgproc_Base + + Brightness + Brightness + + + Contrast + Contrast + + + Gamma correction + Gamma correction + + + + Widget_StatusBar + + 0/0 + 0/0 + + + 0*0*0 + 0×0×0 + + + page + Page + + + size + Resolution + + + mousePos + Coordinates + + + zoom + Zoom + + + + cutDialog + + + cutDialog + + + + + device_menu + + + no device + No scanner detected + + + + default setting + Default settings + + + + dialog_log + + 日志 + Scan status information + + + cancel scan + Cancel scan + + + auto scroll + Auto scroll + + + clear + Clear information + + + export images + Export image + + + continue scan + Continue scanning + + + finish scan + Scan complete + + + (epicycle scanning images %u picture) + (A total of %u frames scanned this time) + + + + hg_settingdialog + + + existing configuration scheme + Existing configuration plan: + + + + change name + Rename + + + + delete + Delete + + + + apply + Apply + + + + delete all configurations + Delete all configurations + + + + confgiuration information: + Configuration information: + + + + scan + Scan + + + + + ok + OK + + + + cancel + Cancel + + + + configuration scheme management + Configuration plan management + + + + regional crop + Regional crop + + + + custom tone curve + Custom tone curve + + + + Please select to overwrite the original configuration: + Please select overwrite original configuration: + + + + ,or add a new configuration + , or add new configuration + + + + save the configuration + Save configuration + + + + cover original configuration: + Overwrite original configuration: + + + + add new configuration + Add new configuration + + + + rename: + Rename: + + + + + + tips + Prompt + + + + scheme name cannot be empty + Configuration name cannot be blank + + + + + scheme name: + Configuration name: + + + + + already exists + already exists + + + + <h6><b> + <h6><b> + + + + :</b></h6> + :</b></h6> + + + + <p> + <p> + + + + </p> + </p> + + + + configuration scheme name change + Rename configuration + + + + + be sure to delete the configuration + Delete configuration + + + + Are you sure you want to delete the configuration " + Are you sure you want to delete configuration + + + + " ? + ? + + + yes + Yes + + + no + No + + + + Are you sure you want to delete the configuration? + Are you sure you want to delete all configurations? + + + + setPicClrTool + + + 自定义色调曲线 + Custom tone curve + + + + 自定义 + Customize + + + + 负片(RGB) + Negative(RGB) + + + + 彩色负片(RGB) + Color negative(RGB) + + + + 较暗(RGB) + Darker(RGB) + + + + 较亮(RGB) + Brighter(RGB) + + + + RGB + RGB + + + + 灰 + Gray + + + + 红 + Red + + + + 蓝 + Blue + + + + 绿 + Green + + + + 初始化 + Initialize + + + + 输入: + Input: + + + + 输出: + OutPut: + + + diff --git a/modules/twainui/cfg/cJSON.c b/modules/twainui/cfg/cJSON.c new file mode 100644 index 00000000..f3dc5bcd --- /dev/null +++ b/modules/twainui/cfg/cJSON.c @@ -0,0 +1,756 @@ +/* + Copyright (c) 2009 Dave Gamble + + 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. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#include +#include +#include +#include +#include +#include +#include +#include "cJSON.h" + +static const char *ep; + +const char *cJSON_GetErrorPtr(void) {return ep;} + +static int cJSON_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} + +static void* ask_memory(size_t bytes) +{ +// printf("allocate %u bytes memory in cJSON\n", bytes); + + return malloc(bytes); +} +static void *(*cJSON_malloc)(size_t sz) = ask_memory; +static void (*cJSON_free)(void *ptr) = free; + +static char* cJSON_strdup(const char* str) +{ + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = (char*)cJSON_malloc(len))) return 0; + memcpy(copy,str,len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (!hooks) { /* Reset hooks */ + cJSON_malloc = ask_memory; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:ask_memory; + cJSON_free = (hooks->free_fn)?hooks->free_fn:free; +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(void) +{ + cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + if (node) memset(node,0,sizeof(cJSON)); + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_Delete(cJSON *c) +{ + cJSON *next; + while (c) + { + next=c->next; + if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); + if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); + cJSON_free(c); + c=next; + } +} + +/* Parse the input text to generate a number, and populate the result into item. */ +static const char *parse_number(cJSON *item,const char *num) +{ + double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; + + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ + } + + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ + + item->valuedouble=n; + item->valueint=(int)n; + item->type=cJSON_Number; + return num; +} + +static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } + +typedef struct {char *buffer; int length; int offset; } printbuffer; + +static char* ensure(printbuffer *p,int needed) +{ + char *newbuffer;int newsize; + if (!p || !p->buffer) return 0; + needed+=p->offset; + if (needed<=p->length) return p->buffer+p->offset; + + newsize=pow2gt(needed); + newbuffer=(char*)cJSON_malloc(newsize); + if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} + if (newbuffer) memcpy(newbuffer,p->buffer,p->length); + cJSON_free(p->buffer); + p->length=newsize; + p->buffer=newbuffer; + return newbuffer+p->offset; +} + +static int update(printbuffer *p) +{ + char *str; + if (!p || !p->buffer) return 0; + str=p->buffer+p->offset; + return p->offset+strlen(str); +} + +/* Render the number nicely from the given item into a string. */ +static char *print_number(cJSON *item,printbuffer *p) +{ + char *str=0; + double d=item->valuedouble; + if (d==0) + { + if (p) str=ensure(p,2); + else str=(char*)cJSON_malloc(2); /* special case for 0. */ + if (str) strcpy(str,"0"); + } + else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) + { + if (p) str=ensure(p,21); + else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ + if (str) sprintf(str,"%d",item->valueint); + } + else + { + if (p) str=ensure(p,64); + else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ + if (str) + { + if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } + } + return str; +} + +static unsigned parse_hex4(const char *str) +{ + unsigned h=0; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + return h; +} + +/* Parse the input text into an unescaped cstring, and populate item. */ +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; + if (*str!='\"') {ep=str;return 0;} /* not a string! */ + + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ + + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ + if (!out) return 0; + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && *ptr) + { + if (*ptr!='\\') *ptr2++=*ptr++; + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': /* transcode utf16 to utf8. */ + uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ + + if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ + { + if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ + uc2=parse_hex4(ptr+3);ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ + uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; + + switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static char *print_string_ptr(const char *str,printbuffer *p) +{ + const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; + + for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; + if (!flag) + { + len=ptr-str; + if (p) out=ensure(p,len+3); + else out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + ptr2=out;*ptr2++='\"'; + strcpy(ptr2,str); + ptr2[len]='\"'; + ptr2[len+1]=0; + return out; + } + + if (!str) + { + if (p) out=ensure(p,3); + else out=(char*)cJSON_malloc(3); + if (!out) return 0; + strcpy(out,"\"\""); + return out; + } + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} + + if (p) out=ensure(p,len+3); + else out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (token=*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +/* Invote print_string_ptr (which is useful) on an item. */ +static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} + +/* Predeclare these prototypes. */ +static const char *parse_value(cJSON *item,const char *value); +static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); +static const char *parse_array(cJSON *item,const char *value); +static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); +static const char *parse_object(cJSON *item,const char *value); +static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); + +/* Utility to jump whitespace and cr/lf */ +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} + +/* Parse an object - create a new root, and populate. */ +cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) +{ + const char *end=0; + cJSON *c=cJSON_New_Item(); + ep=0; + if (!c) return 0; /* memory fail */ + + end=parse_value(c,skip(value)); + if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} + if (return_parse_end) *return_parse_end=end; + return c; +} +/* Default options for cJSON_Parse */ +cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} + +/* Render a cJSON item/entity/structure to text. */ +char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} +char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} + +char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) +{ + printbuffer p; + p.buffer=(char*)cJSON_malloc(prebuffer); + p.length=prebuffer; + p.offset=0; + return print_value(item,0,fmt,&p); + return p.buffer; +} + + +/* Parser core - when encountering text, process appropriately. */ +static const char *parse_value(cJSON *item,const char *value) +{ + if (!value) return 0; /* Fail on null. */ + if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } + if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } + if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } + if (*value=='\"') { return parse_string(item,value); } + if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } + if (*value=='[') { return parse_array(item,value); } + if (*value=='{') { return parse_object(item,value); } + + ep=value;return 0; /* failure. */ +} + +/* Render a value to text. */ +static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char *out=0; + if (!item) return 0; + if (p) + { + switch ((item->type)&255) + { + case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} + case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} + case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} + case cJSON_Number: out=print_number(item,p);break; + case cJSON_String: out=print_string(item,p);break; + case cJSON_Array: out=print_array(item,depth,fmt,p);break; + case cJSON_Object: out=print_object(item,depth,fmt,p);break; + } + } + else + { + switch ((item->type)&255) + { + case cJSON_NULL: out=cJSON_strdup("null"); break; + case cJSON_False: out=cJSON_strdup("false");break; + case cJSON_True: out=cJSON_strdup("true"); break; + case cJSON_Number: out=print_number(item,0);break; + case cJSON_String: out=print_string(item,0);break; + case cJSON_Array: out=print_array(item,depth,fmt,0);break; + case cJSON_Object: out=print_object(item,depth,fmt,0);break; + } + } + return out; +} + +/* Build an array from input text. */ +static const char *parse_array(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='[') {ep=value;return 0;} /* not an array! */ + + item->type=cJSON_Array; + value=skip(value+1); + if (*value==']') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_value(child,skip(value+1))); + if (!value) return 0; /* memory fail */ + } + + if (*value==']') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an array to text */ +static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char **entries; + char *out=0,*ptr,*ret;int len=5; + cJSON *child=item->child; + int numentries=0,i=0,fail=0; + size_t tmplen=0; + + /* How many entries in the array? */ + while (child) numentries++,child=child->next; + /* Explicitly handle numentries==0 */ + if (!numentries) + { + if (p) out=ensure(p,3); + else out=(char*)cJSON_malloc(3); + if (out) strcpy(out,"[]"); + return out; + } + + if (p) + { + /* Compose the output array. */ + i=p->offset; + ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; + child=item->child; + while (child && !fail) + { + print_value(child,depth+1,fmt,p); + p->offset=update(p); + if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} + child=child->next; + } + ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; + out=(p->buffer)+i; + } + else + { + /* Allocate an array to hold the values for each */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + /* Retrieve all the results: */ + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt,0); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; + } + + /* If we didn't fail, try to ask_memory the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + /* If that fails, we fail. */ + if (!out) fail=1; + + /* Handle failure. */ + if (fail) + { + for (i=0;itype=cJSON_Object; + value=skip(value+1); + if (*value=='}') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; + value=skip(parse_string(child,skip(value))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_string(child,skip(value+1))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + } + + if (*value=='}') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an object to text. */ +static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) +{ + char **entries=0,**names=0; + char *out=0,*ptr,*ret,*str;int len=7,i=0,j; + cJSON *child=item->child; + int numentries=0,fail=0; + size_t tmplen=0; + /* Count the number of entries. */ + while (child) numentries++,child=child->next; + /* Explicitly handle empty object case */ + if (!numentries) + { + if (p) out=ensure(p,fmt?depth+4:3); + else out=(char*)cJSON_malloc(fmt?depth+4:3); + if (!out) return 0; + ptr=out;*ptr++='{'; + if (fmt) {*ptr++='\n';for (i=0;ioffset; + len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; + *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; + child=item->child;depth++; + while (child) + { + if (fmt) + { + ptr=ensure(p,depth); if (!ptr) return 0; + for (j=0;joffset+=depth; + } + print_string_ptr(child->string,p); + p->offset=update(p); + + len=fmt?2:1; + ptr=ensure(p,len); if (!ptr) return 0; + *ptr++=':';if (fmt) *ptr++='\t'; + p->offset+=len; + + print_value(child,depth,fmt,p); + p->offset=update(p); + + len=(fmt?1:0)+(child->next?1:0); + ptr=ensure(p,len+1); if (!ptr) return 0; + if (child->next) *ptr++=','; + if (fmt) *ptr++='\n';*ptr=0; + p->offset+=len; + child=child->next; + } + ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; + if (fmt) for (i=0;ibuffer)+i; + } + else + { + /* Allocate space for the names and the objects */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + names=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!names) {cJSON_free(entries);return 0;} + memset(entries,0,sizeof(char*)*numentries); + memset(names,0,sizeof(char*)*numentries); + + /* Collect all the results into our arrays: */ + child=item->child;depth++;if (fmt) len+=depth; + while (child) + { + names[i]=str=print_string_ptr(child->string,0); + entries[i++]=ret=print_value(child,depth,fmt,0); + if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; + child=child->next; + } + + /* Try to allocate the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + if (!out) fail=1; + + /* Handle failure */ + if (fail) + { + for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} +cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +/* Utility for handling references. */ +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} + +/* Add item to array/object. */ +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} +void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} + +cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; + if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} +void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} + +/* Replace array/object items with new ones. */ +void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} + newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} +void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} + +/* Create basic types: */ +cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} + +/* Create Arrays: */ +cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} + +/* Duplication */ +cJSON *cJSON_Duplicate(cJSON *item,int recurse) +{ + cJSON *newitem,*cptr,*nptr=0,*newchild; + /* Bail on bad ptr */ + if (!item) return 0; + /* Create new item */ + newitem=cJSON_New_Item(); + if (!newitem) return 0; + /* Copy over all vars */ + newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; + if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} + if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} + /* If non-recursive, then we're done! */ + if (!recurse) return newitem; + /* Walk the ->next chain for the child. */ + cptr=item->child; + while (cptr) + { + newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) {cJSON_Delete(newitem);return 0;} + if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ + cptr=cptr->next; + } + return newitem; +} + +void cJSON_Minify(char *json) +{ + char *into=json; + while (*json) + { + if (*json==' ') json++; + else if (*json=='\t') json++; /* Whitespace characters. */ + else if (*json=='\r') json++; + else if (*json=='\n') json++; + else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ + else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ + else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ + else *into++=*json++; /* All other characters. */ + } + *into=0; /* and null-terminate. */ +} diff --git a/modules/twainui/cfg/cJSON.h b/modules/twainui/cfg/cJSON.h new file mode 100644 index 00000000..58b91ef6 --- /dev/null +++ b/modules/twainui/cfg/cJSON.h @@ -0,0 +1,154 @@ +/* + Copyright (c) 2009 Dave Gamble + + 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 cJSON__h +#define cJSON__h +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* cJSON Types: */ +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + + +typedef void *(*malloc_fnxx)(size_t sz); +typedef void (*free_fnxx)(void *ptr); + +/* The cJSON structure: */ +typedef struct cJSON { + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int type; /* The type of the item, as above. */ + + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ + + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ +} cJSON; + +typedef struct cJSON_Hooks { + malloc_fnxx malloc_fn; + free_fnxx free_fn; +} cJSON_Hooks; + +/* Supply malloc, realloc and free functions to cJSON */ +extern void cJSON_InitHooks(cJSON_Hooks* hooks); + + +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ +extern cJSON *cJSON_Parse(const char *value); +/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ +extern char *cJSON_Print(cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ +extern char *cJSON_PrintUnformatted(cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); +/* Delete a cJSON entity and all subentities. */ +extern void cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +extern int cJSON_GetArraySize(cJSON *array); +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); +/* Get item "string" from object. Case insensitive. */ +extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +extern const char *cJSON_GetErrorPtr(void); + +/* These calls create a cJSON item of the appropriate type. */ +extern cJSON *cJSON_CreateNull(void); +extern cJSON *cJSON_CreateTrue(void); +extern cJSON *cJSON_CreateFalse(void); +extern cJSON *cJSON_CreateBool(int b); +extern cJSON *cJSON_CreateNumber(double num); +extern cJSON *cJSON_CreateString(const char *string); +extern cJSON *cJSON_CreateArray(void); +extern cJSON *cJSON_CreateObject(void); + +/* These utilities create an Array of count items. */ +extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); +extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); +extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); +extern cJSON *cJSON_CreateStringArray(const char **strings,int count); + +/* Append item to the specified array/object. */ +extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); +extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); +extern void cJSON_DeleteItemFromArray(cJSON *array,int which); +extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); +extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); + +/* Update array items. */ +extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ +extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); +extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ + +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); + +extern void cJSON_Minify(char *json); + +/* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) +#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/modules/twainui/cfg/gb_json.cpp b/modules/twainui/cfg/gb_json.cpp new file mode 100644 index 00000000..6b6e1de0 --- /dev/null +++ b/modules/twainui/cfg/gb_json.cpp @@ -0,0 +1,1879 @@ + +#include "gb_json.h" +#include +#include +#include + +#include "../../sdk/include/huagao/brand.h" + +#if defined(WIN32) || defined(_WIN64) +#define bzero(b, s) memset(b, 0, s) +#endif + + +namespace gb +{ + static std::vector split_with(const char* str, const char* splitor = "/") + { + std::vector ret; + std::string src(str); + size_t pos = src.find(splitor); + + while(pos != std::string::npos) + { + if(pos++) + ret.push_back(src.substr(0, pos - 1)); + src.erase(0, pos + strlen(splitor)); + pos = src.find(splitor); + } + if(src.length()) + ret.push_back(src); + + return ret; + } + static int load_mini_file(const char* file, std::string& cont) + { + FILE* src = fopen(file, "rb"); + if (src) + { + size_t size = 0; + char *buf = NULL; + + fseek(src, 0, SEEK_END); + size = ftell(src); + fseek(src, 0, SEEK_SET); + buf = new char[size + 4]; + memset(buf, 0, size + 4); + fread(buf, 1, size, src); + fclose(src); + cont = std::string(buf, size); + delete[] buf; + + return 0; + } + else + return errno; + } + + refer::refer() : ref_(1) + {} + refer::~refer() + {} + + long refer::add_ref(void) + { +#if defined(WIN32) || defined(_WIN64) + return InterlockedIncrement(&ref_); +#else + return ++ref_; +#endif + } + long refer::release(void) + { +#if defined(WIN32) || defined(_WIN64) + long ref = InterlockedDecrement(&ref_); +#else + long ref = --ref_; +#endif + + if (ref == 0) + delete this; + + return ref; + } + + + json::json(char* json_txt) : obj_(0), cur_child_(0), is_array_(false) + { + memset(&walk_head_, 0, sizeof(walk_head_)); + attach_text(json_txt); + } + json::~json() + { + memset(&walk_head_, 0, sizeof(walk_head_)); + clear(); + } + + std::string json::to_string(cJSON* root, bool formatted) + { + char* txt = formatted ? cJSON_Print(root) : cJSON_PrintUnformatted(root); + std::string ret(txt ? txt : ""); + + if (txt) + free(txt); + + return ret; + } + std::string json::get_value_as_string(cJSON* root, bool integer) + { + std::string ret(""); + + switch (root->type) + { + case cJSON_False: + ret = "false"; + break; + case cJSON_True: + ret = "true"; + break; + case cJSON_NULL: + ret = "null"; + break; + case cJSON_Number: + { + char buf[40]; + if (integer) + sprintf(buf, "%d", root->valueint); + else + sprintf(buf, "%f", root->valuedouble); + ret = buf; + } + break; + case cJSON_String: + if (root->valuestring) + ret = root->valuestring; + break; + default: + ret = json::to_string(root, false); + break; + } + + return ret; + } + void json::free_node_data(cJSON* node) + { + if (node->type == cJSON_String && node->valuestring) + free(node->valuestring); + else if((node->type == cJSON_Object || node->type == cJSON_Array) && node->child) + cJSON_Delete(node->child); + + node->type = cJSON_NULL; + node->valuestring = NULL; + node->child = NULL; + } + cJSON* json::create_element(bool is_array) + { + cJSON* obj = is_array ? cJSON_CreateArray() : cJSON_CreateObject(); + + // bzero(obj, sizeof(*obj)); // cleared in constructor already ! + + return obj; + } + cJSON* json::create_element_with_name(const char* name) + { + cJSON* obj = json::create_element(); + + if(name) + { + obj->string = (char*)malloc(strlen(name) + 4); + bzero(obj->string, strlen(name) + 4); + strcpy(obj->string, name); + } + + return obj; + } + + cJSON* json::find_sibling(cJSON* first, const char* name, cJSON*** prev) + { + cJSON* now = first, **prv = NULL; + while(now) + { + if(now->string && strcmp(now->string, name) == 0) + { + break; + } + prv = &now->next; + now = now->next; + } + if(prev) + *prev = prv; + + return now; + } + cJSON* json::find_child(cJSON *parent, std::vector& path, bool create, cJSON*** addr) + { + if(!parent->child) + { + if(!create) + return NULL; + + parent->child = json::create_element_with_name(path[0].c_str()); + if(path.size() == 1) + { + if(addr) + *addr = &parent->child; + + return parent->child; + } + } + + cJSON** prev = NULL, + *now = find_sibling(parent->child, path[0].c_str(), &prev); + if(!now) + { + if(!create) + return now; + + now = json::create_element_with_name(path[0].c_str()); + if (prev) + { + cJSON* pr = (cJSON*)((DWORD_PTR)prev - (DWORD_PTR)&((cJSON*)0)->next); + pr->next = now; + now->prev = pr; + // *prev = now; + } + else + { + obj_->child = now; + prev = &obj_->child; + } + } + + path.erase(path.begin()); + if(path.empty()) + { + if(addr) + *addr = prev ? prev : &parent->child; + + return now; + } + + return find_child(now, path, create, addr); + } + cJSON* json::find(const char* path, bool create, cJSON*** addr) + { + std::vector tree(split_with(path)); + + if(tree.empty()) + return NULL; + + if(!obj_) + { + if(!create) + return NULL; + + obj_ = json::create_element(); + obj_->child = json::create_element_with_name(tree[0].c_str()); + } + + return find_child(obj_, tree, create, addr); + } + + bool json::attach_text(char* json_txt) + { + clear(); + + obj_ = cJSON_Parse(json_txt); + if(obj_) + is_array_ = obj_->type == cJSON_Array; + + return obj_ != 0; + } + bool json::attach_cjson(cJSON* cjson) + { + clear(); + + if (cjson) + { + std::string txt(json::to_string(cjson, false)); + if (txt.length()) + obj_ = cJSON_Parse(txt.c_str()); + } + if(obj_) + is_array_ = obj_->type == cJSON_Array; + + return obj_ != 0; + } + bool json::create_empty(bool array) + { + clear(); + + obj_ = json::create_element(array); + is_array_ = array; + + return true; + } + void json::clear(void) + { + if (obj_) + { + cJSON_Delete(obj_); + obj_ = 0; + } + } + std::string json::to_string(bool formatted) + { + if (obj_) + return json::to_string(obj_, formatted); + else + return ""; + } + + bool json::get_value(const char* key, bool& val) + { + cJSON* obj = find(key); + + if (!obj) + return false; + + if (obj->type == cJSON_True) + val = true; + else if (obj->type == cJSON_False) + val = false; + else + return false; + + return true; + } + bool json::get_value(const char* key, int& val) + { + cJSON* obj = find(key); + + if (!obj) + return false; + + if (obj->type != cJSON_Number) + return false; + + val = obj->valueint; + + return true; + } + bool json::get_value(const char* key, double& val) + { + cJSON *obj = find(key); + + if (!obj) + return false; + + if (obj->type != cJSON_Number) + return false; + + val = obj->valuedouble; + + return true; + } + bool json::get_value(const char* key, std::string& val) + { + cJSON *obj = find(key); + + if (!obj) + return false; + + if (obj->type != cJSON_String) + return false; + + val = obj->valuestring ? obj->valuestring : ""; + + return true; + } + bool json::get_value(const char* key, json*& val) + { + cJSON *obj = find(key); + + if (!obj) + return false; + + val = new json(); + if (!val->attach_cjson(obj)) + { + val->release(); + + return false; + } + + return true; + } + bool json::get_value_as_string(const char* key, std::string& val, bool integer) + { + cJSON* obj = find(key); + + if (!obj) + return false; + + val = json::get_value_as_string(obj, integer); + + return true; + } + bool json::get_as_array(const char* key, std::vector& val) + { + cJSON *obj = find(key); + + val.clear(); + if (obj && obj->type == cJSON_Array) + { + cJSON *child = obj->child; + while (child) + { + if (child->type == cJSON_Number) + { + char buf[40]; + sprintf(buf, "%d", child->valueint); + val.push_back(buf); + } + else if (child->type == cJSON_String) + val.push_back(child->valuestring ? child->valuestring : ""); + else + { + char *text = cJSON_Print(child); + val.push_back(text); + free(text); + } + + child = child->next; + } + + return true; + } + + return false; + } + + int json::count() + { + if(!obj_ || !obj_->child) + return 0; + + cJSON* child = obj_->child; + int cnt = 0; + + while(child) + { + cnt++; + child = child->next; + } + + return cnt; + } + + + bool json::first_child(std::string& val, std::string* name) + { + cur_child_ = obj_->child; + val = ""; + if (cur_child_) + { + val = json::get_value_as_string(cur_child_); + if (name && cur_child_->string) + *name = cur_child_->string; + + return true; + } + else + { + return false; + } + } + bool json::next_child(std::string& val, std::string* name) + { + if (cur_child_) + cur_child_ = cur_child_->next; + + val = ""; + if (cur_child_) + { + val = json::get_value_as_string(cur_child_); + if (name && cur_child_->string) + *name = cur_child_->string; + + return true; + } + else + { + return false; + } + } + + bool json::set_value(const char* key, bool val) + { + if(!key) + { + if(is_array_) + { + if(!obj_) + obj_ = json::create_element(true); + cJSON_AddItemToArray(obj_, val ? cJSON_CreateTrue() : cJSON_CreateFalse()); + } + + return is_array_; + } + + cJSON* ele = this->find(key, true); + + if (!ele) + return false; + + json::free_node_data(ele); + + if (val) + ele->type = cJSON_True; + else + ele->type = cJSON_False; + + return true; + } + bool json::set_value(const char* key, int val) + { + if(!key) + { + if(is_array_) + { + if(!obj_) + obj_ = json::create_element(true); + cJSON_AddItemToArray(obj_, cJSON_CreateNumber(val)); + } + + return is_array_; + } + + cJSON* ele = this->find(key, true); + + if (!ele) + return false; + + json::free_node_data(ele); + + ele->type = cJSON_Number; + ele->valuedouble = ele->valueint = val; + + return true; + } + bool json::set_value(const char* key, double val) + { + if(!key) + { + if(is_array_) + { + if(!obj_) + obj_ = json::create_element(true); + cJSON_AddItemToArray(obj_, cJSON_CreateNumber(val)); + } + + return is_array_; + } + + cJSON* ele = this->find(key, true); + + if (!ele) + return false; + + json::free_node_data(ele); + + ele->type = cJSON_Number; + ele->valuedouble = val; + + return true; + } + bool json::set_value(const char* key, std::string val) + { + if(!key) + { + if(is_array_) + { + if(!obj_) + obj_ = json::create_element(true); + cJSON_AddItemToArray(obj_, cJSON_CreateString(val.c_str())); + } + + return is_array_; + } + + cJSON* ele = this->find(key, true); + + if (!ele) + return false; + + json::free_node_data(ele); + + ele->type = cJSON_String; + ele->valuestring = (char*)malloc(val.length() + 4); + bzero(ele->valuestring, val.length() + 4); + strcpy(ele->valuestring, val.c_str()); + + return true; + } + bool json::set_value(const char* key, const char* val) + { + return set_value(key, std::string(val)); + } + bool json::set_value(const char* key, json* obj) + { + if(!key) + { + if(is_array_) + { + if(!obj_) + obj_ = json::create_element(true); + if(obj && obj->obj_) + { + cJSON_AddItemToArray(obj_, obj->obj_); + obj->obj_ = NULL; + } + } + + return is_array_; + } + + cJSON** addr = NULL; + cJSON* ele = this->find(key, true, &addr); + + if (!ele) + return false; + +// json::free_node_data(ele); + cJSON_Delete(ele); + *addr = obj->obj_; + ele = obj->obj_; + if(ele->string) + free(ele->string); + ele->string = (char*)malloc(strlen(key) + 4); + bzero(ele->string, strlen(key) + 4); + strcpy(ele->string, key); + obj->obj_ = NULL; + + return true; + } + + bool json::change_key(const char* old_key, const char* new_key) + { + if (!obj_ || !new_key || *new_key == 0 || !old_key || *old_key == 0) + return false; + + cJSON** addr = NULL, + *ele = find(old_key, false, &addr); + + if (!ele) + return false; + + if (strlen(ele->string) < strlen(new_key)) + { + int l = strlen(new_key) + 4; + free(ele->string); + ele->string = (char*)malloc(l); + memset(ele->string, 0, l); + } + strcpy(ele->string, new_key); + + return true; + } + bool json::remove(const char* key) + { + if(!obj_) + return false; + + cJSON **addr = NULL, + *ele = find(key, false, &addr); + + if(ele) + { + bool cur_child = cur_child_ == obj_->child; + + if(addr) + *addr = ele->next; + if (cur_child_ == ele) + { + if (cur_child) + { + walk_head_.next = obj_->child; + cur_child_ = &walk_head_; + } + else + cur_child_ = ele->prev; + } + if (ele->prev) + ele->prev->next = ele->next; + if (ele->next) + ele->next->prev = ele->prev; + ele->prev = NULL; + ele->next = NULL; + cJSON_Delete(ele); + + return true; + } + else + return false; + } +} + + + +namespace gb +{ + static char base64_default_table[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" }; + + base64::base64() : padding_char_('=') + { + base64_ind_[0] = base64_char_[0] = 0; + + initialize_base64_table(base64_default_table); + } + base64::~base64() + {} + + bool base64::is_valid_base64_table(const char* table) + { + bool valid = false; + + if (table && strlen(table) >= 64) + { + char repeat[4] = { 0 }; + + valid = true; + for (int i = 0; i < 63; ++i) + { + repeat[0] = table[i]; + if (strstr(table + i + 1, repeat)) + { + valid = false; + break; + } + } + } + + return valid; + } + bool base64::initialize_base64_table(const char* table) + { + if (!table || strlen(table) < 64) + { + if (memcmp(base64_default_table, base64_char_, 64) == 0) + { + return !table; + } + + memcpy(base64_char_, base64_default_table, 64); + } + else + { + if (memcmp(base64_char_, table, 64) == 0) + { + return true; + } + else if (!is_valid_base64_table(table)) + return false; + + memcpy(base64_char_, table, 64); + } + base64_char_[64] = base64_char_[65] = 0; + + // initialize base64_index + memset(base64_ind_, 0, sizeof(base64_ind_)); + for (int i = 0; i < 64; ++i) + { + base64_ind_[base64_char_[i]] = i; + } + + // padding char + padding_char_ = '='; + if (base64_ind_[padding_char_]) + { + for (padding_char_ = 0x21; padding_char_ < 0x7e && base64_ind_[padding_char_] && padding_char_ != base64_char_[0]; ++padding_char_); + } + + return padding_char_ < 0x7e; + } + + bool base64::set_base64_table(const char* table) + { + return initialize_base64_table(table ? table : base64_default_table); + } + std::string base64::encode(const char* data, size_t bytes, unsigned int line_bytes, bool need_padding) + { + char* str = (char*)malloc(bytes * 2 + 3); + unsigned char c1 = 0, c2 = 0, c3 = 0; + unsigned long line_len = 0; + unsigned long words = bytes / 3; + int rest = bytes % 3, + pos = 0; + std::string ret(""); + + for (unsigned long i = 0; i < words; ++i) + { + // fetch 3 letters + c1 = *data++; + c2 = *data++; + c3 = *data++; + + // encoding into 4-bytes + str[pos++] = base64_char_[c1 >> 2]; + str[pos++] = base64_char_[((c1 << 4) | (c2 >> 4)) & 0x3f]; + str[pos++] = base64_char_[((c2 << 2) | (c3 >> 6)) & 0x3f]; + str[pos++] = base64_char_[c3 & 0x3f]; + line_len += 4; + + // new line ... + if ((unsigned int)line_len > line_bytes - 4) + { + str[pos++] = '\r'; + str[pos++] = '\n'; + line_len = 0; + } + } + + // rest ... + if (rest == 1) + { + c1 = *data++; + str[pos++] = base64_char_[(c1 & 0xfc) >> 2]; + str[pos++] = base64_char_[((c1 & 0x03) << 4)]; + if (need_padding) + { + str[pos++] = padding_char_; + str[pos++] = padding_char_; + } + } + else if (rest == 2) + { + c1 = *data++; + c2 = *data++; + str[pos++] = base64_char_[(c1 & 0xfc) >> 2]; + str[pos++] = base64_char_[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)]; + str[pos++] = base64_char_[((c2 & 0x0f) << 2)]; + if (need_padding) + { + str[pos++] = padding_char_; + } + } + if (pos > 0) + { + str[pos++] = 0; + ret = std::string(str, pos - 1); + } + free(str); + + return ret; + } + std::string base64::decode(const char* data, size_t bytes) + { + char* str = (char*)malloc(bytes + 1); + int pos = 0, + shifts = 18, + value = 0; + std::string ret(""); + + for (int i = 0; i < (int)bytes; ++i) + { + if (*data != '\r' && *data != '\n') + { + if (*data == padding_char_) + { + break; + } + + value += base64_ind_[*data] << shifts; + if (shifts == 0) + { + shifts = 18; + str[pos++] = (value >> 16) & 0x0ff; + str[pos++] = (value >> 8) & 0x0ff; + str[pos++] = (value >> 0) & 0x0ff; + value = 0; + } + else + { + shifts -= 6; + } + } + data++; + } + + if (shifts == 12 || shifts == 6) + { + str[pos++] = (value >> 16) & 0x0ff; + } + else if (shifts == 0) + { + str[pos++] = (value >> 16) & 0x0ff; + str[pos++] = (value >> 8) & 0x0ff; + } + + if (pos > 0) + { + str[pos++] = 0; + ret = std::string(str, pos - 1); + } + free(str); + + return ret; + } +} + +namespace updater +{ + static std::string hg_model_from_pid(const char* pid) + { + if (strcmp(pid, "7823") == 0) + return "G200"; + + char m[] = { 'G', pid[0], '0', '0', 0}; + + return std::string(m) + " - " + pid; + } + static std::string hv_model_from_pid(const char* pid) + { + std::string m(""); + if (strcmp(pid, "1000") == 0) + m = "HW-1000NS"; + else if (strcmp(pid, "1002") == 0) + m = "HW-1000"; + else if (strcmp(pid, "7000") == 0) + m = "HW-7000NS"; + else if (strcmp(pid, "7002") == 0) + m = "HW-7000"; + else if (strcmp(pid, "7039") == 0) + m = "HW-7000NS"; + else + m = std::string("HW-") + pid; + + return m + " - " + pid; + } + static std::string lsc_model_from_pid(const char* pid) + { + if (strcmp(pid, "8200") == 0) + return "G42S - 8200"; + else + { + char m[] = {'G', pid[1], pid[2], 'S', 0}; + + return std::string(m) + " - " + pid; + } + } + static std::string scanner_chinese_name_2_model(const char* cn) + { + static const char* hg = "\345\215\216\351\253\230", + * hw = "\346\261\211\347\216\213", + * lsc = "\347\253\213\346\200\235\350\276\260", + * smy = "\346\211\253\346\217\217\344\273\252\342\200\224G", + * f = strstr(cn, hg); + std::string model(""); + std::string(* model_from_pid)(const char* pid) = nullptr; + + if (f == cn) + { + model = "HUAGOSCAN "; + model_from_pid = hg_model_from_pid;; + } + else if (strstr(cn, hw) == cn) + { + model = "Hanvon "; + model_from_pid = hv_model_from_pid;; + } + else if (strstr(cn, lsc) == cn) + { + model = "LANXUMSCAN "; + model_from_pid = lsc_model_from_pid;; + } + else + return ""; + + f = strstr(cn, smy); + if (!f) + return ""; + + f += strlen(smy); + model += model_from_pid(f); + + return model; + } + static int update_app_config(const char* scanner_name, const char* jsn_txt, const char* path, gb::scanner_cfg::LPUDF lpfunc) + { + std::string scanner(""), jsn_str(jsn_txt); + std::vector efiles; + + if ((unsigned char)scanner_name[0] > 0x7f) + scanner = scanner_chinese_name_2_model(scanner_name); + else + scanner = scanner_name; + + gb::json* jsn = new gb::json(); + int cur_sel = -1, ret = 0; + gb::scanner_cfg* cfg = nullptr; + if (!jsn->attach_text(&jsn_str[0])) + { + jsn->release(); + return EINVAL; + } + + if (jsn->first_child(jsn_str)) + { + gb::json* child = new gb::json(); + if (child->attach_text(&jsn_str[0])) + { + if (!child->get_value("cur_sel", cur_sel)) + ret = EINVAL; + } + if (ret == 0) + { + cfg = new gb::scanner_cfg(); + int ind = 0; + while (jsn->next_child(jsn_str)) + { + if (!child->attach_text(&jsn_str[0])) + { + ret = EINVAL; + break; + } + + std::string schm_name(""); + if (!child->get_value("scheme", schm_name)) + { + ret = EINVAL; + break; + } + + gb::json* items = nullptr; + if (!child->get_value("opts", items) || !items) + { + ret = EINVAL; + break; + } + + gb::sane_config_schm* schm = new gb::sane_config_schm(); + if (items->first_child(jsn_str)) + { + do + { + std::string name(""), val(""); + gb::json* item = new gb::json(); + if (item->attach_text(&jsn_str[0])) + { + if (item->get_value("name", name) && item->get_value("value", val)) + { + name = lpfunc->title2name(name.c_str(), lpfunc->func_param); + lpfunc->trans_number(name.c_str(), val, lpfunc->func_param); + schm->set_value(name.c_str(), val.c_str(), val.length()); + + val = ""; + item->get_value("extra", val); + if (val.length() && gb::load_mini_file(val.c_str(), val) == 0) + { + schm->set_value(name.c_str(), val.c_str(), val.length(), true); + item->get_value("extra", val); + efiles.push_back(val); + } + } + } + item->release(); + } while (items->next_child(jsn_str)); + } + items->release(); + + cfg->add_scheme(schm, schm_name.c_str()); + schm->release(); + if (ind++ == cur_sel) + cfg->select_scheme(schm_name.c_str()); + } + } + child->release(); + } + jsn->release(); + if (cfg) + { + if (ret == 0) + { + cfg->save((path + scanner + ".cfg").c_str()); + for (auto& v : efiles) + rename(v.c_str(), (v + "_bk").c_str()); + } + cfg->release(); + } + + return ret; + } +} +namespace gb +{ + std::string sane_config_schm::opt_data_appendix_("_data"); + + sane_config_schm::sane_config_schm(scanner_cfg* scanner) : jsn_(NULL), bkp_(NULL), in_setting_(false), scheme_name_("") + , scanner_(scanner) + { + char empty[8] = { "{}" }; + jsn_ = new gb::json(); + jsn_->attach_text(empty); + def_val_ = new gb::json(); + if (scanner_) + scanner_->add_ref(); + } + sane_config_schm::~sane_config_schm() + { + clear(); + def_val_->release(); + if (scanner_) + scanner_->release(); + } + + bool sane_config_schm::hex(unsigned char ch, unsigned char* val) + { + bool ret = true; + + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if (ch >= 'a' && ch <= 'f') + ch = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + ch = ch - 'A' + 10; + else + ret = false; + + if (ret && val) + { + *val &= 0x0f0; + *val |= ch; + } + + return ret; + } + bool sane_config_schm::hex_char(const char* data, unsigned char* val) + { + unsigned char v = 0; + bool ret = false; + + if (sane_config_schm::hex(*data++, &v)) + { + v <<= 4; + if (sane_config_schm::hex(*data++, &v)) + { + if (val) + *val = v; + + ret = true; + } + } + + return ret; + } + bool sane_config_schm::is_option_data(std::string& name) + { + size_t pos = name.find(sane_config_schm::opt_data_appendix_); + + if (pos != std::string::npos) + { + if (pos + sane_config_schm::opt_data_appendix_.length() == name.length()) + { + name.erase(pos); + + return true; + } + } + + return false; + } + + void sane_config_schm::clear() + { + if (jsn_) + jsn_->release(); + jsn_ = NULL; + if (bkp_) + bkp_->release(); + bkp_ = NULL; + // file_ = ""; + } + std::string sane_config_schm::to_hex_letter(const char* data, size_t bytes) + { + std::string hex(""); + const unsigned char* ptr = (const unsigned char*)data; + char buf[8] = { 0 }; + + for (size_t i = 0; i < bytes; ++i) + { + sprintf(buf, "%02X", ptr[i]); + hex += buf; + } + + return hex; + } + std::string sane_config_schm::from_hex_letter(const char* data, size_t bytes) + { + std::string stream(""); + + bytes /= 2; + for (size_t i = 0; i < bytes; ++i) + { + unsigned char ch = 0; + if (!sane_config_schm::hex_char(data, &ch)) + break; + stream.append(1, ch); + data += 2; + } + + return stream; + } + std::string sane_config_schm::default_value(const char* hex_title) + { + std::string val(""); + + def_val_->get_value(hex_title, val); + + return val; + } + + sane_config_schm* sane_config_schm::copy(void) + { + sane_config_schm *cp = new sane_config_schm(scanner_); + std::string val(jsn_->to_string(false)); + + cp->scheme_name_ = scheme_name_; + cp->file_ = file_; + cp->jsn_->attach_text(&val[0]); + cp->id_name_ = id_name_; + val = def_val_->to_string(false); + cp->def_val_->attach_text(&val[0]); + + return cp; + } + bool sane_config_schm::load_from_file(const char* file) + { + clear(); + + std::string cont(""); + + file_ = file; + if (gb::load_mini_file(file, cont)) + return false; + + return load_from_mem(cont.c_str()); + } + bool sane_config_schm::load_from_mem(const char* mem, bool in_b64) + { + gb::base64 b64; + std::string stream(in_b64 ? b64.decode(mem, strlen(mem)) : mem); + + clear(); + jsn_ = new gb::json(); + if (!jsn_->attach_text(&stream[0])) + { + jsn_->release(); + jsn_ = NULL; + + return false; + } + + return true; + } + bool sane_config_schm::save_to(const char* file) + { + bool ret = false; + std::string encode(to_text_stream()); + + if (!file || *file == 0) + file = file_.c_str(); + + if (encode.length()) + { + FILE* dst = fopen(file, "wb"); + + if (dst) + { + fwrite(encode.c_str(), 1, encode.length(), dst); + fclose(dst); + ret = true; + } + } + + return ret; + } + void sane_config_schm::set_default_value(int sn, const char* name, const char* val, size_t bytes) + { + id_name_[sn] = name; + def_val_->set_value(name, to_hex_letter(val, bytes).c_str()); + } + void sane_config_schm::copy_default_value(sane_config_schm* from) + { + if(from) + { + std::string t(from->def_val_->to_string(false)); + + id_name_ = from->id_name_; + def_val_->attach_text(&t[0]); + } + } + bool sane_config_schm::first_config(std::string& name, std::string& val) + { + bool ret = false; + std::string raw_v(""); + + if (jsn_ && jsn_->first_child(raw_v, &name)) + { + val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length()); + + ret = true; + } + + return ret; + } + bool sane_config_schm::next_config(std::string& name, std::string& val) + { + bool ret = false; + std::string raw_v(""); + + if (jsn_ && jsn_->next_child(raw_v, &name)) + { + val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length()); + + ret = true; + } + + return ret; + } + bool sane_config_schm::get_config(const char* name, std::string& val) + { + bool ret = jsn_ ? jsn_->get_value(name, val) : false; + + if(!ret && def_val_) + ret = def_val_->get_value(name, val); + + if(ret) + val = sane_config_schm::from_hex_letter(val.c_str(), val.length()); + + return ret; + } + void sane_config_schm::begin_setting(bool restore) + { + if (bkp_) + bkp_->release(); + bkp_ = jsn_; + in_setting_ = true; + jsn_ = new gb::json(); + if (!restore && bkp_) + { + std::string stream(bkp_->to_string(false)); + if(stream.length()) + jsn_->attach_text(&stream[0]); + } + } + void sane_config_schm::config_changed(const char* name, const char* val, size_t bytes, bool extra) + { + std::string hex_v(to_hex_letter(val, bytes)); + + if (extra) + { + jsn_->set_value((name + sane_config_schm::opt_data_appendix_).c_str(), hex_v.c_str()); + } + else + { + std::string def = default_value(name); + if (hex_v == def) + { + jsn_->remove(name); + jsn_->remove((name + sane_config_schm::opt_data_appendix_).c_str()); + } + else + jsn_->set_value(name, hex_v.c_str()); + } + } + void sane_config_schm::config_changed(int sn, const char* val, size_t bytes, bool extra) + { + std::string name(""); + + if (id_name_.count(sn)) + { + name = id_name_[sn]; + config_changed(name.c_str(), val, bytes, extra); + } + } + void sane_config_schm::remove_config(const char* name) + { + if (jsn_) + jsn_->remove(name); + } + void sane_config_schm::set_value(const char* name, const char* val, size_t bytes, bool extra) + { + std::string hex_v(to_hex_letter(val, bytes)); + + if (extra) + jsn_->set_value((name + sane_config_schm::opt_data_appendix_).c_str(), hex_v.c_str()); + else + jsn_->set_value(name, hex_v.c_str()); + } + bool sane_config_schm::has_changed(int* items) + { + if(items) + *items = jsn_ ? jsn_->count() : 0; + + if(!bkp_) + { + return false; + } + + std::map old; + std::string n(""), v(""); + if(bkp_->first_child(v, &n)) + { + do + { + old[n] = v; + }while(bkp_->next_child(v, &n)); + } + + if(jsn_->first_child(v, &n)) + { + do + { + if(old.count(n) == 0) + return true; + if(old[n]!=v) + return true; + + old.erase(n); + }while(jsn_->next_child(v, &n)); + } + + return old.size() > 0; + } + void sane_config_schm::end_setting(bool cancel) + { + if (in_setting_) + { + if (cancel) + { + jsn_->release(); + jsn_ = bkp_; + bkp_ = NULL; + } + else if (bkp_) + { + bkp_->release(); + bkp_ = NULL; + } + } + in_setting_ = false; + } + int sane_config_schm::id_from_name(const char* name) + { + for (const auto& v : id_name_) + { + if (v.second == name) + return v.first; + } + + return -1; + } + std::string sane_config_schm::to_text_stream(bool b64, bool with_ver) + { + if (jsn_) + { + if(with_ver) + { + char ver[40] = { 0 }; + sprintf(ver, "%u.%u", VERSION_MAIN, VERSION_SUB); + jsn_->set_value("ver", ver); + } + + std::string cont(jsn_->to_string(false)); + if (b64) + { + gb::base64 b64; + + cont = b64.encode(cont.c_str(), cont.length()); + } + + return cont; + } + else + return ""; + } + std::string sane_config_schm::get_version(void) + { + std::string ver(""); + + if (jsn_) + jsn_->get_value("ver", ver); + + return ver; + } + std::string sane_config_schm::get_scheme_name(void) + { + return scheme_name_; + } + void sane_config_schm::set_scheme_name(const char* name) + { + scheme_name_ = name ? name : ""; + } + void sane_config_schm::update(bool(* is_float)(int, void*), void* param, const char* (* t2n)(const char*), std::string* discard) + { + if (!jsn_) + return; + + std::string ver(get_version()), + name(""), + val(""); + int mv = atoi(ver.c_str()), + sv = ver.find("."); + bool changed = false; + char vs[40] = { 0 }; + + if (sv++ != -1) + sv = atoi(ver.c_str() + sv); + + // change title to name ... + if (mv <= 4 && sv < 30) + { + if (jsn_->first_child(val, &name)) + { + changed = true; + do + { + jsn_->change_key(name.c_str(), t2n(sane_config_schm::from_hex_letter(name.c_str(), name.length()).c_str())); + } while (jsn_->next_child(val, &name)); + } + } + + // fix float does not convert to SANE_Fixed bug in eldest version .... (discard them) + if (ver.empty()) + { + if (jsn_->first_child(val, &name)) + { + do + { + int id = id_from_name(name.c_str()); + if (id == -1 || is_float(id, param)) + { + jsn_->remove(name.c_str()); + if (discard) + *discard += name + "\r\n"; + changed = true; + } + } while (jsn_->next_child(val, &name)); + } + } + sprintf(vs, "%u.%u", VERSION_MAIN, VERSION_SUB); + jsn_->set_value("ver", vs); + + if (changed) + save_to(NULL); + } + + + + + /////////////////////////////////////////////////////////////////////////////////// + // scanner_cfg + std::string scanner_cfg::global_name_ = "global"; + std::string scanner_cfg::cur_sel_ = "cur"; + std::string scanner_cfg::default_setting_name_; + + scanner_cfg::scanner_cfg() : path_(""), scanner_name_(""), global_(new json()) + { + default_setting_name_ = QObject::tr("default_setting").toStdString(); + init_version(); + init_select(); + } + scanner_cfg::~scanner_cfg() + { + clear(); + global_->release(); + } + + bool scanner_cfg::update(const char* file, LPUDF func) + { + std::string cont(""), name(""), path(file); + int ret = gb::load_mini_file(file, cont); + base64 b64; + json *jsn = nullptr; + bool ok = true; + + if (ret) + return false; + else if (cont.empty()) + return true; + + cont = b64.decode(cont.c_str(), cont.length()); + jsn = new json(); + if (!jsn->attach_text(&cont[0])) + { + jsn->release(); + return false; + } + + cont = ""; + ret = path.rfind(PATH_SYMBOL[0]); + if (ret++ != std::string::npos) + path.erase(ret); + if (jsn->first_child(cont, &name)) + { + do + { + ok &= updater::update_app_config(name.c_str(), cont.c_str(), path.c_str(), func) == 0; + } while (jsn->next_child(cont, &name)); + } + jsn->release(); + if (ok) + rename(file, (std::string(file) + "_bk").c_str()); + + return true; + } + + void scanner_cfg::clear(void) + { + global_->set_value("ver", ""); + global_->set_value(scanner_cfg::cur_sel_.c_str(), -1); + + for (size_t i = 0; i < schemes_.size(); ++i) + schemes_[i].schm->release(); + schemes_.clear(); + scanner_name_ = ""; + } + void scanner_cfg::init_version(void) + { + char vstr[40] = { 0 }; + + sprintf(vstr, "%u.%u", VERSION_MAIN, VERSION_SUB); + global_->set_value("ver", vstr); + } + void scanner_cfg::init_select(void) + { + global_->set_value(scanner_cfg::cur_sel_.c_str(), -1); + } + void scanner_cfg::walk_sibling_schemes(cJSON* first) + { + if (!first) + return; + + cJSON* next = first->next; + std::string name(first->string ? first->string : ""), + cont(""); + CFGSCHM sch; + + first->next = nullptr; + cont = json::to_string(first, false); + if (name == scanner_cfg::global_name_) + { + global_->attach_text(&cont[0]); + } + else + { + sch.schm = new sane_config_schm(); + if (sch.schm->load_from_mem(cont.c_str(), false)) + { + sch.name = sane_config_schm::from_hex_letter(name.c_str(), name.length()); + sch.schm->set_scheme_name(sch.name.c_str()); + schemes_.push_back(sch); + } + else + sch.schm->release(); + } + + first->next = next; + walk_sibling_schemes(next); + } + + int scanner_cfg::load_file(const char* file) + { + std::string cont(""); + int ret = gb::load_mini_file(file, cont); + + if (ret == 0) + ret = load_mem(cont.c_str()); + + // if (ret == 0 && scanner_name_.empty()) + { + const char* name = strrchr(file, PATH_SYMBOL[0]); + if (name++ == nullptr) + name = file; + else + path_ = std::string(file, name - file); + + scanner_name_ = name; + ret = scanner_name_.rfind('.'); + if (ret != std::string::npos) + scanner_name_.erase(ret); + ret = 0; + } + + return ret; + } + int scanner_cfg::load_mem(const char* mem) + { + base64 b64; + std::string text(b64.decode(mem, strlen(mem))); + cJSON* root = cJSON_Parse(text.c_str()); + + if (!root) + { + FILE* dst = fopen((path_ + "err_cfg.txt").c_str(), "wb"); + fwrite(text.c_str(), 1, text.length(), dst); + fclose(dst); + return EINVAL; + } + + clear(); + walk_sibling_schemes(root->child); + cJSON_Delete(root); + + return 0; + } + int scanner_cfg::save(const char* file) + { + if (!file && path_.empty() && scanner_name_.empty()) + return EINVAL; + + std::string cont("{\"" + scanner_cfg::global_name_ + "\":"), + f(file ? file : path_ + scanner_name_ + ".cfg"), + v(""); + int sel = -1; + + if (!global_->get_value("ver", v) || v.empty()) + init_version(); + if (!global_->get_value(scanner_cfg::cur_sel_.c_str(), sel) || sel >= schemes_.size()) + init_select(); + + cont += global_->to_string(false); + for (auto& v: schemes_) + { + cont += ",\"" + sane_config_schm::to_hex_letter(v.name.c_str(), v.name.length()) + "\":"; + cont += v.schm->to_text_stream(false, false); + } + cont += "}"; + + base64 b64; + FILE* dst = fopen(f.c_str(), "wb"); + + if (!dst) + return errno; + + f = b64.encode(cont.c_str(), cont.length()); + fwrite(f.c_str(), 1, f.length(), dst); + fclose(dst); + + return 0; + } + + void scanner_cfg::get_all_schemes(std::vector& schemes) + { + schemes.push_back(scanner_cfg::default_setting_name_); + for (auto& v : schemes_) + schemes.push_back(v.name); + } + sane_config_schm* scanner_cfg::get_scheme(const char* scheme_name) + { + sane_config_schm* found = nullptr; + + if (scheme_name && *scheme_name) + { + std::vector::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name); + if (it != schemes_.end()) + found = it->schm; + } + else + { + int ind = -1; + + global_->get_value(scanner_cfg::cur_sel_.c_str(), ind); + if (ind >= 0 && ind < schemes_.size()) + found = schemes_[ind].schm; + } + + if (found) + found->add_ref(); + + return found; + } + std::string scanner_cfg::get_current_scheme_name(void) + { + int ind = -1; + + global_->get_value(scanner_cfg::cur_sel_.c_str(), ind); + if (ind >= 0 && ind < schemes_.size()) + return schemes_[ind].name; + else + return scanner_cfg::default_setting_name_; + } + bool scanner_cfg::remove_scheme(const char* scheme_name) + { + std::vector::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name); + + if (it != schemes_.end()) + { + int id = it - schemes_.begin(), + ind = -1; + + it->schm->release(); + schemes_.erase(it); + global_->get_value(scanner_cfg::cur_sel_.c_str(), ind); + if (ind == id) + global_->set_value(scanner_cfg::cur_sel_.c_str(), -1); + else if (ind > id) + global_->set_value(scanner_cfg::cur_sel_.c_str(), ind - 1); + + return true; + } + + return false; + } + void scanner_cfg::remove_all_schemes(void) + { + for(auto& v: schemes_) + v.schm->release(); + + schemes_.clear(); + } + bool scanner_cfg::select_scheme(const char* scheme_name) + { + std::vector::iterator it = scheme_name ? std::find(schemes_.begin(), schemes_.end(), scheme_name) : schemes_.end(); + + if (it == schemes_.end()) + global_->set_value(scanner_cfg::cur_sel_.c_str(), -1); + else + global_->set_value(scanner_cfg::cur_sel_.c_str(), (int)(it - schemes_.begin())); + + return true; + } + + sane_config_schm* scanner_cfg::copy_scheme(const char* cp_from_name) // for UI setting, call release() if not use anymore + { + if (!cp_from_name) + return nullptr; + else if (scanner_cfg::default_setting_name_ == cp_from_name) + return new sane_config_schm(); + else + { + std::vector::iterator it = std::find(schemes_.begin(), schemes_.end(), cp_from_name); + if (it == schemes_.end()) + return nullptr; + + std::string cont(it->schm->to_text_stream()); + sane_config_schm* schm = new sane_config_schm(); + schm->load_from_mem(cont.c_str()); + + return schm; + } + } + bool scanner_cfg::add_scheme(sane_config_schm* schm, const char* name) + { + CFGSCHM cs; + + cs.name = name ? name : schm->get_scheme_name(); + if(cs.name.empty() || cs.name == scanner_cfg::global_name_) + return false; + + if (std::find(schemes_.begin(), schemes_.end(), cs.name.c_str()) != schemes_.end()) + return false; + + cs.schm = schm; + + schemes_.push_back(cs); + schm->set_scheme_name(cs.name.c_str()); + schm->add_ref(); + + return true; + } + bool scanner_cfg::rename_scheme(const char* from, const char* to) + { + if (to && std::find(schemes_.begin(), schemes_.end(), to) != schemes_.end()) + return false; + + for(auto& v: schemes_) + { + if(v.name == from) + { + v.name = to; + v.schm->set_scheme_name(to); + return true; + } + } + + return false; + } +} diff --git a/modules/twainui/cfg/gb_json.h b/modules/twainui/cfg/gb_json.h new file mode 100644 index 00000000..ffc79d94 --- /dev/null +++ b/modules/twainui/cfg/gb_json.h @@ -0,0 +1,233 @@ +#pragma once + +#if defined(WIN32) || defined(_WIN64) +#include +#define PATH_SYMBOL "\\" +#else +#define PATH_SYMBOL "/" +#define NULL nullptr +#define DWORD_PTR char* +#define _countof(a) sizeof(a) / sizeof(a[0]) +#endif + +#include "cJSON.h" +//#include "../../code_device/hgsane/cJSON.h" +#include +#include +#include +#include + +namespace gb +{ + class scanner_cfg; + class refer + { + volatile long ref_; + + protected: + refer(); + virtual ~refer(); + + public: + long add_ref(void); + long release(void); + }; + + + class json : public refer + { + cJSON *obj_; + cJSON *cur_child_; + cJSON walk_head_; + bool is_array_; + + cJSON* find_sibling(cJSON* first, const char* name, cJSON*** addr); + cJSON* find_child(cJSON *parent, std::vector& path, bool create, cJSON*** addr = NULL); + cJSON* find(const char* path, bool create = false, cJSON*** addr = NULL); + + protected: + ~json(); + + public: + json(char* json_txt = 0); + + static std::string to_string(cJSON* root, bool formatted); + static std::string get_value_as_string(cJSON* root, bool integer = false); + static void free_node_data(cJSON* node); + static cJSON* create_element(bool is_array = false); + static cJSON* create_element_with_name(const char* name); + + public: + bool attach_text(char* json_txt); + bool attach_cjson(cJSON* cjson); + bool create_empty(bool array = false); + void clear(void); + std::string to_string(bool formatted); + + // can be path: child/value ... + bool get_value(const char* key, bool& val); + bool get_value(const char* key, int& val); + bool get_value(const char* key, double& val); + bool get_value(const char* key, std::string& val); + bool get_value(const char* key, json*& val); // caller shoud call "delete" to free the returned object !!! + bool get_value_as_string(const char* key, std::string& val, bool integer); + bool get_as_array(const char* key, std::vector& val); + + int count(void); + bool first_child(std::string& val, std::string* name = NULL); + bool next_child(std::string& val, std::string* name = NULL); + + bool set_value(const char* key, bool val); + bool set_value(const char* key, int val); + bool set_value(const char* key, double val); + bool set_value(const char* key, std::string val); + bool set_value(const char* key, const char* val); + bool set_value(const char* key, json* obj); + + bool change_key(const char* old_key, const char* new_key); + bool remove(const char* key); + }; + + class base64 + { + char base64_ind_[128]; + char base64_char_[80]; + char padding_char_; + + bool is_valid_base64_table(const char* table); + bool initialize_base64_table(const char* table); + + public: + base64(); + ~base64(); + + public: + bool set_base64_table(const char* table = NULL); + std::string encode(const char* data, size_t bytes, unsigned int line_bytes = -1, bool need_padding = true); + std::string decode(const char* data, size_t bytes); + }; + + class sane_config_schm : public refer + { + std::string scheme_name_; + scanner_cfg *scanner_; + std::string file_; + json* jsn_; + json* bkp_; + json* def_val_; + bool in_setting_; + std::map id_name_; // (id, default-val) + + void clear(); + std::string default_value(const char* name); + + protected: + ~sane_config_schm(); + + public: + sane_config_schm(scanner_cfg* scanner = nullptr); + + static std::string opt_data_appendix_; + static bool hex(unsigned char ch, unsigned char* val); + static bool hex_char(const char* data, unsigned char* val); + static std::string to_hex_letter(const char* data, size_t bytes); + static std::string from_hex_letter(const char* data, size_t bytes); + static bool is_option_data(std::string& name); // reset baase option name into 'name' if name was option data, and return true + + public: + sane_config_schm* copy(void); + bool load_from_file(const char* file); + bool load_from_mem(const char* mem, bool in_b64 = true); + bool save_to(const char* file); + void set_default_value(int sn, const char* name, const char* val, size_t bytes); + void copy_default_value(sane_config_schm* from); + bool first_config(std::string& name, std::string& val); + bool next_config(std::string& name, std::string& val); + bool get_config(const char* name, std::string& val); + void begin_setting(bool restore = false); + void config_changed(const char* name, const char* val, size_t bytes, bool extra = false); + void config_changed(int sn, const char* val, size_t bytes, bool extra = false); + void remove_config(const char* name); + void set_value(const char* name, const char* val, size_t bytes, bool extra = false); + bool has_changed(int* items = nullptr); + void end_setting(bool cancel); + int id_from_name(const char* name); + std::string to_text_stream(bool b64 = true, bool with_ver = true); + std::string get_version(void); + std::string get_scheme_name(void); + void set_scheme_name(const char* name); + void update(bool(* is_float)(int, void*), void* param, const char*(* t2n)(const char*), std::string* discard = NULL); + }; + + class scanner_cfg : public refer + { + // format: in base64 + // + // { + // "global": { + // "ver": "4.33", + // "cur": -1 + // }, + // "scheme_1": sane_config_schm*, + // "scheme_2": sane_config_schm*, + // "scheme_3": sane_config_schm*, + // ... + // } + // + std::string path_; + std::string scanner_name_; // scanner type: HUAGOSCAN G100 - 0100 + json *global_; // version, current scheme, ... + + typedef struct _cfg_schm + { + std::string name; + sane_config_schm* schm; + + bool operator==(const char* n) + { + return name == n; + } + }CFGSCHM; + std::vector schemes_; + + static std::string global_name_; + static std::string cur_sel_; + static std::string default_setting_name_; + + void clear(void); + void init_version(void); + void init_select(void); + void walk_sibling_schemes(cJSON* first); + + protected: + ~scanner_cfg(); + + public: + scanner_cfg(); + + typedef struct _update_func + { + void(* trans_number)(const char* name, std::string& val, void* param); + const char* (* title2name)(const char* title, void* param); + std::string discard_msg; // update failed items ... + void* func_param; + }UDF, *LPUDF; + static bool update(const char* file, LPUDF func); + + public: + int load_file(const char* file); + int load_mem(const char* mem); + int save(const char* file = nullptr); + + void get_all_schemes(std::vector& schemes); // return all schemes name queue, the first is always be 'Default settings' + sane_config_schm* get_scheme(const char* scheme_name = nullptr/*return current scheme if was null*/); // call sane_config_schm::release() if not use anymore + std::string get_current_scheme_name(void); + bool remove_scheme(const char* scheme_name); + void remove_all_schemes(void); + bool select_scheme(const char* scheme_name); + + sane_config_schm* copy_scheme(const char* cp_from_name); // for UI setting, call release() if not use anymore + bool add_scheme(sane_config_schm* schm, const char* name = nullptr); + bool rename_scheme(const char* from, const char* to); + }; +}; diff --git a/modules/twainui/cutdialog.cpp b/modules/twainui/cutdialog.cpp new file mode 100644 index 00000000..ff701baa --- /dev/null +++ b/modules/twainui/cutdialog.cpp @@ -0,0 +1,464 @@ +#include "cutdialog.h" +#include "ui_cutdialog.h" +#include +#include +#include +#include "HGString.h" +#include "sane/sane_option_definitions.h" + +cutDialog::cutDialog(QWidget *parent) : + QWidget(parent), + ui(new Ui::cutDialog) +{ + ui->setupUi(this); + divisor = 8; + dpi = 1; + sizeType = 0; + paperWidth = 185; + h_w = 260.0/185.0; + sizeRate = 1; + paperHeight = paperWidth*h_w; + + this->setFixedSize(paperWidth,paperHeight); + setMouseTracking(true); + m_startPoint = QPoint(10,10); + m_endPoint = QPoint(50,50); + m_mouse_down = false; + + initAllCorner(); +} + +cutDialog::~cutDialog() +{ + delete ui; +} + +void cutDialog::setPaperSize(QString type, const int w) +{ + paperType = type; + + if (paperType == OPTION_VALUE_ZZCC_A3) h_w = 420.0 / 297.0; + else if (paperType == OPTION_VALUE_ZZCC_8K) h_w = 390.0 / 270.0; + else if (paperType == OPTION_VALUE_ZZCC_16K) h_w = 270.0 / 190.0; + else if (paperType == OPTION_VALUE_ZZCC_16KHX) h_w = 190.0 / 270.0; + else if (paperType == OPTION_VALUE_ZZCC_A4) h_w = 297.0 / 210.0; + else if (paperType == OPTION_VALUE_ZZCC_A4HX) h_w = 210.0 / 297.0; + else if (paperType == OPTION_VALUE_ZZCC_A5) h_w = 210.0 / 148.0; + else if (paperType == OPTION_VALUE_ZZCC_A5HX) h_w = 148.0 / 210.0; + else if (paperType == OPTION_VALUE_ZZCC_A6) h_w = 148.0 / 105.0; + else if (paperType == OPTION_VALUE_ZZCC_A6HX) h_w = 105.0 / 148.0; + else if (paperType == OPTION_VALUE_ZZCC_B4) h_w = 353.0 / 250.0; + else if (paperType == OPTION_VALUE_ZZCC_B5) h_w = 250.0 / 176.0; + else if (paperType == OPTION_VALUE_ZZCC_B5HX) h_w = 176.0 / 250.0; + else if (paperType == OPTION_VALUE_ZZCC_B6) h_w = 176.0 / 125.0; + else if (paperType == OPTION_VALUE_ZZCC_B6HX) h_w = 125.0 / 176.0; + else if (paperType == OPTION_VALUE_ZZCC_Letter) h_w = 279.0 / 216.0; + else if (paperType == OPTION_VALUE_ZZCC_LetterHX) h_w = 216.0 / 279.0; + else if (paperType == OPTION_VALUE_ZZCC_DoubleLetter) h_w = 559.0 / 216.0; + else if (paperType == OPTION_VALUE_ZZCC_LEGAL) h_w = 356.0 / 216.0; + else if (paperType == OPTION_VALUE_ZZCC_SLSJ) h_w = 560.0 / 270.0; + else if(paperType == OPTION_VALUE_ZZCC_ZDSMCC) h_w = 3307.0*2/2338; + else if(paperType == OPTION_VALUE_ZZCC_PPYSCC) { + if(dpi == 100.0) h_w = 1795.0/1189; + if(dpi == 150.0) h_w = 1795.0/1784; + if(dpi == 200.0) h_w = 3307.0/2338; + if(dpi == 240.0) h_w = 4308.0/2854; + if(dpi == 200.0) h_w = 5385.0/3567; + }; + + + if(type.contains("3")) divisor = 2; + else if (type.contains("4")) divisor = 4; + else if (type.contains("5")) divisor = 6; + else if (type.contains("6")) divisor = 8; + else divisor = 4; + paperWidth = w; + if(type.contains(StdStringToUtf8("横向").c_str())) + paperWidth = paperWidth*h_w*1.5; + double realW = paperWidth; + + if (paperType == OPTION_VALUE_ZZCC_A3 || paperType == OPTION_VALUE_ZZCC_A4HX) realRate = 297.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_A4 || paperType == OPTION_VALUE_ZZCC_A5HX) realRate = 210.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_A5 || paperType == OPTION_VALUE_ZZCC_A6HX) realRate = 148.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_A6) realRate = 105.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_16K) realRate = 190.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_8K || paperType == OPTION_VALUE_ZZCC_16KHX) realRate = 270.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_B4 || paperType == OPTION_VALUE_ZZCC_B5HX) realRate = 250.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_B5 || paperType == OPTION_VALUE_ZZCC_B6HX) realRate = 176.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_B6) realRate = 125.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_Letter) realRate = 216.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_LetterHX) realRate = 279.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_DoubleLetter) realRate = 216.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_LEGAL) realRate = 216.0 / realW; + else if (paperType == OPTION_VALUE_ZZCC_SLSJ) realRate = 270.0 / realW; + else if(paperType == OPTION_VALUE_ZZCC_ZDSMCC) realRate = 297.0/realW; + else if(paperType == OPTION_VALUE_ZZCC_PPYSCC) { + if(dpi == 100.0) realRate = 1189.0*0.039377/dpi/realW; + if(dpi == 150.0) realRate = 1784*0.039377/dpi/realW; + if(dpi == 200.0) realRate = 2338*0.039377/dpi/realW; + if(dpi == 240.0) realRate = 2854*0.039377/dpi/realW; + if(dpi == 200.0) realRate = 3567*0.039377/dpi/realW; + }; + + paperHeight = paperWidth*h_w; + this->setFixedSize(paperWidth+4,paperHeight+4); + scaleRec = QRectF(0,0,paperWidth,paperHeight+0.5); + m_rect = QRectF(m_startPoint,m_endPoint); + update(); + refreshView(); +} + +void cutDialog::setDpiValue(const double d) +{ + dpi = d; + if(sizeType == PIXEL) sizeRate = 0.03937*dpi; + update(); +} + +void cutDialog::setSizeType(const SIZETYPE &t) +{ + sizeType = t; + switch (sizeType) { + case MILLIM: + sizeRate = 1; + break; + case INCH: + sizeRate = 0.03937; + break; + case PIXEL: + sizeRate = 0.03937*dpi; + break; + } + update(); +} + +void cutDialog::setCutRectWidth(double w) +{ + m_endPoint.setX(m_startPoint.x()+scaleRec.width()*w/getPaperSize().width()); + update(); +} + +void cutDialog::setCutRectHeight(double h) +{ + m_endPoint.setY(m_startPoint.y()+scaleRec.height()*h/getPaperSize().height()); + update(); +} + +void cutDialog::setCutRectStartX(double x) +{ + m_startPoint.setX(scaleRec.width()*x/getPaperSize().width()); + update(); +} + +void cutDialog::setCutRectStartY(double y) +{ + m_startPoint.setY(scaleRec.height()*y/getPaperSize().height()); + update(); +} + +QSizeF cutDialog::getPaperSize() const +{ + double realW = paperWidth*realRate*sizeRate; + double realH = paperHeight*realRate*sizeRate; + return QSizeF(realW,realH); +} + +QSizeF cutDialog::getCutRectSize() const +{ + double realCutW = getPaperSize().width()*m_rect.width()/scaleRec.width(); + double realCutH = getPaperSize().height()*m_rect.height()/scaleRec.height(); + return QSizeF(realCutW,realCutH); +} + +QPointF cutDialog::getCutRectStartPos() const +{ + double realCutX = getPaperSize().width()*m_startPoint.x()/scaleRec.width(); + double realCutY = getPaperSize().height()*m_startPoint.y()/scaleRec.height(); + return QPointF(realCutX,realCutY); +} + +QRectF cutDialog::getCutRectPixel() const +{ + double x = 0.03937*dpi*paperWidth*realRate*m_startPoint.x()/scaleRec.width(); + double y = 0.03937*dpi*paperHeight*realRate*m_startPoint.y()/scaleRec.height(); + double w = 0.03937*dpi*paperWidth*realRate*m_rect.width()/scaleRec.width(); + double h = 0.03937*dpi*paperHeight*realRate*m_rect.height()/scaleRec.height(); + return QRectF(x,y,w,h); +} + +void cutDialog::setCutRectPixel(QRectF &rect) +{ + m_startPoint.setX(scaleRec.width()*rect.x()/(paperWidth*realRate*0.03937*dpi)); + m_startPoint.setY(scaleRec.height()*rect.y()/(paperHeight*realRate*0.03937*dpi)); + m_endPoint.setX(m_startPoint.x()+scaleRec.width()*rect.width()/(paperWidth*realRate*0.03937*dpi)); + m_endPoint.setY(m_startPoint.y()+scaleRec.height()*rect.height()/(paperHeight*realRate*0.03937*dpi)); + update(); +} + +int cutDialog::getCutRectRight() const +{ + return getPaperSize().width()*m_rect.right()/scaleRec.right(); +} + +int cutDialog::getCutRectBottom() const +{ + return getPaperSize().height()*m_rect.bottom()/scaleRec.bottom(); +} + +void cutDialog::mousePressEvent(QMouseEvent *event) +{ + int x = event->x()/**paperWidth/width()*/; + int y = event->y()/**paperHeight/height()*/; + m_moveStart = QPoint(x,y); + m_mouse_down = event->button() == Qt::LeftButton; + update(); +} + +void cutDialog::mouseMoveEvent(QMouseEvent *event) +{ + int x = event->x()/**paperWidth/width()*/; + int y = event->y()/**paperHeight/height()*/; + if(m_mouse_down){ + int dx = m_moveStart.x() - x; + int dy = m_moveStart.y() - y; + m_moveStart = QPoint(x,y); + + if(m_leftCorn){ + m_startPoint.setX(x); + }else if(m_rightCorn){ + m_endPoint.setX(x); + }else if(m_topCorn){ + m_startPoint.setY(y); + }else if(m_bottomCorn){ + m_endPoint.setY(y); + }else if(m_leftTop){ + m_startPoint.setX(x); + m_startPoint.setY(y); + }else if(m_leftBottom){ + m_startPoint.setX(x); + m_endPoint.setY(y); + }else if(m_rightTop){ + m_startPoint.setY(y); + m_endPoint.setX(x); + }else if(m_rightBottom){ + m_endPoint.setX(x); + m_endPoint.setY(y); + } + else if(!m_out){ + if(m_startPoint.x() - dx < 0) dx = 0; + if(m_startPoint.y() - dy < 0) dy = 0; + if(m_endPoint.x() - dx > scaleRec.right()) dx = 0; + if(m_endPoint.y() - dy > scaleRec.bottom()) dy = 0; + m_startPoint.setX(m_rect.left()-dx); + m_startPoint.setY(m_rect.top()-dy); + m_endPoint.setX(m_rect.right()-dx); + m_endPoint.setY(m_rect.bottom()-dy); + } + if(m_startPoint.x()<=0) m_startPoint.setX(0); + if(m_startPoint.y()<=0) m_startPoint.setY(0); + if(m_endPoint.x()>=scaleRec.width()) m_endPoint.setX(scaleRec.right()); + if(m_endPoint.y()>=scaleRec.height()) m_endPoint.setY(scaleRec.bottom()); + + + if(qAbs(m_startPoint.x() - m_endPoint.x()) <= 10 || m_startPoint.x() > m_endPoint.x()){ + m_startPoint.setX(m_rect.left()); + m_endPoint.setX(m_rect.right()); + } + if(qAbs(m_startPoint.y() - m_endPoint.y()) <= 10 || m_startPoint.y() > m_endPoint.y()){ + m_startPoint.setY(m_rect.top()); + m_endPoint.setY(m_rect.bottom()); + } + + update(); + }else{ + mousePosition(QPoint(x,y)); + } +} + +void cutDialog::mouseReleaseEvent(QMouseEvent *) +{ + m_mouse_down = false; + update(); +} + +void cutDialog::enterEvent(QEvent *) +{ + emit lineEditEnable(false); +} + +void cutDialog::leaveEvent(QEvent *) +{ + emit lineEditEnable(true); +} + +void cutDialog::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.translate(0,0); + + drawScale(painter); + drawCutRect(painter); + drawTransparentColor(painter); + if(m_mouse_down){ + if(sizeType == INCH || sizeType == MILLIM){ + emit cutRectX(QString::number(getCutRectStartPos().x(),'f',2).toDouble()); + emit cutRectY(QString::number(getCutRectStartPos().y(),'f',2).toDouble()); + emit cutRectWidth(QString::number(getCutRectSize().width(),'f',2).toDouble()); + emit cutRectHeight(QString::number(getCutRectSize().height(),'f',2).toDouble()); + }else{ + emit cutRectX(double(int(getCutRectStartPos().x()))); + emit cutRectY(double(int(getCutRectStartPos().y()))); + emit cutRectWidth(double(int(getCutRectSize().width()))); + emit cutRectHeight(double(int(getCutRectSize().height()))); + } + } + + painter.end(); +} + +void cutDialog::drawScale(QPainter& painter) +{ + painter.setPen(QPen(Qt::black,1)); + scaleRec = QRectF(0,0,paperWidth,paperHeight+0.5); + painter.drawRect(scaleRec); + for(int i = 6 ; i <= paperWidth-6; i++){ + if(int(paperWidth/2) == i || int(paperWidth/4) == i || int(paperWidth*3/4) == i){ + painter.setPen(QPen(Qt::gray,1)); + painter.drawLine(i,0,i,paperHeight); + painter.setPen(QPen(Qt::black,1)); + } + if(i%divisor == 0){ + painter.drawLine(i,paperHeight-4,i,paperHeight); + painter.drawLine(i,0,i,4); + } + if(i%(divisor*5) == 0){ + painter.drawLine(i,paperHeight-8,i,paperHeight); + painter.drawLine(i,0,i,8); + } + } + for(int i = 6 ; i <= paperHeight-6; i++){ + if(int(paperHeight/2) == i || int(paperHeight/4) == i || int(paperHeight*3/4) == i){ + painter.setPen(QPen(Qt::gray,1)); + painter.drawLine(0,i,paperWidth,i); + painter.setPen(QPen(Qt::black,1)); + } + if(i%divisor == 0){ + painter.drawLine(0,i,4,i); + painter.drawLine(paperWidth,i,paperWidth-4,i); + } + if(i%(divisor*5) == 0){ + painter.drawLine(0,i,8,i); + painter.drawLine(paperWidth,i,paperWidth-8,i); + } + } +} + +void cutDialog::drawCutRect(QPainter &painter) +{ + painter.setPen(QPen(Qt::green,1)); + m_rect = QRectF(m_startPoint,m_endPoint); + + QRectF r(m_rect); + if(r.right() + 6 > paperWidth) + r.setRight(paperWidth - 6); + if(r.bottom() + 2 > paperHeight) + r.setBottom(paperHeight - 2); + + painter.drawRect(r); + painter.setPen(QPen(Qt::red,1)); + painter.setBrush(Qt::red); + painter.drawEllipse(r.left()-2,(r.bottom()-r.top())/2+r.top()-2,4,4); + painter.drawEllipse(r.left()-2,r.top()-2,4,4); + painter.drawEllipse(r.left()-2,r.bottom()-2,4,4); + painter.drawEllipse(r.right()-2,r.top()-2,4,4); + painter.drawEllipse(r.right()-2,r.bottom()-2,4,4); + painter.drawEllipse(r.right()-2,(r.bottom()-r.top())/2+r.top()-2,4,4); + painter.drawEllipse((r.right()-r.left())/2+r.left()-2,r.top()-2,4,4); + painter.drawEllipse((r.right()-r.left())/2+r.left()-2,r.bottom()-2,4,4); +} + +void cutDialog::drawTransparentColor(QPainter &painter) +{ + QPainterPath painterPath; + QPainterPath p; + p.addRect(scaleRec); + painterPath.addRect(m_rect); + QPainterPath drawPath =p.subtracted(painterPath); + painter.setOpacity(0.7); + painter.fillPath(drawPath,QBrush(Qt::gray)); +} + +void cutDialog::mousePosition(const QPoint& e) +{ + initAllCorner(); + QRectF r = QRectF(m_rect); + int x = e.x(); + int y = e.y(); + m_left = qAbs(x - r.left()) < 5; + m_right = qAbs(x - r.right()) < 5; + m_bottom = qAbs(y - r.bottom()) < 5; + m_top = qAbs(y - r.top()) < 5; + m_out = r.left()-x>=5 || x-r.right()>=5 || r.top()-y>=5 || y-r.bottom()>=5; + bool lorr = m_left | m_right; + bool torb = m_top | m_bottom; + if(lorr && torb) + { + if((m_left && m_top) || (m_right && m_bottom)) + setCursor(Qt::SizeFDiagCursor); + else + setCursor(Qt::SizeBDiagCursor); + } + else if(lorr) + setCursor(Qt::SizeHorCursor); + else if(torb) + setCursor(Qt::SizeVerCursor); + else if(!m_out) + { + setCursor(Qt::SizeAllCursor); + m_bottom = m_left = m_right = m_top = false; + }else if(m_out){ + setCursor(Qt::ArrowCursor); + m_bottom = m_left = m_right = m_top = false; + } + + if(m_left && m_top) m_leftTop = true; + else if(m_left && m_bottom) m_leftBottom = true; + else if(m_right && m_top) m_rightTop = true; + else if(m_right && m_bottom) m_rightBottom = true; + else if(m_left && !m_top && !m_bottom) m_leftCorn = true; + else if(m_right && !m_top && !m_bottom) m_rightCorn = true; + else if(m_top && !m_left && !m_right) m_topCorn = true; + else if(m_bottom && !m_left && !m_right) m_bottomCorn = true; + else initAllCorner(); +} + +void cutDialog::refreshView() +{ + if(sizeType == INCH){ + emit cutRectX(QString::number(getCutRectStartPos().x(),'f',2).toDouble()); + emit cutRectY(QString::number(getCutRectStartPos().y(),'f',2).toDouble()); + emit cutRectWidth(QString::number(getCutRectSize().width(),'f',2).toDouble()); + emit cutRectHeight(QString::number(getCutRectSize().height(),'f',2).toDouble()); + }else{ + emit cutRectX(QString::number(getCutRectStartPos().x(),'f',0).toDouble()); + emit cutRectY(QString::number(getCutRectStartPos().y(),'f',0).toDouble()); + emit cutRectWidth(double(int(getCutRectSize().width()))); + emit cutRectHeight(double(int(getCutRectSize().height()))); + } +} + +void cutDialog::initAllCorner() +{ + m_left = false; + m_right = false; + m_bottom = false; + m_top = false; + m_leftCorn = false; + m_rightCorn = false; + m_topCorn = false; + m_bottomCorn = false; + m_leftTop = false; + m_leftBottom = false; + m_rightTop = false; + m_rightBottom = false; +} diff --git a/modules/twainui/cutdialog.h b/modules/twainui/cutdialog.h new file mode 100644 index 00000000..2f77ef2a --- /dev/null +++ b/modules/twainui/cutdialog.h @@ -0,0 +1,100 @@ +#ifndef CUTDIALOG_H +#define CUTDIALOG_H + +#include +#include +#include +#include + +namespace Ui { +class cutDialog; +} + +enum SIZETYPE{ + MILLIM , + INCH, + PIXEL +}; + +class cutDialog : public QWidget +{ + Q_OBJECT + +public: + explicit cutDialog(QWidget *parent = nullptr); + ~cutDialog(); + void setPaperSize(QString type = "A1", const int w = 200); + void setDpiValue(const double d); + void setSizeType(const SIZETYPE& t); + void setCutRectWidth(double w); + void setCutRectHeight(double h); + void setCutRectStartX(double x); + void setCutRectStartY(double y); + QSizeF getPaperSize()const; + QSizeF getCutRectSize()const; + QPointF getCutRectStartPos()const; + QRectF getCutRectPixel()const; + void setCutRectPixel(QRectF& rect); + int getCutRectRight()const; + int getCutRectBottom()const; + void refreshView(); + +signals: + void cutRectX(double x); + void cutRectY(double y); + void cutRectWidth(double w); + void cutRectHeight(double h); + void lineEditEnable(bool b); + +private: + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void enterEvent(QEvent*); + void leaveEvent(QEvent*); + //void resizeEvent(QResizeEvent*); + void paintEvent(QPaintEvent *); + void drawScale(QPainter &painter); + void drawCutRect(QPainter &painter); + void drawTransparentColor(QPainter &painter); + void drawPaperSize(); + void mousePosition(const QPoint &e); + void initAllCorner(); + //void mouseChangeRect(int dx,int dy); + +private: + Ui::cutDialog *ui; + QPointF m_startPoint; + QPointF m_endPoint; + QPointF m_moveStart; + + QRectF m_rect; + QRectF scaleRec; + + QString paperType; + double paperWidth; + double paperHeight; + int divisor; + int sizeType; + double dpi; + double h_w; + double realRate; + double sizeRate; + + bool m_mouse_down; + bool m_left; + bool m_right; + bool m_bottom; + bool m_top; + bool m_leftCorn; + bool m_rightCorn; + bool m_topCorn; + bool m_bottomCorn; + bool m_leftTop; + bool m_rightTop; + bool m_leftBottom; + bool m_rightBottom; + bool m_out; +}; + +#endif // CUTDIALOG_H diff --git a/modules/twainui/cutdialog.ui b/modules/twainui/cutdialog.ui new file mode 100644 index 00000000..de03c34e --- /dev/null +++ b/modules/twainui/cutdialog.ui @@ -0,0 +1,44 @@ + + + cutDialog + + + true + + + + 0 + 0 + 321 + 342 + + + + + 0 + 0 + + + + + 2 + 0 + + + + + 2 + 0 + + + + true + + + cutDialog + + + + + + diff --git a/modules/twainui/cutpapertool.cpp b/modules/twainui/cutpapertool.cpp new file mode 100644 index 00000000..ab2f84e0 --- /dev/null +++ b/modules/twainui/cutpapertool.cpp @@ -0,0 +1,219 @@ +#include "cutpapertool.h" +#include "ui_cutpapertool.h" +#include +#include + +CutPaperTool::CutPaperTool(QWidget *parent) : + QDialog(parent), + ui(new Ui::CutPaperTool) +{ + ui->setupUi(this); + setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); + connect(ui->widget,SIGNAL(cutRectX(double)),this,SLOT(cutRectXSlot(double))); + connect(ui->widget,SIGNAL(cutRectY(double)),this,SLOT(cutRectYSlot(double))); + connect(ui->widget,SIGNAL(cutRectWidth(double)),this,SLOT(cutRectWidthSlot(double))); + connect(ui->widget,SIGNAL(cutRectHeight(double)),this,SLOT(cutRectHeightSlot(double))); + connect(ui->widget,SIGNAL(lineEditEnable(bool)),this,SLOT(lineEditEnableSlot(bool))); + //setDpi(200); + //setPaperType(200,"A4",400); + ui->widget->setSizeType(MILLIM); + setSizeLabel(); + //ui->pbtn_init->setFixedWidth(160); + this->setFixedWidth(ui->widget->width()+40); +} + +CutPaperTool::~CutPaperTool() +{ + delete ui; +} + +void CutPaperTool::paintEvent(QPaintEvent *) +{ + +} + +void CutPaperTool::setPaperType(const int d, const QString &t, const int& w) +{ + dpi = d; + ui->dpiLab->setText(QString::number(dpi)); + ui->widget->setDpiValue(dpi); + paperType = t; + ui->paperLab->setText(paperType); + ui->widget->setPaperSize(paperType,w); + //ui->widget->refreshView(); + setSizeLabel(); + this->setFixedWidth(ui->widget->width()+40); + setSizeInit(); +} + +QRectF CutPaperTool::getCutRectPixel() +{ + return QRectF(ui->widget->getCutRectPixel()); +} + +void CutPaperTool::setCutRect(QRectF &rect) +{ + ui->widget->setCutRectPixel(rect); + ui->startXEdt->setText(QString::number(rect.x()/dpi/0.03937)); + ui->startYEdt->setText(QString::number(rect.y()/dpi/0.03937)); + ui->rectWidth->setText(QString::number(rect.width()/dpi/0.03937)); + ui->rectHeight->setText(QString::number(rect.height()/dpi/0.03937)); +} + +void CutPaperTool::setSizeLabel() +{ + QString wSize; + QString hSize; + if(ui->comboBox_2->currentIndex() == INCH){ + wSize = QString::number(ui->widget->getPaperSize().width(),'f',2); + hSize = QString::number(ui->widget->getPaperSize().height(),'f',2); + } + else { + wSize = QString::number(int(ui->widget->getPaperSize().width()+0.001)); + hSize = QString::number(int(ui->widget->getPaperSize().height()+0.001)); + } + ui->sizeLabel->setText("("+wSize + " * " +hSize+")"); +} + +void CutPaperTool::setSizeInit() +{ + ui->widget->setCutRectStartX(0); + ui->widget->setCutRectStartY(0); + ui->widget->setCutRectWidth(ui->widget->getPaperSize().width()); + ui->widget->setCutRectHeight(ui->widget->getPaperSize().height()); + ui->startXEdt->setText("0"); + ui->startYEdt->setText("0"); + ui->rectWidth->setText(QString::number(int(ui->widget->getPaperSize().width()))); + ui->rectHeight->setText(QString::number(int(ui->widget->getPaperSize().height()))); +} + +void CutPaperTool::setSizeInit(QRectF& rect){ + setSizeInit(); + if(rect != QRectF(0,0,0,0)) + setCutRect(rect); +} + +void CutPaperTool::cutRectXSlot(double x) +{ + ui->startXEdt->setText(QString::number(x)); +} + +void CutPaperTool::cutRectYSlot(double y) +{ + ui->startYEdt->setText(QString::number(y)); +} + +void CutPaperTool::cutRectWidthSlot(double w) +{ + ui->rectWidth->setText(QString::number(w)); +} + +void CutPaperTool::cutRectHeightSlot(double h) +{ + ui->rectHeight->setText(QString::number(h)); +} + +void CutPaperTool::lineEditEnableSlot(bool b) +{ + ui->startXEdt->setEnabled(b); + ui->startYEdt->setEnabled(b); + ui->rectWidth->setEnabled(b); + ui->rectHeight->setEnabled(b); +} + +void CutPaperTool::on_startXEdt_textEdited(QString arg1) +{ + double x = arg1.toDouble(); + if(x >ui->widget->getCutRectRight()) { + //arg1.chop(1); + //x = arg1.toDouble(); + //x = ui->widget->getCutRectRight(); + return ; + } + if(type == PIXEL) x = arg1.toInt(); + ui->widget->setCutRectStartX(x); +} + +void CutPaperTool::on_startYEdt_textEdited(QString arg1) +{ + double y = arg1.toDouble(); + if(y >ui->widget->getCutRectBottom()) { + //arg1.chop(1); + //y = arg1.toDouble(); + return ; + } + if(type == PIXEL) y = arg1.toInt(); + ui->widget->setCutRectStartY(y); +} + +void CutPaperTool::on_rectWidth_textEdited(QString arg1) +{ + double v = arg1.toDouble(); + if(v > ui->widget->getPaperSize().width() - ui->widget->getCutRectStartPos().x()) { + //arg1.chop(1); + //v = arg1.toDouble(); + //v=ui->widget->getPaperSize().width() - ui->widget->getCutRectStartPos().x(); + return ; + } + if(type == PIXEL) v = arg1.toInt(); + ui->widget->setCutRectWidth(v); +} + +void CutPaperTool::on_rectHeight_textEdited(QString arg1) +{ + double v = arg1.toDouble(); + if(v > ui->widget->getPaperSize().height() - ui->widget->getCutRectStartPos().y()) { + //arg1.chop(1); + //v = arg1.toDouble(); + //v = ui->widget->getPaperSize().height() - ui->widget->getCutRectStartPos().y(); + return ; + } + if(type == PIXEL) v = arg1.toInt(); + ui->widget->setCutRectHeight(v); +} + +void CutPaperTool::on_comboBox_2_currentIndexChanged(int index) +{ + switch(index){ + case 0: + ui->xLabel->setText("mm"); + ui->yLabel->setText("mm"); + ui->wLabel->setText("mm"); + ui->hLabel->setText("mm"); + ui->widget->setSizeType(MILLIM); + break; + case 1: + ui->xLabel->setText("in"); + ui->yLabel->setText("in"); + ui->wLabel->setText("in"); + ui->hLabel->setText("in"); + ui->widget->setSizeType(INCH); + break; + case 2: + ui->xLabel->setText("px"); + ui->yLabel->setText("px"); + ui->wLabel->setText("px"); + ui->hLabel->setText("px"); + ui->widget->setSizeType(PIXEL); + break; + } + update(); + setSizeLabel(); + ui->widget->refreshView(); +} + + +void CutPaperTool::on_buttonBox_accepted() +{ + accept(); +} + +void CutPaperTool::on_buttonBox_rejected() +{ + reject(); +} + +void CutPaperTool::on_pbtn_init_clicked() +{ + setSizeInit(); +} diff --git a/modules/twainui/cutpapertool.h b/modules/twainui/cutpapertool.h new file mode 100644 index 00000000..cf6d40eb --- /dev/null +++ b/modules/twainui/cutpapertool.h @@ -0,0 +1,59 @@ +#ifndef CUTPAPERTOOL_H +#define CUTPAPERTOOL_H + +#include +#include "cutdialog.h" + +namespace Ui { +class CutPaperTool; +} + +class CutPaperTool : public QDialog +{ + Q_OBJECT + +public: + explicit CutPaperTool(QWidget *parent = nullptr); + ~CutPaperTool(); + void setPaperType(const int dpi, const QString& t,const int& w=200); + QRectF getCutRectPixel(); + void setCutRect(QRectF& rect); + void setSizeInit(); + void setSizeInit(QRectF& rect); + + +private: + void paintEvent(QPaintEvent *); + void setSizeLabel(); + +private slots: + void cutRectXSlot(double x); + void cutRectYSlot(double y); + void cutRectWidthSlot(double w); + void cutRectHeightSlot(double h); + void lineEditEnableSlot(bool b); + + void on_startXEdt_textEdited(QString arg1); + + void on_startYEdt_textEdited(QString arg1); + + void on_rectWidth_textEdited(QString arg1); + + void on_rectHeight_textEdited(QString arg1); + + void on_comboBox_2_currentIndexChanged(int index); + + void on_buttonBox_accepted(); + + void on_buttonBox_rejected(); + + void on_pbtn_init_clicked(); + +private: + Ui::CutPaperTool *ui; + SIZETYPE type; + int dpi; + QString paperType; +}; + +#endif // CUTPAPERTOOL_H diff --git a/modules/twainui/cutpapertool.ui b/modules/twainui/cutpapertool.ui new file mode 100644 index 00000000..0e5178d6 --- /dev/null +++ b/modules/twainui/cutpapertool.ui @@ -0,0 +1,298 @@ + + + CutPaperTool + + + true + + + + 0 + 0 + 439 + 676 + + + + + 0 + 0 + + + + 自定义扫描区域 + + + + + + + + 纸张尺寸: + + + + + + + A4 + + + + + + + (210*297) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + DPI(像素/英寸): + + + Qt::AlignJustify|Qt::AlignVCenter + + + + + + + 200 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 单位: + + + + + + + + 毫米(mm) + + + + + 英寸(in) + + + + + 像素(px) + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 初始化选择区域 + + + + + + + + + true + + + + + 0 + 0 + 421 + 430 + + + + + + + + 0 + 0 + + + + + + + + + + + + + + x: + + + + + + + + + + mm + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + y: + + + + + + + + + + mm + + + + + + + + + + + w: + + + + + + + + + + mm + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + h: + + + + + + + + + + mm + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + cutDialog + QWidget +
cutdialog.h
+ 1 +
+
+ + +
diff --git a/modules/twainui/device_menu.cpp b/modules/twainui/device_menu.cpp new file mode 100644 index 00000000..1259f158 --- /dev/null +++ b/modules/twainui/device_menu.cpp @@ -0,0 +1,189 @@ +#include "device_menu.h" + +#define ACTION_DEVICE_NAME_PROPERTY "device_name" + +device_menu::device_menu(QWidget *parent) + : QMenu(parent) + , cur_action_(nullptr), none_action_(nullptr) +{ + group_action_ = new QActionGroup(this); + deviceMenuUpdate(nullptr); + connect(group_action_, SIGNAL(triggered(QAction*)), this, SLOT(on_act_triggered(QAction*))); +} + +device_menu::device_menu(const QString &title, QWidget *parent) + : QMenu(title, parent) + , cur_action_(nullptr), none_action_(nullptr) +{ + group_action_ = new QActionGroup(this); + deviceMenuUpdate(nullptr); + connect(group_action_, SIGNAL(triggered(QAction*)), this, SLOT(on_act_triggered(QAction*))); +} + +QMenu* device_menu::find_device_menu(const QString& dev_name) +{ + std::lock_guard lock(mutex_); + std::vector::iterator it = std::find(menus_.begin(), menus_.end(), dev_name); + + if(it == menus_.end()) + return nullptr; + else + return it->menu; +} +QAction* device_menu::find_device_config(const QString& dev_name, const QString& cfg_name) +{ + std::lock_guard lock(mutex_); + std::vector::iterator it = std::find(menus_.begin(), menus_.end(), dev_name); + + if(it == menus_.end()) + return NULL; + + for(size_t i = 0; i < it->actions.size(); ++i) + { + if(it->actions[i]->text() == cfg_name) + return it->actions[i]; + } + + return NULL; +} + +void device_menu::connectedDevice(const QString &device) +{ + QMenu* menu = find_device_menu(device); + if (menu) + menu->setEnabled(true); +} + +void device_menu::disconnectedDevice(const QString &device) +{ + QMenu* menu = find_device_menu(device); + if (menu) + menu->setEnabled(false); +} + +void device_menu::setOptionChecked(const QString &device, const QString &opt, bool checked) +{ + QAction* act = find_device_config(device, opt); + + if(act) + { + act->setChecked(checked); + if(checked) + cur_action_ = act; + else + { + if(cur_action_ == act) + cur_action_ = nullptr; + } + } + else if(checked) + cur_action_ = nullptr; +} + +void device_menu::get_online_devices(QList& dev_names) +{ + std::lock_guard lock(mutex_); + + for(size_t i = 0; i < menus_.size(); ++i) + { + if(menus_[i].menu->isEnabled()) + dev_names.push_back(menus_[i].menu->title()); + } +} + +void device_menu::deviceMenuUpdate(dev_que* que) +{ + std::lock_guard lock(mutex_); + + cur_action_ = nullptr; + if(none_action_) + { + removeAction(none_action_); + none_action_ = nullptr; + } + + for(size_t i = 0; i < menus_.size(); ++i) + menus_[i].menu->setEnabled(false); + if (!que || que->scanners() == 0) + { + if(menus_.empty()) + { + none_action_ = addAction(tr("no device")); + none_action_->setEnabled(false); + } + + return; + } + + for (size_t i = 0; i < que->scanners(); i++) + { + SCANNER s = que->get_at(i); + std::vector::iterator it = std::find(menus_.begin(), menus_.end(), QString::fromStdString((s.name))); + POPMENU pm; + std::vector schemes; + + if(it == menus_.end()) + pm.menu = addMenu(QString::fromStdString(s.name)); + else + { + pm = *it; + menus_.erase(it); + } + pm.menu->setEnabled(true); + pm.menu->setToolTipsVisible(true); + for(size_t j = 0; j < pm.actions.size(); ++j) + { + pm.menu->removeAction(pm.actions[j]); + group_action_->removeAction(pm.actions[j]); + } + pm.actions.clear(); + s.cfg->get_all_schemes(schemes); + for (size_t j = 0; j < schemes.size(); j++) + { + QAction *child = group_action_->addAction(QString::fromStdString(schemes[j])); + child->setProperty(ACTION_DEVICE_NAME_PROPERTY, QVariant(QString::fromStdString(s.name))); + child->setCheckable(true); + + if(que->opened_scanner_name() == s.name && + schemes[j] == s.cfg->get_current_scheme_name()) + { + cur_action_ = child; + child->setChecked(true); + } + + pm.menu->addAction(child); + pm.actions.push_back(child); + + QString tips; + if(tips.isNull()) + { + tips = tr("default setting"); + } + // child->setToolTip(tips); + } + menus_.push_back(pm); + s.cfg->release(); + } +} + +void device_menu::on_act_triggered(QAction* act) +{ + QString deviceName = act->property(ACTION_DEVICE_NAME_PROPERTY).toString(); + QString opt = act->text(); + bool checked_now = act->isChecked(); + + if(cur_action_ == act) + { + checked_now = false; + act->setChecked(false); + cur_action_ = nullptr; +// emit scanOptionsChanged("", "", false); +// return; + } + else { + cur_action_ = act; + checked_now = true; + } + + emit scanOptionsChanged(deviceName, opt, checked_now); +} diff --git a/modules/twainui/device_menu.h b/modules/twainui/device_menu.h new file mode 100644 index 00000000..bab55cae --- /dev/null +++ b/modules/twainui/device_menu.h @@ -0,0 +1,494 @@ +#ifndef DEVICE_MENU_H +#define DEVICE_MENU_H + +#include +#include +#include "sane/sane_ex.h" +#include "sane/sane_option_definitions.h" +#include "../../../sdk/include/huagao/hgscanner_error.h" + +#include "cfg/gb_json.h" +#include "lang/app_language.h" + +typedef struct _scanner +{ + std::string name; + std::string model; + bool online; + gb::scanner_cfg *cfg; +}SCANNER; +class dev_que +{ + std::vector que_; + std::string root_dir_; + std::string opened_scanner_; + std::string applied_scheme_; + SANE_Handle handle_; + + + static void trans_number(const char* name, std::string& val, void* param) + { + if (strcmp(name, "tl-x") == 0 + || strcmp(name, "br-x") == 0 + || strcmp(name, "tl-y") == 0 + || strcmp(name, "br-y") == 0 + || strcmp(name, "gamma") == 0 + || strcmp(name, "search-hole-range-l") == 0 + || strcmp(name, "search-hole-range-r") == 0 + || strcmp(name, "search-hole-range-t") == 0 + || strcmp(name, "search-hole-range-b") == 0 + || strcmp(name, "feed-strength-value") == 0 + ) + { + float v = atof(val.c_str()); + SANE_Fixed f = SANE_FIX(v); + + val = std::string((char*)&f, sizeof(f)); + } + else if (strcmp(name, "binary-threshold") == 0 + || strcmp(name, "bkg-color-range") == 0 + || strcmp(name, "noise-size") == 0 + || strcmp(name, "blank-sensitivity") == 0 + || strcmp(name, "resolution") == 0 + || strcmp(name, "brightness") == 0 + || strcmp(name, "contrast") == 0 + || strcmp(name, "threshold") == 0 + || strcmp(name, "anti-noise-level") == 0 + || strcmp(name, "margin") == 0 + || strcmp(name, "scan-count") == 0 + || strcmp(name, "askew-range") == 0 + || strcmp(name, "dog-ear-size") == 0 + ) + { + SANE_Int v = atoi(val.c_str()); + val = std::string((char*)&v, sizeof(v)); + } + else if (strcmp(val.c_str(), "true") == 0) + { + SANE_Bool b = SANE_TRUE; + val = std::string((char*)&b, sizeof(b)); + } + else if (strcmp(val.c_str(), "false") == 0) + { + SANE_Bool b = SANE_FALSE; + val = std::string((char*)&b, sizeof(b)); + } + } + static const char* title_2_name(const char* title, void* param) + { + struct + { + const char* name; + const char* title; + }g_opts[] = { {SANE_STD_OPT_NAME_RESTORE , OPTION_TITLE_HFMRSZ} + , {SANE_STD_OPT_NAME_HELP , OPTION_TITLE_BZ} + , {SANE_STD_OPT_NAME_IS_MULTI_OUT , OPTION_TITLE_DLSC} + , {SANE_STD_OPT_NAME_MULTI_OUT_TYPE , OPTION_TITLE_DLSCLX} + , {SANE_STD_OPT_NAME_COLOR_MODE , OPTION_TITLE_YSMS} + , {SANE_STD_OPT_NAME_BINARY_THRESHOLD , OPTION_TITLE_HBTXYZ} + , {SANE_STD_OPT_NAME_REVERSE_01 , OPTION_TITLE_HBTXFSSC} + , {SANE_STD_OPT_NAME_FILTER , OPTION_TITLE_HDHHBTX_CSYZQ} + , {SANE_STD_OPT_NAME_RID_MULTIOUT_RED , OPTION_TITLE_24WCSTX_DLSCCH} + , {SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED , OPTION_TITLE_24WCSTX_DTKCH} + , {SANE_STD_OPT_NAME_ERASE_BACKGROUND , OPTION_TITLE_BJYC} + , {SANE_STD_OPT_NAME_BKG_COLOR_RANGE , OPTION_TITLE_BJSCFDFW} + , {SANE_STD_OPT_NAME_SHARPEN , OPTION_TITLE_RHYMH} + , {SANE_STD_OPT_NAME_RID_MORR , OPTION_TITLE_QCMW} + , {SANE_STD_OPT_NAME_RID_GRID , OPTION_TITLE_CWW} + , {SANE_STD_OPT_NAME_ERROR_EXTENSION , OPTION_TITLE_CWKS} + , {SANE_STD_OPT_NAME_NOISE_OPTIMIZE , OPTION_TITLE_HBTXZDYH} + , {SANE_STD_OPT_NAME_NOISE_SIZE , OPTION_TITLE_ZDYHCC} + , {SANE_STD_OPT_NAME_PAPER , OPTION_TITLE_ZZCC} + , {SANE_STD_OPT_NAME_CUSTOM_AREA , OPTION_TITLE_ZDYSMQY} + , {SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT , OPTION_TITLE_SMQYZCmm} + , {SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT , OPTION_TITLE_SMQYYCmm} + , {SANE_STD_OPT_NAME_CUSTOM_AREA_TOP , OPTION_TITLE_SMQYSCmm} + , {SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM , OPTION_TITLE_SMQYXCmm} + , {SANE_STD_OPT_NAME_SIZE_CHECK , OPTION_TITLE_CCJC} + , {SANE_STD_OPT_NAME_PAGE , OPTION_TITLE_SMYM} + , {SANE_STD_OPT_NAME_DISCARD_BLANK_SENS , OPTION_TITLE_TGKBYLMD} + , {SANE_STD_OPT_NAME_RESOLUTION , OPTION_TITLE_FBL} + , {SANE_STD_OPT_NAME_TIME_TO_SLEEP , OPTION_TITLE_XMSJ} + , {SANE_STD_OPT_NAME_IMAGE_QUALITY , OPTION_TITLE_HZ} + , {SANE_STD_OPT_NAME_EXCHANGE ,OPTION_TITLE_JHZFM} + , {SANE_STD_OPT_NAME_SPLIT ,OPTION_TITLE_TXCF } + , {SANE_STD_OPT_NAME_ANTI_SKEW , OPTION_TITLE_ZDJP} + , {SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA , OPTION_TITLE_QYSDQX} + , {SANE_STD_OPT_NAME_GAMMA , OPTION_TITLE_JMZ} + , {SANE_STD_OPT_NAME_BRIGHTNESS , OPTION_TITLE_LDZ} + , {SANE_STD_OPT_NAME_CONTRAST , OPTION_TITLE_DBD} + , {SANE_STD_OPT_NAME_IS_PHOTO_MODE , OPTION_TITLE_ZPMS} + , {SANE_STD_OPT_NAME_ERASE_BLACK_FRAME , OPTION_TITLE_XCHK} + , {SANE_STD_OPT_NAME_DARK_SAMPLE , OPTION_TITLE_SSYZ} + , {SANE_STD_OPT_NAME_THRESHOLD , OPTION_TITLE_YZ} + , {SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL , OPTION_TITLE_BJKZDJ} + , {SANE_STD_OPT_NAME_MARGIN , OPTION_TITLE_BYSJ} + , {SANE_STD_OPT_NAME_FILL_BKG_MODE , OPTION_TITLE_BJTCFS} + , {SANE_STD_OPT_NAME_IS_ANTI_PERMEATE , OPTION_TITLE_FZST} + , {SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL , OPTION_TITLE_FZSTDJ} + , {SANE_STD_OPT_NAME_RID_HOLE_L , OPTION_TITLE_CKYCZC} + , {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L , OPTION_TITLE_ZCCKSSFWZFMBL} + , {SANE_STD_OPT_NAME_RID_HOLE_R , OPTION_TITLE_CKYCYC} + , {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R , OPTION_TITLE_YCCKSSFWZFMBL} + , {SANE_STD_OPT_NAME_RID_HOLE_T , OPTION_TITLE_CKYCSC} + , {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T , OPTION_TITLE_SCCKSSFWZFMBL} + , {SANE_STD_OPT_NAME_RID_HOLE_B , OPTION_TITLE_CKYCXC} + , {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B , OPTION_TITLE_XCCKSSFWZFMBL} + , {SANE_STD_OPT_NAME_IS_FILL_COLOR , OPTION_TITLE_SCTC} + , {SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK , OPTION_TITLE_CSBJC} + , {SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE , OPTION_TITLE_SZTPCL} + , {SANE_STD_OPT_NAME_IS_CHECK_STAPLE , OPTION_TITLE_ZDJC} + , {SANE_STD_OPT_NAME_SCAN_MODE , OPTION_TITLE_SMZS} + , {SANE_STD_OPT_NAME_SCAN_COUNT , OPTION_TITLE_SMSL} + , {SANE_STD_OPT_NAME_TEXT_DIRECTION , OPTION_TITLE_WGFX} + , {SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 , OPTION_TITLE_BMXZ180} + , {SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR , OPTION_TITLE_ZJJC} + , {SANE_STD_OPT_NAME_DOG_EAR_SIZE , OPTION_TITLE_ZJDX} + , {SANE_STD_OPT_NAME_IS_CHECK_ASKEW , OPTION_TITLE_WXJC} + , {SANE_STD_OPT_NAME_ASKEW_RANGE , OPTION_TITLE_WXRRD} + , {SANE_STD_OPT_NAME_FEED_STRENGTH , OPTION_TITLE_FZQD} + , {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , OPTION_TITLE_ZDFZQD} + , {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , OPTION_TITLE_JZSBL} + , {SANE_STD_OPT_NAME_WAIT_TO_SCAN , OPTION_TITLE_DZSM} + , {SANE_STD_OPT_NAME_FOLD_TYPE , OPTION_TITLE_DZMS} + }, + g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 黑白图像反色输出(正常颜色为:0-黑色;1-白色) + , {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 灰度或黑白图像 - 除色 + , {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 自动搓纸强度 + , {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 搓纸阈值" + }; + while (*title == ' ') + title++; + + for (size_t i = 0; i < _countof(g_opts); ++i) + { + if (strcmp(title, g_opts[i].title) == 0) + return g_opts[i].name; + } + for (size_t i = 0; i < _countof(g_discard); ++i) + { + if (strcmp(title, g_discard[i].title) == 0) + return g_discard[i].name; + } + + return title; + } + +public: + dev_que() : handle_(nullptr) + {} + ~dev_que() + { + close_scanner(); + + for(auto& v : que_) + v.cfg->release(); + } + + static void update_old_cfg(const char* conf) + { + gb::scanner_cfg::UDF func; + + func.func_param = nullptr; + func.title2name = &dev_que::title_2_name; + func.trans_number = &dev_que::trans_number; + + gb::scanner_cfg::update(conf, &func); + } + static void apply_scheme(const SANEAPI* saneApi, SANE_Handle h, gb::sane_config_schm* schm) + { + SANE_Int count = 0, none = 0; + std::string name(""), val(""); + + none = saneApi->sane_io_control_api(h, IO_CTRL_CODE_RESTORE_SETTINGS, NULL, NULL); + if(schm && schm->id_from_name(SANE_STD_OPT_NAME_COLOR_MODE) == -1) + { + SANE_Int dev_options = 0; + saneApi->sane_control_option_api(h, 0, SANE_ACTION_GET_VALUE, &dev_options, nullptr); + for(int i = 1; i < dev_options; ++i) + { + const SANE_Option_Descriptor* opt = saneApi->sane_get_option_descriptor_api(h, i); + if(!opt) + continue; + + unsigned int n = i; + if(opt->type == SANE_TYPE_BOOL) + { + SANE_Bool v = SANE_TRUE; + saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, &v, &n); + schm->set_default_value(i, opt->name, (char*)&v, sizeof(v)); + } + else if (opt->type == SANE_TYPE_INT) { + SANE_Int v = 0; + saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, &v, &n); + schm->set_default_value(i, opt->name, (char*)&v, sizeof(v)); + } + else if(opt->type == SANE_TYPE_FIXED) + { + SANE_Fixed v = 0; + saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, &v, &n); + schm->set_default_value(i, opt->name, (char*)&v, sizeof(v)); + } + else { + char *buf = new char[opt->size + 4]; + memset(buf, 0, opt->size + 4); + saneApi->sane_io_control_api(h, IO_CTRL_CODE_GET_DEFAULT_VALUE, buf, &n); + std::string langCN(to_default_language(buf, nullptr)); + schm->set_default_value(i, opt->name, &langCN[0], langCN.length()); + delete[] buf; + } + } + } + if(schm && schm->first_config(name, val)) + { + do + { + int id = schm->id_from_name(name.c_str()); + if(id == -1) + { + if(gb::sane_config_schm::is_option_data(name)) + { + if(name == SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA && val.length() == sizeof(SANE_Gamma)) + { + unsigned int l = val.length(); + saneApi->sane_io_control_api(h, IO_CTRL_CODE_SET_CUSTOM_GAMMA, &val[0], &l); + } + } + } + else { + const SANE_Option_Descriptor* opt = reinterpret_cast(saneApi->sane_get_option_descriptor_api(h, id)); + if(opt) + { + if(opt->type == SANE_TYPE_STRING) + { + char *buf = new char[opt->size + 4]; + memset(buf, 0, opt->size + 4); + strcpy(buf, val.c_str()); + std::string langCN(from_default_language(buf, nullptr)); + saneApi->sane_control_option_api(h, id, SANE_ACTION_SET_VALUE, &langCN[0], &none); + delete[] buf; + } + else { + saneApi->sane_control_option_api(h, id, SANE_ACTION_SET_VALUE, &val[0], &none); + } + } + } + + }while(schm->next_config(name, val)); + } + } + + +public: + void set_root_dir(const char* root) + { + root_dir_ = std::string(root) + PATH_SYMBOL; + } + void add_scanner(const char* sane_name) + { + bool found = false; + + for(auto& v: que_) + { + if(v.name == sane_name) + { + found = true; + break; + } + } + + if(!found) + { + SCANNER s; + size_t pos = 0; + + s.model = s.name = sane_name; + s.cfg = nullptr; + pos = s.model.find(" - "); + if(pos != std::string::npos) + { + pos = s.model.find(" - ", pos + 3); + if(pos != std::string::npos) + s.model.erase(pos); + } + for(auto& v: que_) + { + if(v.model == s.model) + { + s.cfg = v.cfg; + s.cfg->add_ref(); + break; + } + } + + if(!s.cfg) + { + s.cfg = new gb::scanner_cfg(); + s.cfg->load_file((root_dir_ + s.model + ".cfg").c_str()); + } + s.online = true; + que_.push_back(s); + } + } + void get_schemes(const char* scanner_name, std::vector& schemes) + { + schemes.clear(); + for(auto& v : que_) + { + if(v.name == scanner_name) + { + v.cfg->get_all_schemes(schemes); + break; + } + } + } + SANE_Handle handle(void) + { + return handle_; + } + std::string opened_scanner_name(void) + { + return opened_scanner_; + } + std::string applied_scheme(void) + { + return applied_scheme_; + } + int open_scanner(const SANEAPI* saneAPI, SANE_Handle handle, const char* scanner_name, const char* scheme = nullptr) + { + handle_ = handle; + opened_scanner_ = scanner_name; + apply_scheme(saneAPI, scheme); + return SANE_STATUS_GOOD; + } + int close_scanner(void) + { + handle_ = nullptr; + opened_scanner_ = ""; + applied_scheme_ = ""; + return SANE_STATUS_GOOD; + } + int scanners(void) + { + return que_.size(); + } + SCANNER get_at(int pos) + { + SCANNER s; + + s.name = s.model = ""; + s.cfg = nullptr; + if(pos >= 0 && pos < que_.size()) + { + s = que_[pos]; + s.cfg->add_ref(); + } + + return s; + } + bool is_online(const char* scanner = nullptr) + { + if(!scanner) + scanner = opened_scanner_.c_str(); + + for(auto& v : que_) + { + if(v.name == scanner) + return v.online; + } + + return false; + } + void set_online(bool online, const char* scanner = nullptr) + { + if(!scanner) + scanner = opened_scanner_.c_str(); + + for(auto& v : que_) + { + if(v.name == scanner) + { + v.online = online; + break; + } + } + } + void get_scanners(std::vector& que) + { + for(auto& v: que_) + que.push_back(v.name); + } + int apply_scheme(const SANEAPI* saneApi, const char* scheme_name) + { + if(!handle_) + return SCANNER_ERR_NOT_OPEN; + + for(auto& v: que_) + { + if(v.name == opened_scanner_) + { + gb::sane_config_schm* schm = v.cfg->get_scheme(scheme_name); + dev_que::apply_scheme(saneApi, handle_, schm); + if(schm) + { + v.cfg->select_scheme(schm->get_scheme_name().c_str()); + schm->release(); + } + else { + v.cfg->select_scheme(scheme_name); + } + applied_scheme_ = v.cfg->get_current_scheme_name(); + v.cfg->save(); + break; + } + } + + return SCANNER_ERR_OK; + } +}; + + +class device_menu : public QMenu +{ + Q_OBJECT + typedef struct _pop_menu + { + QMenu* menu; + std::vector actions; + + bool operator==(const QString& menu_title) + { + return menu->title() == menu_title; + } + }POPMENU; + std::vector menus_; + QAction* cur_action_; + QAction* none_action_; + QActionGroup* group_action_; + std::mutex mutex_; + + QMenu* find_device_menu(const QString& dev_name); + QAction* find_device_config(const QString& dev_name, const QString& cfg_name); + +public: + device_menu(QWidget* parent = nullptr); + device_menu(const QString& title, QWidget* parent = nullptr); + + void deviceMenuUpdate(dev_que* que); + + void connectedDevice(const QString& device); + + void disconnectedDevice(const QString& device); + + void setOptionChecked(const QString& device, const QString& opt, bool checked); + + void get_online_devices(QList& dev_names); + +signals: + void scanOptionsChanged(const QString& device, const QString& opt, bool checked_now); + +private slots: + void on_act_triggered(QAction* act); +}; + +#endif // DEVICE_MENU_H diff --git a/modules/twainui/dialog_device_select.cpp b/modules/twainui/dialog_device_select.cpp new file mode 100644 index 00000000..e65f106d --- /dev/null +++ b/modules/twainui/dialog_device_select.cpp @@ -0,0 +1,51 @@ +#include "dialog_device_select.h" +#include "ui_dialog_device_select.h" + +Dialog_device_select::Dialog_device_select(const std::vector& devs, QWidget *parent) : + QDialog(parent), + ui(new Ui::Dialog_device_select) + , m_devId(-1) + , m_devs(devs) +{ + ui->setupUi(this); + + for (int i = 0; i < m_devs.size(); ++i) + { + ui->listWidget->addItem(QString::fromStdString(m_devs[i].name)); + } +} + +Dialog_device_select::~Dialog_device_select() +{ + delete ui; +} + +int Dialog_device_select::getDevId() +{ + return m_devId; +} + +void Dialog_device_select::on_pbtn_ok_clicked() +{ + std::string selectDev = ui->listWidget->currentItem()->text().toStdString(); + + for (int i = 0; i < m_devs.size(); ++i) + { + if (m_devs[i].name == selectDev) + { + m_devId = m_devs[i].id; + } + else + { + m_devId = -1; + } + } + + accept(); +} + +void Dialog_device_select::on_pbtn_cancel_clicked() +{ + m_devId = -1; + reject(); +} diff --git a/modules/twainui/dialog_device_select.h b/modules/twainui/dialog_device_select.h new file mode 100644 index 00000000..40610faf --- /dev/null +++ b/modules/twainui/dialog_device_select.h @@ -0,0 +1,33 @@ +#ifndef DIALOG_DEVICE_SELECT_H +#define DIALOG_DEVICE_SELECT_H + +#include +#include "twainui.h" + +namespace Ui { +class Dialog_device_select; +} + +class Dialog_device_select : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog_device_select(const std::vector& devs, QWidget *parent = nullptr); + ~Dialog_device_select(); + + int getDevId(); + +private slots: + void on_pbtn_ok_clicked(); + + void on_pbtn_cancel_clicked(); + +private: + Ui::Dialog_device_select *ui; + + std::vector m_devs; + int m_devId; +}; + +#endif // DIALOG_DEVICE_SELECT_H diff --git a/modules/twainui/dialog_device_select.ui b/modules/twainui/dialog_device_select.ui new file mode 100644 index 00000000..ce77ca6a --- /dev/null +++ b/modules/twainui/dialog_device_select.ui @@ -0,0 +1,55 @@ + + + Dialog_device_select + + + + 0 + 0 + 342 + 216 + + + + Dialog + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Ok + + + + + + + Cancel + + + + + + + + + + diff --git a/modules/twainui/dialog_input.cpp b/modules/twainui/dialog_input.cpp new file mode 100644 index 00000000..1692c79d --- /dev/null +++ b/modules/twainui/dialog_input.cpp @@ -0,0 +1,65 @@ +#include "dialog_input.h" +#include "ui_dialog_input.h" +#include +#include + +Dialog_Input::Dialog_Input(QWidget *parent) : + QDialog(parent), + ui(new Ui::Dialog_Input) +{ + ui->setupUi(this); +} + +Dialog_Input::~Dialog_Input() +{ + delete ui; +} + +void Dialog_Input::on_pushButton_clicked() +{ + QString text = ui->lineEdit->text(); + static QRegularExpression re("\\s"); + text.remove(re);//Remove space + + std::string str(text.toStdString()); + int pos = 0; + while(pos < str.length() && str[pos++] == ' '); + if(--pos > 0) + str.erase(0, pos); + pos = str.length() - 1; + while(pos >= 0) + { + if(str[pos] != ' ') + break; + } + str.erase(pos + 1); + + if(str.empty()) + { + QString title(QString::fromStdString("\351\224\231\350\257\257")), + text(QString::fromStdString("\350\276\223\345\205\245\351\235\236\346\263\225")); + + QMessageBox::warning(this, title, text); + + return; + } + + val_ = QString::fromStdString(str); + done(1); +} + +void Dialog_Input::on_pushButton_2_clicked() +{ + done(0); +} + +void Dialog_Input::init_value(const QString& str) +{ + val_ = str; + ui->lineEdit->setText(str); + ui->lineEdit->setSelection(0, str.length()); +} +QString Dialog_Input::get_inputting_value(void) +{ + return val_; +} diff --git a/modules/twainui/dialog_input.h b/modules/twainui/dialog_input.h new file mode 100644 index 00000000..df8a9fd0 --- /dev/null +++ b/modules/twainui/dialog_input.h @@ -0,0 +1,33 @@ +#ifndef DIALOG_INPUT_H +#define DIALOG_INPUT_H + +#include + +namespace Ui { +class Dialog_Input; +} + +class Dialog_Input : public QDialog +{ + Q_OBJECT + + QString val_; + +public: + explicit Dialog_Input(QWidget *parent = nullptr); + ~Dialog_Input(); + +public: + void init_value(const QString& str); + QString get_inputting_value(void); + +private slots: + void on_pushButton_clicked(); + + void on_pushButton_2_clicked(); + +private: + Ui::Dialog_Input *ui; +}; + +#endif // DIALOG_INPUT_H diff --git a/modules/twainui/dialog_input.ui b/modules/twainui/dialog_input.ui new file mode 100644 index 00000000..1508f61c --- /dev/null +++ b/modules/twainui/dialog_input.ui @@ -0,0 +1,85 @@ + + + Dialog_Input + + + + 0 + 0 + 282 + 82 + + + + Dialog + + + + + + + + -1 + + + 输入: + + + 0 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Ok + + + + + + + Cancel + + + + + + + + + + diff --git a/modules/twainui/dialog_progress_ui.cpp b/modules/twainui/dialog_progress_ui.cpp new file mode 100644 index 00000000..cbe278ad --- /dev/null +++ b/modules/twainui/dialog_progress_ui.cpp @@ -0,0 +1,48 @@ +#include "dialog_progress_ui.h" +#include "ui_dialog_progress_ui.h" + +Dialog_progress_ui *Dialog_progress_ui::m_param = nullptr; + +Dialog_progress_ui::Dialog_progress_ui(std::function callback, std::function *notify, QWidget *parent) : + QDialog(parent), + ui(new Ui::Dialog_progress_ui) +{ + ui->setupUi(this); + + m_callback = callback; + *notify = FuncNotify; + m_param = this; + + connect(this, SIGNAL(scan_finish(QString)), this, SLOT(on_scan_finish(QString)), Qt::QueuedConnection); +} + +Dialog_progress_ui::~Dialog_progress_ui() +{ + delete ui; +} + +void Dialog_progress_ui::on_pbtn_cancelScan_clicked() +{ + m_callback(UI_RESULT_CLOSE_CANCEL); + close(); +} + +void Dialog_progress_ui::on_scan_finish(QString finishInfo) +{ + ui->label->setText(finishInfo); +} + +void Dialog_progress_ui::FuncNotify(int event, void *msg, int flag) +{ + Dialog_progress_ui *p = (Dialog_progress_ui *)m_param; + + switch (event) + { + case SANE_EVENT_SCAN_FINISHED: + { + QString finishInfo((char*)msg); + emit p->scan_finish(finishInfo); + } + break; + } +} diff --git a/modules/twainui/dialog_progress_ui.h b/modules/twainui/dialog_progress_ui.h new file mode 100644 index 00000000..06918463 --- /dev/null +++ b/modules/twainui/dialog_progress_ui.h @@ -0,0 +1,38 @@ +#ifndef DIALOG_PROGRESS_UI_H +#define DIALOG_PROGRESS_UI_H + +#include +#include "twainui.h" + +namespace Ui { +class Dialog_progress_ui; +} + +class Dialog_progress_ui : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog_progress_ui(std::function callback, std::function *notify, QWidget *parent = nullptr); + ~Dialog_progress_ui(); + +private: + static Dialog_progress_ui *m_param; + +signals: + void scan_finish(QString finishInfo); + +private slots: + void on_pbtn_cancelScan_clicked(); + void on_scan_finish(QString finishInfo); + +private: + static void FuncNotify(int event, void *msg, int flag); + +private: + Ui::Dialog_progress_ui *ui; + + std::function m_callback; +}; + +#endif // DIALOG_PROGRESS_UI_H diff --git a/modules/twainui/dialog_progress_ui.ui b/modules/twainui/dialog_progress_ui.ui new file mode 100644 index 00000000..b9db1818 --- /dev/null +++ b/modules/twainui/dialog_progress_ui.ui @@ -0,0 +1,95 @@ + + + Dialog_progress_ui + + + + 0 + 0 + 325 + 166 + + + + Dialog + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel Scan + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/modules/twainui/dllmain.cpp b/modules/twainui/dllmain.cpp new file mode 100644 index 00000000..e7002101 --- /dev/null +++ b/modules/twainui/dllmain.cpp @@ -0,0 +1,62 @@ +#include "base/HGDef.h" +#include "base/HGInc.h" +#include "base/HGUtility.h" + +#if defined (HG_CMP_MSC) +#include "qmfcapp.hpp" +#include "qwinwidget.hpp" + +HINSTANCE g_hInst = NULL; +bool g_ownApplication = FALSE; + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpvReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hInst = hInstance; + + HGChar moduleName[512]; + HGBase_GetModuleName(DllMain, moduleName, 512); + HGChar modulePath[512]; + HGBase_GetFilePath(moduleName, modulePath, 512); + + char *env = getenv("QT_QPA_PLATFORM_PLUGIN_PATH"); + if (NULL == env) + { + char newEnv[256]; + sprintf(newEnv, "QT_QPA_PLATFORM_PLUGIN_PATH=%s", modulePath); + putenv(newEnv); + } + else if (NULL == strstr(env, modulePath)) + { + char *newEnv = new char [strlen(env) + 256]; + sprintf(newEnv, "QT_QPA_PLATFORM_PLUGIN_PATH=%s;%s", env, modulePath); + putenv(newEnv); + delete []newEnv; + } + } + else if (dwReason == DLL_PROCESS_DETACH) + { + if (g_ownApplication) + delete qApp; + g_hInst = NULL; + } + + return TRUE; +} +#else + +void __attribute__((constructor)) global_load(void); +void __attribute__((destructor)) global_unload(void); + +void global_load(void) +{ + +} + +void global_unload(void) +{ + +} + +#endif diff --git a/modules/twainui/gaosixy.cpp b/modules/twainui/gaosixy.cpp new file mode 100644 index 00000000..15de754a --- /dev/null +++ b/modules/twainui/gaosixy.cpp @@ -0,0 +1,54 @@ +#include "gaosixy.h" +#include +#include +#include + +GaoSiXY::GaoSiXY() +{ +} + +void GaoSiXY::solve(double**a,int n,double *recv) +{ + int m = 0; + int i,j; + + for(j = 0; j < n; j++){ + double max = 0; + double imax = 0; + for(i = j; i < n; i++){ + if(imax < fabs(a[i][j])){ + imax = fabs(a[i][j]); + max = a[i][j];//得到各行中所在列最大元素 + m = i; + } + } + if(fabs(a[j][j]) != max) { + double b = 0; + for(int k = j;k < n + 1; k++){ + b = a[j][k]; + a[j][k] = a[m][k]; + a[m][k] = b; } + } + for(int r = j;r < n + 1;r++){ + a[j][r] = a[j][r] / max;//让该行的所在列除以所在列的第一个元素,目的是让首元素为1 + } + for(i = j + 1;i < n; i++){ + double c = a[i][j]; + if(c == 0) continue; + for(int s = j;s < n + 1;s++){ + //double tempdata = a[i][s]; + a[i][s] = a[i][s] - a[j][s] * c;//前后行数相减,使下一行或者上一行的首元素为0 + } + } + } + for(i = n - 2; i >= 0; i--){ + for(j = i + 1;j < n; j++){ + a[i][n] = a[i][n] - a[j][n] * a[i][j]; + } + } + + for(int k = 0; k < n; k++){ + recv[k] = a[k][n]; + } + +} diff --git a/modules/twainui/gaosixy.h b/modules/twainui/gaosixy.h new file mode 100644 index 00000000..4b446756 --- /dev/null +++ b/modules/twainui/gaosixy.h @@ -0,0 +1,17 @@ +#ifndef GAOSIXY_H +#define GAOSIXY_H + +#include +#include + +class GaoSiXY +{ +public: + GaoSiXY(); + void solve(double **a,int n,double *recv);//用于计算曲线方程 + +private: + +}; + +#endif // GAOSIXY_H diff --git a/modules/twainui/hg_settingdialog.cpp b/modules/twainui/hg_settingdialog.cpp new file mode 100644 index 00000000..11b9539f --- /dev/null +++ b/modules/twainui/hg_settingdialog.cpp @@ -0,0 +1,1955 @@ +#include "hg_settingdialog.h" + +#include +#include +#include "cutpapertool.h" +#include "setpicclrtool.h" +#include "base/HGDef.h" +#include "base/HGUtility.h" +#include "HGString.h" +#include "sane/sane_option_definitions.h" +#include "lang/app_language.h" +#include "dialog_input.h" +#include +#include "device_menu.h" +#include "dialog_device_scan.h" + +std::string hg_settingdialog::property_combox_data_type_ = "combox_value_type"; + +hg_settingdialog::hg_settingdialog(SANE_Handle handle, const SANEAPI* saneApi, bool showScan, QWidget *parent) + : QDialog(parent) + , save_(false) + , btn_cut_area_(nullptr), btn_gamma_(nullptr), clicked_gamma_(false) + , custom_area_lable_(nullptr), comb_(nullptr) +{ + HGChar cfgpath[512] = {0}; + QString old; + HGBase_GetConfigPath(cfgpath, _countof(cfgpath) - 1); + HGBase_CreateDir(cfgpath); + dev_que_.set_root_dir(cfgpath); + old = QString::fromStdString(cfgpath) + PATH_SYMBOL + "scanner.schm"; + if(QFile::exists(old)) + dev_que::update_old_cfg(old.toStdString().c_str()); + + std::string n(dev_que_.opened_scanner_name()); + for(int i = 0; i < dev_que_.scanners(); ++i) + { + SCANNER s = dev_que_.get_at(i); + if(s.name == n) + { + cur_cfg_ = s.cfg; + break; + } + } + cur_scheme_ = cur_cfg_->get_scheme(); + if(!cur_scheme_) + cur_scheme_ = new gb::sane_config_schm(); + cur_scheme_->begin_setting(); + + m_dpiId = -1; + m_dpiValue = 200; + m_paperSizeId = -1; + m_paperSizeValue.clear(); + m_cutLeftId = -1; + m_cutTopId = -1; + m_cutRightId = -1; + m_cutBottomId = -1; + m_cutWidth = 210; + m_cutHeight = 297; + m_cutLeftValue = 0; + m_cutTopValue = 0; + m_cutRightValue = 210; + m_cutBottomValue = 297; + + m_colorModeId = -1; + m_colorModeValue.clear(); + memset(&m_gammaData, 0, sizeof(m_gammaData)); + for(int i = 0; i < sizeof(m_gammaData.table) / sizeof(m_gammaData.table[0]); ++i) + m_gammaData.table[i] = i & 0x0ff; + + memcpy(&m_saneAPI, saneApi, sizeof(SANEAPI)); + m_devHandle = handle; + m_showScan = showScan; + m_closeButton = closeButtonCancel; + + initUi(); + on_current_scheme_changed(); + getAppVersion(); +} + +hg_settingdialog::~hg_settingdialog() +{ + cur_scheme_->release(); + cur_cfg_->release(); +} + +void hg_settingdialog::initUi() +{ + updateOpt(); + createUI(); + +#if defined(OEM_ZHONGJING) + setWindowTitle("Microtek DocWizard EX TWAIN"); +#else + setWindowTitle(QString::fromStdString(dev_que_.opened_scanner_name())); +#endif + + setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); + resize(740, height()); +} + +void hg_settingdialog::updateOpt() +{ + bool first = true; + + m_list_defaultOptions.clear(); + + SANE_Int dev_options = 0; + m_saneAPI.sane_control_option_api(m_devHandle, 0, SANE_ACTION_GET_VALUE, &dev_options, nullptr); + for (int i = 1, j= dev_options; i < j; i++) + { + const SANE_Option_Descriptor* opt = m_saneAPI.sane_get_option_descriptor_api(m_devHandle, i); + SANE_Int method = 0; + if (opt == nullptr) + { + m_list_defaultOptions.append(QPair(opt, QVariant(0))); + } + else + { + if(opt->type == SANE_TYPE_INT) + { + SANE_Int init = 0; + + m_saneAPI.sane_control_option_api(m_devHandle, i, SANE_ACTION_GET_VALUE, &init, &method); + m_list_defaultOptions.append(QPair(opt, QVariant(init))); + + if(first) + { + unsigned int n = i; + m_saneAPI.sane_io_control_api(m_devHandle, IO_CTRL_CODE_GET_DEFAULT_VALUE, &init, &n); + cur_scheme_->set_default_value(i, opt->name, (char*)&init, sizeof(init)); + } + } + else if(opt->type == SANE_TYPE_FIXED) + { + SANE_Fixed init = 0; + + m_saneAPI.sane_control_option_api(m_devHandle, i, SANE_ACTION_GET_VALUE, &init, &method); + m_list_defaultOptions.append(QPair(opt, QVariant(init))); + + if(first) + { + unsigned int n = i; + m_saneAPI.sane_io_control_api(m_devHandle, IO_CTRL_CODE_GET_DEFAULT_VALUE, &init, &n); + cur_scheme_->set_default_value(i, opt->name, (char*)&init, sizeof(init)); + } + } + else if(opt->type == SANE_TYPE_BOOL) + { + SANE_Bool init = 0; + + m_saneAPI.sane_control_option_api(m_devHandle, i, SANE_ACTION_GET_VALUE, &init, &method); + m_list_defaultOptions.append(QPair(opt, QVariant(init))); + + if(first) + { + unsigned int n = i; + m_saneAPI.sane_io_control_api(m_devHandle, IO_CTRL_CODE_GET_DEFAULT_VALUE, &init, &n); + cur_scheme_->set_default_value(i, opt->name, (char*)&init, sizeof(init)); + } + } + else if(opt->type == SANE_TYPE_STRING) + { + char *init = (char*)malloc(opt->size * 2 + 4); + + m_saneAPI.sane_control_option_api(m_devHandle, i, SANE_ACTION_GET_VALUE, init, &method); + m_list_defaultOptions.append(QPair(opt, QVariant(QString::fromStdString(init)))); + + if(first) + { + unsigned int n = i; + int err = m_saneAPI.sane_io_control_api(m_devHandle, IO_CTRL_CODE_GET_DEFAULT_VALUE, init, &n); + (void)err; + std::string langCN(to_default_language(init, nullptr)); + cur_scheme_->set_default_value(i, opt->name, &langCN[0], langCN.length()); + } + free(init); + } + else + { + m_list_defaultOptions.append(QPair(opt, QVariant(0))); + } + } + } +} + +QString hg_settingdialog::find_current_scheme_menu(int *scheme_id) +{ + QString text(comb_->currentText()); + + if(scheme_id) + { + if(comb_->currentIndex() >= 0 && comb_->currentIndex() < comb_->count()) + *scheme_id = comb_->currentIndex(); + else { + *scheme_id = -1; + } + } + + return text; +} +void hg_settingdialog::create_scheme_management_ui(QVBoxLayout* layout) +{ + QLabel *title = new QLabel(this); + bool enabled = false; + QHBoxLayout *hbox = new QHBoxLayout(); + int width = 180; + std::vector schemes; + std::string cur_schm(cur_cfg_->get_current_scheme_name()); + + cur_cfg_->get_all_schemes(schemes); + comb_ = new QComboBox(this); + layout->addSpacing(30); + for(int i = 1; i < (int)schemes.size(); ++i) + { + comb_->addItem(QString::fromStdString(schemes[i])); + if(cur_schm == schemes[i]) + { + enabled = true; + comb_->setCurrentText(QString::fromStdString(schemes[i])); + } + } + + if(!enabled) + comb_->setCurrentIndex(-1); + + title->setFixedWidth(width); + comb_->setFixedWidth(width); + + title->setText(tr("existing configuration scheme")); + layout->addWidget(title); + layout->addWidget(comb_); + + rename_ = new QPushButton(this); + rename_->setText(tr("change name")); + rename_->setEnabled(enabled); + rename_->setFixedWidth(width/3); + hbox->addWidget(rename_); + connect(rename_, SIGNAL(clicked(bool)), this, SLOT(slot_pushButton_scheme_management())); + + del_this_ = new QPushButton(this); + del_this_->setText(tr("delete")); + del_this_->setEnabled(enabled); + del_this_->setFixedWidth(width / 3); + hbox->addWidget(del_this_); + connect(del_this_, SIGNAL(clicked(bool)), this, SLOT(slot_pushButton_scheme_management())); + + apply_ = new QPushButton(this); + apply_->setText(tr("apply")); + apply_->setEnabled(enabled); + apply_->setFixedWidth(width / 3); + hbox->addWidget(apply_); + connect(apply_, SIGNAL(clicked(bool)), this, SLOT(slot_pushButton_scheme_management())); + hbox->setSizeConstraint(QLayout::SetFixedSize); + + layout->addLayout(hbox); + layout->addSpacing(10); + + del_all_ = new QPushButton(this); + del_all_->setText(tr("delete all configurations")); + del_all_->setEnabled(enabled); + del_all_->setFixedWidth(width); + layout->addWidget(del_all_); + connect(del_all_, SIGNAL(clicked(bool)), this, SLOT(slot_pushButton_scheme_management())); + + layout->addStretch(); + + title = new QLabel(this); + title->setText(tr("confgiuration information:")); + layout->addWidget(title); + + sketch_ = new QTextEdit(this); + sketch_->setReadOnly(true); + sketch_->setFixedSize(width, 200); + layout->addWidget(sketch_); + + connect(comb_, SIGNAL(currentTextChanged(const QString)), this, SLOT(on_current_scheme_changed())); + on_current_scheme_changed(); +} +void hg_settingdialog::createUI() +{ + QTabWidget *tabWidgetCreation = new QTabWidget(this); + + QPushButton *buttonScan = new QPushButton(this); + buttonScan->setText(tr("scan")); + QPushButton *buttonOk = new QPushButton(this); + buttonOk->setText(tr("ok")); + QPushButton *buttonCancel = new QPushButton(this); + buttonCancel->setText(tr("cancel")); + QHBoxLayout *hlayoutOkAndCancel = new QHBoxLayout; + hlayoutOkAndCancel->addStretch(); + hlayoutOkAndCancel->addWidget(buttonScan); + hlayoutOkAndCancel->addWidget(buttonOk); + hlayoutOkAndCancel->addWidget(buttonCancel); + QWidget *widgetOkAndCancel = new QWidget(); + widgetOkAndCancel->setLayout(hlayoutOkAndCancel); + connect(buttonScan, SIGNAL(clicked(bool)), this, SLOT(slot_buttonScanClicked())); + connect(buttonOk, SIGNAL(clicked(bool)), this, SLOT(slot_buttonOkClicked())); + connect(buttonCancel, SIGNAL(clicked(bool)), this, SLOT(slot_buttonCancelClicked())); + + if (!m_showScan) + { + buttonScan->setVisible(false); + } + + QHBoxLayout *h = new QHBoxLayout(); + QVBoxLayout *v1 = new QVBoxLayout(), + *v2 = new QVBoxLayout(); + create_scheme_management_ui(v1); + v2->addWidget(tabWidgetCreation); + + QGroupBox *grp = new QGroupBox(tr("configuration scheme management"), this); + grp->setLayout(v1); + grp->setFixedSize(195, 500); + + h->addWidget(grp); + h->addLayout(v2); + + QVBoxLayout* mainVerticalLayout = new QVBoxLayout(this); + mainVerticalLayout->addLayout(h); +// mainVerticalLayout->addWidget(tabWidgetCreation); + mainVerticalLayout->addWidget(widgetOkAndCancel); + this->setLayout(mainVerticalLayout); + + QScrollArea* scrollArea = new QScrollArea; + scrollArea->setWidgetResizable(true); + scrollArea->setAlignment(Qt::AlignCenter); + QFormLayout* layout = new QFormLayout; + + QWidget* widget = new QWidget; + widget->setLayout(layout); + + bool isBegin = true; + std::string cur_val(""); + for (int i = 0; i < m_list_defaultOptions.size(); i++) + { + const SANE_Option_Descriptor* opt = reinterpret_cast(m_list_defaultOptions.at(i).first); + int ind = -1; + + if(opt == nullptr) continue; + h = nullptr; + cur_scheme_->get_config(opt->name, cur_val); + switch (opt->type) + { + case SANE_TYPE_BOOL: + { + QCheckBox *checkBoxCreation = new QCheckBox; + + if (strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA) == 0) + { + QWidget* widget_cbtn_pbtn = new QWidget; + widget_cbtn_pbtn->setMaximumWidth(200); + + QLabel *label = new QLabel; + label->setText(QString::fromStdString(opt->title) + QString(" : ")); + + btn_cut_area_ = new QPushButton; + btn_cut_area_->setText(tr("regional crop")); + btn_cut_area_->setFixedWidth(150); + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(checkBoxCreation); + hLayout->addWidget(btn_cut_area_); + widget_cbtn_pbtn->setLayout(hLayout); + + custom_area_lable_ = label; + + reinterpret_cast(widget->layout())->addRow(label, widget_cbtn_pbtn); + + connect(btn_cut_area_, SIGNAL(clicked(bool)), this, SLOT(slot_cutButtonClicked())); + } + else if (strcmp(opt->name, SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA) == 0) + { + QWidget* widget_cbtn_pbtn = new QWidget(scrollArea); + widget_cbtn_pbtn->setMaximumWidth(200); + btn_gamma_ = new QPushButton(widget_cbtn_pbtn); + btn_gamma_->setText(tr("custom tone curve")); + btn_gamma_->setFixedWidth(150); + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(checkBoxCreation); + hLayout->addWidget(btn_gamma_); + widget_cbtn_pbtn->setLayout(hLayout); + + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), widget_cbtn_pbtn); + connect(btn_gamma_, SIGNAL(clicked(bool)), this, SLOT(slot_gammaButtonClicked())); + } + else + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), checkBoxCreation); + + checkBoxCreation->setToolTip(opt->desc); + int id = i + 1; + bool enable = *(bool*)&cur_val[0]; + checkBoxCreation->setProperty("controls_id", id); + checkBoxCreation->setChecked(enable); + if (strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA) == 0) + btn_cut_area_->setEnabled(enable); + else if (strcmp(opt->name, SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA) == 0) + btn_gamma_->setEnabled(enable); + connect(checkBoxCreation, SIGNAL(stateChanged(int)), this, SLOT(slot_checkedClicked())); + m_list_widgets.append(checkBoxCreation); + + m_list_getOpt.append(QPair(id, opt)); + break; + } + + case SANE_TYPE_INT: + { + switch(opt->constraint_type) + { + case SANE_CONSTRAINT_NONE: + { + QSpinBox* spinBox = new QSpinBox(scrollArea); + spinBox->setMinimumWidth(150); + spinBox->setToolTip(opt->desc); + spinBox->setRange(1, 1000); + int id = i + 1; + spinBox->setProperty("controls_id", id); + + QHBoxLayout* hLayout = new QHBoxLayout; + hLayout->addWidget(spinBox); + hLayout->addStretch(); + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), spinBox); + + m_list_widgets.append(spinBox); + m_list_getOpt.append(QPair(id, opt)); + + spinBox->setValue(*(int*)&cur_val[0]); + connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(slot_spinBoxClicked(int))); + break; + } + + case SANE_CONSTRAINT_RANGE: + { + QWidget* widget_slider_spin = new QWidget(scrollArea); + widget_slider_spin->setMinimumWidth(300); + + QSlider* sliderCreation = new QSlider(widget_slider_spin); + sliderCreation->setOrientation(Qt::Horizontal); + sliderCreation->setMinimumWidth(120); + sliderCreation->setRange(opt->constraint.range->min, opt->constraint.range->max); + sliderCreation->setToolTip(opt->desc); + sliderCreation->setProperty("controls_id", i+1); + sliderCreation->setValue(m_list_defaultOptions.at(i).second.toInt()); + + QSpinBox* spinBox = new QSpinBox(widget_slider_spin); + spinBox->setMinimumWidth(150); + spinBox->setToolTip(opt->desc); + spinBox->setRange(opt->constraint.range->min, opt->constraint.range->max); + + spinBox->setSingleStep(1); + spinBox->setValue(m_list_defaultOptions.at(i).second.toInt()); + int id = i + 1; + spinBox->setProperty("controls_id", id); + m_list_sliderSpinbox.append(QPair(sliderCreation, spinBox)); + + QHBoxLayout* hLayout = new QHBoxLayout; + hLayout->addWidget(sliderCreation); + hLayout->addWidget(spinBox); +// hLayout->addStretch(); + widget_slider_spin->setLayout(hLayout); + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), widget_slider_spin); + + m_list_widgets.append(sliderCreation); + m_list_widgets.append(spinBox); + m_list_getOpt.append(QPair(id, opt)); + + int cur = *(int*)&cur_val[0]; + spinBox->setValue(cur); + sliderCreation->setValue(cur); + + connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(slot_spinBoxClicked(int))); + connect(sliderCreation, SIGNAL(valueChanged(int)), this, SLOT(slot_sliderClicked(int))); + + break; + } + + case SANE_CONSTRAINT_WORD_LIST: + { + QComboBox* comboBoxCreation = new QComboBox(scrollArea); + comboBoxCreation->setToolTip(opt->desc); + int id = i + 1; + comboBoxCreation->setProperty("controls_id", id); + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), comboBoxCreation); + + auto p_str = opt->constraint.word_list; + char buf[20]; + for(SANE_Int i = 0; i < p_str[0]; ++i) + { + sprintf(buf, "%d", p_str[i + 1]); + comboBoxCreation->addItem(QString::fromStdString(buf)); + } + sprintf(buf, "%d", m_list_defaultOptions.at(i).second.toInt()); + comboBoxCreation->setProperty(hg_settingdialog::property_combox_data_type_.c_str(), COMBO_VAL_INT); + m_list_widgets.append(comboBoxCreation); + m_list_getOpt.append(QPair(id, opt)); + + char nstr[40] = {0}; + sprintf(nstr, "%d", *(int*)&cur_val[0]); + comboBoxCreation->setCurrentText(QString::fromStdString(nstr)); + connect(comboBoxCreation, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + break; + } + + case SANE_CONSTRAINT_STRING_LIST: + break; + } + break; + } + + case SANE_TYPE_FIXED: + { + QWidget* widget_slider_spin = new QWidget(scrollArea); + widget_slider_spin->setMinimumWidth(300); + QSlider* sliderCreation = new QSlider(widget_slider_spin); + sliderCreation->setOrientation(Qt::Horizontal); + sliderCreation->setMinimumWidth(120); + sliderCreation->setToolTip(opt->desc); + int id = i + 1; + sliderCreation->setProperty("controls_id", id); + sliderCreation->setRange(SANE_UNFIX(opt->constraint.range->min) * 100, SANE_UNFIX(opt->constraint.range->max) * 100); + sliderCreation->setValue(SANE_UNFIX(m_list_defaultOptions.at(i).second.toDouble()) * 100); + + QDoubleSpinBox* spinBox = new QDoubleSpinBox(widget_slider_spin); + spinBox->setMinimumWidth(150); + spinBox->setToolTip(opt->desc); + spinBox->setDecimals(2); + spinBox->setSingleStep(0.01); + spinBox->setRange(SANE_UNFIX(opt->constraint.range->min), SANE_UNFIX(opt->constraint.range->max)); + spinBox->setValue(sliderCreation->value() * spinBox->singleStep()); + spinBox->setProperty("controls_id", id); + + m_list_sliderSpinbox.append(QPair(sliderCreation, spinBox)); + + QHBoxLayout* hLayout = new QHBoxLayout; + hLayout->addWidget(sliderCreation); + hLayout->addWidget(spinBox); +// hLayout->addStretch(); + widget_slider_spin->setLayout(hLayout); + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), widget_slider_spin); + + m_list_widgets.append(sliderCreation); + m_list_widgets.append(spinBox); + + m_list_getOpt.append(QPair(id, opt)); +// iniRead(md5(opt->title), id, sliderCreation); +// iniRead(md5(opt->title), id, spinBox); + + float v = SANE_UNFIX(*(SANE_Fixed*)&cur_val[0]); + sliderCreation->setValue(v * 100); + spinBox->setValue(sliderCreation->value() * spinBox->singleStep()); + connect(spinBox, SIGNAL(valueChanged(double)), this, SLOT(slot_doubleSpinboxClicked(double))); + connect(sliderCreation, SIGNAL(valueChanged(int)), this, SLOT(slot_sliderClicked(int))); + break; + } + + case SANE_TYPE_STRING: + { + switch(opt->constraint_type) + { + case SANE_CONSTRAINT_NONE: + { + QLineEdit *lineEdit = new QLineEdit(scrollArea); + lineEdit->setToolTip(opt->desc); + int id = i + 1; + lineEdit->setProperty("controls_id", id); + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), lineEdit); + + m_list_widgets.append(lineEdit); + m_list_getOpt.append(QPair(id, opt)); +// iniRead(md5(opt->title), id, lineEdit); + + lineEdit->setText(QString::fromStdString(cur_val)); + connect(lineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slot_lineEditInput())); + break; + } + + case SANE_CONSTRAINT_RANGE: + break; + case SANE_CONSTRAINT_WORD_LIST: + break; + + case SANE_CONSTRAINT_STRING_LIST: + { + QComboBox* comboBoxCreation = new QComboBox(scrollArea); + comboBoxCreation->setToolTip(opt->desc); + int id = i + 1; + comboBoxCreation->setProperty("controls_id", id); + reinterpret_cast(widget->layout())->addRow(opt->title + QString(" : "), comboBoxCreation); + + auto p_str = opt->constraint.string_list; + QStringList stringList; + while(*p_str) + { + stringList.append(*p_str); + p_str++; + } + + if(stringList.isEmpty() != true) + { + for(int i = 0; i < (stringList.size()); i++) + comboBoxCreation->addItem(stringList.at(i)); + } + comboBoxCreation->setCurrentText(m_list_defaultOptions.at(i).second.toString()); + comboBoxCreation->setProperty(hg_settingdialog::property_combox_data_type_.c_str(), COMBO_VAL_STRING); + //printf("Option %02d default value is: %s\n", i + 1, m_list_defaultOptions.at(i).second.toString().data()); + + m_list_widgets.append(comboBoxCreation); + + m_list_getOpt.append(QPair(id, opt)); +// iniRead(md5(opt->title), id, comboBoxCreation); + + comboBoxCreation->setCurrentText(QString::fromStdString(cur_val)); + connect(comboBoxCreation, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + break; + } + } + break; + } + + case SANE_TYPE_BUTTON: + { + QPushButton* pushButton = new QPushButton(this); + pushButton->setText(opt->title); + pushButton->setToolTip(opt->desc); + int id = i + 1; + pushButton->setProperty("controls_id", id); + hlayoutOkAndCancel->insertWidget(0, pushButton, 0, Qt::AlignRight); + + connect(pushButton, SIGNAL(clicked(bool)), this, SLOT(slot_pushButtonClicked())); + break; + } + + case SANE_TYPE_GROUP: + { + if (isBegin) + { + scrollArea->setWindowTitle(opt->title); + isBegin = false; + }else{ + scrollArea->setWidget(widget); + tabWidgetCreation->addTab(scrollArea, scrollArea->windowTitle()); + scrollArea = new QScrollArea; + scrollArea->setWidgetResizable(true); + scrollArea->setWindowTitle(opt->title); + layout = new QFormLayout; + widget = new QWidget; + widget->setLayout(layout); + } + + m_list_widgets.append(nullptr); + break; + } + } //switch(opt->type) + +// if (Utf8ToStdString(opt->title) == "分辨率") + if (strcmp(opt->name, SANE_STD_OPT_NAME_RESOLUTION) == 0) + { + m_dpiId = i + 1; + m_dpiValue = m_list_defaultOptions.at(i).second.toInt(); + } +// else if (Utf8ToStdString(opt->title) == "纸张尺寸") + else if (strcmp(opt->name, SANE_STD_OPT_NAME_PAPER) == 0) + { + m_paperSizeId = i + 1; + m_paperSizeValue = m_list_defaultOptions.at(i).second.toString(); + } + + if (0 == strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT)) + { + m_cutLeftId = i + 1; + m_cutLeftValue = SANE_UNFIX(m_list_defaultOptions.at(i).second.toInt()); + if (opt->constraint_type == SANE_CONSTRAINT_RANGE) + m_cutWidth = SANE_UNFIX(opt->constraint.range->max); + } + else if (0 == strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_TOP)) + { + m_cutTopId = i + 1; + m_cutTopValue = SANE_UNFIX(m_list_defaultOptions.at(i).second.toInt()); + if (opt->constraint_type == SANE_CONSTRAINT_RANGE) + m_cutHeight = SANE_UNFIX(opt->constraint.range->max); + } + else if (0 == strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT)) + { + m_cutRightId = i + 1; + m_cutRightValue = SANE_UNFIX(m_list_defaultOptions.at(i).second.toInt()); + } + else if (0 == strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM)) + { + m_cutBottomId = i + 1; + m_cutBottomValue = SANE_UNFIX(m_list_defaultOptions.at(i).second.toInt()); + } + +// else if (Utf8ToStdString(opt->title) == "颜色模式") + if (strcmp(opt->name, SANE_STD_OPT_NAME_COLOR_MODE) == 0) + { + m_colorModeId = i + 1; + m_colorModeValue = m_list_defaultOptions.at(i).second.toString(); + } +// else if (Utf8ToStdString(opt->title) == "伽玛" || Utf8ToStdString(opt->title) == "伽玛值") + + } //for + + updateUIStatus(); + + scrollArea->setWidget(widget); + tabWidgetCreation->addTab(scrollArea, scrollArea->windowTitle()); +} + +void hg_settingdialog::refresh_control_value(int op_id) +{ + QVector ctrls = find_control(op_id); + + if(ctrls.empty()) + return; + + const SANE_Option_Descriptor* opt = (const SANE_Option_Descriptor*)m_list_defaultOptions.at(op_id - 1).first; + if(opt->type == SANE_TYPE_BOOL) + { + for(size_t i = 0; i < (size_t)ctrls.size(); ++i) + { + QCheckBox* cb = qobject_cast(ctrls[i]); + if(cb) + { + disconnect(cb, SIGNAL(stateChanged(int)), this, SLOT(slot_checkedClicked())); + cb->setChecked(m_list_defaultOptions.at(op_id - 1).second.toBool()); + connect(cb, SIGNAL(stateChanged(int)), this, SLOT(slot_checkedClicked())); + break; + } + } + } + else if(opt->type == SANE_TYPE_INT) + { + for(size_t i = 0; i < (size_t)ctrls.size(); ++i) + { + QComboBox* comb = qobject_cast(ctrls[i]); + if(comb) + { + char buf[40] = {0}; + sprintf(buf, "%d", m_list_defaultOptions.at(op_id - 1).second.toInt()); + comb->disconnect(comb, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + comb->setCurrentText(QString::fromStdString(buf)); + connect(comb, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + } + else + { + QSlider* slider = qobject_cast(ctrls[i]); + if(slider) + { + disconnect(slider, SIGNAL(valueChanged(int)), this, SLOT(slot_sliderClicked(int))); + slider->setValue(m_list_defaultOptions.at(op_id - 1).second.toInt()); + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(slot_sliderClicked(int))); + } + else + { + QSpinBox* spin = qobject_cast(ctrls[i]); + if(spin) + { + disconnect(spin, SIGNAL(valueChanged(int)), this, SLOT(slot_spinBoxClicked(int))); + spin->setValue(m_list_defaultOptions.at(op_id - 1).second.toInt()); + connect(spin, SIGNAL(valueChanged(int)), this, SLOT(slot_spinBoxClicked(int))); + } + } + } + } + } + else if(opt->type == SANE_TYPE_FIXED) + { + double val = SANE_UNFIX(m_list_defaultOptions.at(op_id - 1).second.toInt()); + QSlider *slider = NULL; + QDoubleSpinBox* spin = NULL; + for(size_t i = 0; i < (size_t)ctrls.size(); ++i) + { + QComboBox* comb = qobject_cast(ctrls[i]); + if(comb) + { + char buf[40] = {0}; + sprintf(buf, "%f", val); + comb->disconnect(comb, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + comb->setCurrentText(QString::fromStdString(buf)); + connect(comb, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + } + else if(!slider) + { + slider = qobject_cast(ctrls[i]); + if(slider) + disconnect(slider, SIGNAL(valueChanged(int)), this, SLOT(slot_sliderClicked(int))); + } + else if(!spin) + { + spin = qobject_cast(ctrls[i]); + if(spin) + disconnect(spin, SIGNAL(valueChanged(double)), this, SLOT(slot_spinBoxClicked(double))); + } + } + if(slider) + slider->setValue(val * 100); + if(spin) + spin->setValue(val); + if(slider) + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(slot_sliderClicked(int))); + if(spin) + connect(spin, SIGNAL(valueChanged(double)), this, SLOT(slot_spinBoxClicked(double))); + } + else if(opt->type == SANE_TYPE_STRING) + { + for(size_t i = 0; i < (size_t)ctrls.size(); ++i) + { + QComboBox* comb = qobject_cast(ctrls[i]); + if(comb) + { + disconnect(comb, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + comb->setCurrentText(m_list_defaultOptions.at(op_id - 1).second.toString()); + // comb->setProperty(hg_settingdialog::property_combox_data_type_.c_str(), COMBO_VAL_STRING); + connect(comb, SIGNAL(currentTextChanged(const QString)), this, SLOT(slot_string_list_comboBoxClicked())); + } + else + { + QLineEdit* edit = qobject_cast(ctrls[i]); + if(edit) + { + disconnect(edit, SIGNAL(textChanged(const QString&)), this, SLOT(slot_lineEditInput())); + edit->setText(m_list_defaultOptions.at(op_id - 1).second.toString()); + connect(edit, SIGNAL(textChanged(const QString&)), this, SLOT(slot_lineEditInput())); + } + } + } + } +} +QVector hg_settingdialog::find_control(int opt_num) +{ + QVector list_w; + for(int i = 0; i< m_list_widgets.size(); i++) + { + if (m_list_widgets.at(i) == nullptr) continue; + QWidget* w = m_list_widgets.at(i); + int id = w->property("controls_id").toInt(); + if(opt_num == id) + list_w.append(w); + } + return list_w; +} + +void hg_settingdialog::updateUIStatus() +{ + updateOpt(); + + SANE_Int dev_options = 0; + m_saneAPI.sane_control_option_api(m_devHandle, 0, SANE_ACTION_GET_VALUE, &dev_options, nullptr); + for(int id = 1, optons = dev_options; id < optons; id++) + { + QVector list_widgets = find_control(id); + if (list_widgets.empty()) continue; + QWidget* widget = list_widgets.first(); + if (widget == nullptr) continue; + QWidget* parentWidget = widget->parentWidget(); + + while (parentWidget->layout() && + typeid(*(parentWidget->layout())) != typeid(QFormLayout)) + { + widget = parentWidget; + parentWidget = widget->parentWidget(); + } + + QFormLayout* layout = reinterpret_cast(parentWidget->layout()); + const SANE_Option_Descriptor* opt = reinterpret_cast(m_list_defaultOptions.at(id - 1).first); + bool hide = (opt->cap & SANE_CAP_INACTIVE) == SANE_CAP_INACTIVE; + QWidget* w_label = layout ? layout->labelForField(widget) : nullptr; + + if( strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT) == 0 || + strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_TOP) == 0 || + strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT) == 0 || + strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM) == 0 ) + hide = true; + + refresh_control_value(id); + if(w_label) + hide ? w_label->hide() : w_label->show(); + widget->setVisible(!hide); + if(strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA) == 0) + { + if(hide) + { + custom_area_lable_->hide(); + btn_cut_area_->hide(); + } + else + { + custom_area_lable_->show(); + btn_cut_area_->show(); + } + } + } +} + +void hg_settingdialog::slot_checkedClicked() +{ + QCheckBox *checkBox = qobject_cast(sender()); + SANE_Int id = checkBox->property("controls_id").toInt(); + SANE_Bool checkBoxcurrentState = checkBox->isChecked(); + + const SANE_Option_Descriptor* opt = nullptr; + for(int i = 0; i < m_list_getOpt.size(); i++) + if (m_list_getOpt.at(i).first == id) + { + opt = reinterpret_cast(m_list_getOpt.at(i).second); + break; + } + + m_list_IdValueTitle.append(QPair, QString>(QPair(id, checkBoxcurrentState), md5(opt->title))); + + SANE_Int method = 0; + m_saneAPI.sane_control_option_api(m_devHandle, id, SANE_ACTION_SET_VALUE, &checkBoxcurrentState, &method); + if((method & SANE_INFO_RELOAD_OPTIONS) == SANE_INFO_RELOAD_OPTIONS) + updateUIStatus(); + else if(method & SANE_INFO_INEXACT) + checkBox->setCheckState(checkBoxcurrentState ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + + if(strcmp(opt->name, SANE_STD_OPT_NAME_CUSTOM_AREA) == 0) + btn_cut_area_->setEnabled(checkBoxcurrentState); + else if (strcmp(opt->name, SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA) == 0) + btn_gamma_->setEnabled(checkBoxcurrentState); + cur_scheme_->config_changed(id, (char*)&checkBoxcurrentState, sizeof(checkBoxcurrentState)); +} + +void hg_settingdialog::slot_string_list_comboBoxClicked() +{ + QComboBox *comboBox = qobject_cast(sender()); + SANE_Int id = comboBox->property("controls_id").toInt(); + std::string comboBoxcurrentItem(comboBox->currentText().toUtf8()); + int type = comboBox->property(hg_settingdialog::property_combox_data_type_.c_str()).toInt(); + + if (id == m_dpiId) + { + m_dpiValue = atoi(comboBoxcurrentItem.c_str()); + qDebug("dpi=%d", m_dpiValue); + } + else if (id == m_paperSizeId) + { + m_paperSizeValue = comboBoxcurrentItem.c_str(); + qDebug("paperSize=%s", comboBoxcurrentItem.c_str()); + } + else if (id == m_colorModeId) + { + m_colorModeValue = comboBoxcurrentItem.c_str(); + qDebug("colorMode=%s", comboBoxcurrentItem.c_str()); + } + + const SANE_Option_Descriptor* opt = nullptr; + for(int i = 0; i < m_list_getOpt.size(); i++) + if (m_list_getOpt.at(i).first == id) + { + opt = reinterpret_cast(m_list_getOpt.at(i).second); + break; + } + + m_list_IdValueTitle.append(QPair, QString>(QPair(id, &comboBoxcurrentItem.at(0)), md5(opt->title))); + + SANE_Int method = 0; + SANE_String buf = (SANE_String)malloc(opt->size * 2 + 4); + if(type == COMBO_VAL_INT) + *((SANE_Int*)buf) = atoi(comboBoxcurrentItem.c_str()); + else if(type == COMBO_VAL_FLOAT) + *((SANE_Fixed*)buf) = SANE_FIX(atof(comboBoxcurrentItem.c_str())); + else + strcpy(buf, comboBoxcurrentItem.c_str()); + m_saneAPI.sane_control_option_api(m_devHandle, id, SANE_ACTION_SET_VALUE, buf, &method); + if((method & SANE_INFO_RELOAD_OPTIONS) == SANE_INFO_RELOAD_OPTIONS) + updateUIStatus(); + else if(method & SANE_INFO_INEXACT) + comboBox->setCurrentText(QString::fromStdString(buf)); + + if(type == COMBO_VAL_INT) + cur_scheme_->config_changed(id, buf, sizeof(SANE_Int)); + else if(type == COMBO_VAL_FLOAT) + cur_scheme_->config_changed(id, buf, sizeof(SANE_Fixed)); + else + { + std::string langCN(to_default_language(buf, nullptr)); + cur_scheme_->config_changed(id, &langCN[0], langCN.length()); + } + free(buf); +} + +void hg_settingdialog::slot_pushButtonClicked() +{ + QPushButton *pushButton = qobject_cast(sender()); + SANE_Int id = pushButton->property("controls_id").toInt(), + after = 0; + + // restore to default setting ? + m_saneAPI.sane_control_option_api(m_devHandle, id, SANE_ACTION_SET_VALUE, NULL, &after); + if((after & SANE_INFO_RELOAD_OPTIONS) == SANE_INFO_RELOAD_OPTIONS) + updateUIStatus(); + + const SANE_Option_Descriptor* opt = m_saneAPI.sane_get_option_descriptor_api(m_devHandle, id); + if(opt && strcmp(opt->name, SANE_STD_OPT_NAME_RESTORE) == 0) + { + restore_2_default_settings(); + } +} + +void hg_settingdialog::slot_cutButtonClicked() +{ + //int width = 0.03937 * m_cutWidth * m_dpiValue; + //int height = 0.03937 * m_cutHeight * m_dpiValue; + int left = 0.03937 * m_cutLeftValue * m_dpiValue; + int top = 0.03937 * m_cutTopValue * m_dpiValue; + int right = 0.03937 * m_cutRightValue * m_dpiValue; + int bottom = 0.03937 * m_cutBottomValue * m_dpiValue; + + CutPaperTool dlg(this); + dlg.setPaperType(m_dpiValue, m_paperSizeValue, 300); + QRectF rc(left, top, right - left, bottom - top); + dlg.setCutRect(rc); + if (dlg.exec()) + { + QRectF rcRet = dlg.getCutRectPixel(); + + m_cutLeftValue = rcRet.left() / (0.03937 * m_dpiValue); + m_cutTopValue = rcRet.top() / (0.03937 * m_dpiValue); + m_cutRightValue = rcRet.right() / (0.03937 * m_dpiValue); + m_cutBottomValue = rcRet.bottom() / (0.03937 * m_dpiValue); + + SANE_Int info; + SANE_Word value = SANE_FIX(m_cutLeftValue); + m_saneAPI.sane_control_option_api(m_devHandle, m_cutLeftId, SANE_ACTION_SET_VALUE, &value, &info); + cur_scheme_->config_changed(m_cutLeftId, (char*)&value, sizeof(value)); + value = SANE_FIX(m_cutTopValue); + m_saneAPI.sane_control_option_api(m_devHandle, m_cutTopId, SANE_ACTION_SET_VALUE, &value, &info); + cur_scheme_->config_changed(m_cutTopId, (char*)&value, sizeof(value)); + value = SANE_FIX(m_cutRightValue); + m_saneAPI.sane_control_option_api(m_devHandle, m_cutRightId, SANE_ACTION_SET_VALUE, &value, &info); + cur_scheme_->config_changed(m_cutRightId, (char*)&value, sizeof(value)); + value = SANE_FIX(m_cutBottomValue); + m_saneAPI.sane_control_option_api(m_devHandle, m_cutBottomId, SANE_ACTION_SET_VALUE, &value, &info); + cur_scheme_->config_changed(m_cutBottomId, (char*)&value, sizeof(value)); + } +} + +void hg_settingdialog::slot_gammaButtonClicked() +{ + setPicClrTool dlg(this); + + int colorMode; // 0-彩色, 1-灰度 + if (m_colorModeValue.toStdString() == OPTION_VALUE_YSMS_256JHD + || m_colorModeValue.toStdString() == OPTION_VALUE_YSMS_HB) + { + colorMode = 1; + + QList keyTable; + for (int i = 0; i < m_gammaData.pt_count; ++i) + { + QPoint pt(m_gammaData.keypoint[i].x, m_gammaData.keypoint[i].y); + keyTable.append(pt); + } + + if (!keyTable.empty()) + { + dlg.setGrayKeyTable(keyTable); + } + } + else + { + colorMode = 0; + + QList keyTable; + for (int i = 0; i < m_gammaData.pt_count; ++i) + { + QPoint pt(m_gammaData.keypoint[i].x, m_gammaData.keypoint[i].y); + keyTable.append(pt); + } + + QList rKeyTable; + for (int i = 0; i < m_gammaData.pt_count_r; ++i) + { + QPoint pt(m_gammaData.keypoint_r[i].x, m_gammaData.keypoint_r[i].y); + rKeyTable.append(pt); + } + + QList gKeyTable; + for (int i = 0; i < m_gammaData.pt_count_g; ++i) + { + QPoint pt(m_gammaData.keypoint_g[i].x, m_gammaData.keypoint_g[i].y); + gKeyTable.append(pt); + } + + QList bKeyTable; + for (int i = 0; i < m_gammaData.pt_count_b; ++i) + { + QPoint pt(m_gammaData.keypoint_b[i].x, m_gammaData.keypoint_b[i].y); + bKeyTable.append(pt); + } + + QVector> keyTableList; + if (!keyTable.empty() && !rKeyTable.empty() && !gKeyTable.empty() && !bKeyTable.empty()) + { + keyTableList.append(keyTable); + keyTableList.append(rKeyTable); + keyTableList.append(gKeyTable); + keyTableList.append(bKeyTable); + dlg.setRGBKeyTable(keyTableList); + } + } + + dlg.setColorMode(colorMode); + if (dlg.exec()) + { + memset(&m_gammaData, 0, sizeof(m_gammaData)); + clicked_gamma_ = true; + + if (1 == colorMode) + { + QList keyTable = dlg.getGrayKeyTable(); + + m_gammaData.pt_count = HGMIN(4, keyTable.size()); + int i = 0; + for (QPoint pt : keyTable) + { + if (i >= 4) + break; + + m_gammaData.keypoint[i].x = pt.x(); + m_gammaData.keypoint[i].y = pt.y(); + ++i; + } + + uchar data[256]; + dlg.getGrayTable(data, 256); + for (int i = 0; i < 256; ++i) + { + m_gammaData.table[i] = data[i]; + } + } + else + { + QVector> keyTableList = dlg.getRGBKeyTable(); + + m_gammaData.pt_count = HGMIN(4, keyTableList[0].size()); + int i = 0; + for (QPoint pt : keyTableList[0]) + { + if (i >= 4) + break; + + m_gammaData.keypoint[i].x = pt.x(); + m_gammaData.keypoint[i].y = pt.y(); + ++i; + } + + m_gammaData.pt_count_r = HGMIN(4, keyTableList[1].size()); + i = 0; + for (QPoint pt : keyTableList[1]) + { + if (i >= 4) + break; + + m_gammaData.keypoint_r[i].x = pt.x(); + m_gammaData.keypoint_r[i].y = pt.y(); + ++i; + } + + m_gammaData.pt_count_g = HGMIN(4, keyTableList[2].size()); + i = 0; + for (QPoint pt : keyTableList[2]) + { + if (i >= 4) + break; + + m_gammaData.keypoint_g[i].x = pt.x(); + m_gammaData.keypoint_g[i].y = pt.y(); + ++i; + } + + m_gammaData.pt_count_b = HGMIN(4, keyTableList[3].size()); + i = 0; + for (QPoint pt : keyTableList[3]) + { + if (i >= 4) + break; + + m_gammaData.keypoint_b[i].x = pt.x(); + m_gammaData.keypoint_b[i].y = pt.y(); + ++i; + } + + uchar data[256 * 3]; + dlg.getRGBTable(data, 256 * 3); + for (int i = 0; i < 256; ++i) + { + m_gammaData.table[i] = data[i * 3 + 2]; + m_gammaData.table[i + 256] = data[i * 3 + 1]; + m_gammaData.table[i + 512] = data[i * 3 + 0]; + } + } + + unsigned int len = sizeof(SANE_Gamma); + m_saneAPI.sane_io_control_api(m_devHandle, IO_CTRL_CODE_SET_CUSTOM_GAMMA, &m_gammaData, &len); + cur_scheme_->config_changed(SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA, (char*)&m_gammaData, sizeof(m_gammaData), true); + } +} + +void hg_settingdialog::slot_word_list_comboBoxClicked(int value) +{ + QComboBox *comboBox = qobject_cast(sender()); + SANE_Int id = comboBox->property("controls_id").toInt(); + SANE_Int temp = value; + + const SANE_Option_Descriptor* opt = nullptr; + for(int i = 0; i < m_list_getOpt.size(); i++) + if (m_list_getOpt.at(i).first == id) + { + opt = reinterpret_cast(m_list_getOpt.at(i).second); + break; + } + m_list_IdValueTitle.append(QPair, QString>(QPair(id, temp), md5(opt->title))); + + + SANE_Int method = 0; + m_saneAPI.sane_control_option_api(m_devHandle, id, SANE_ACTION_SET_VALUE, &temp, &method); + if((method & SANE_INFO_RELOAD_OPTIONS) == SANE_INFO_RELOAD_OPTIONS) + updateUIStatus(); + else if(method & SANE_INFO_INEXACT) + { + char buf[20]; + sprintf(buf, "%d", temp); + comboBox->setCurrentText(QString::fromStdString(buf)); + } + cur_scheme_->config_changed(id, (char*)&temp, sizeof(temp)); +} + +void hg_settingdialog::slot_sliderClicked(int value) +{ + QSlider *slider = qobject_cast(sender()); + SANE_Int id = slider->property("controls_id").toInt(); + + const SANE_Option_Descriptor* opt = nullptr; + for(int i = 0; i < m_list_getOpt.size(); i++) + if (m_list_getOpt.at(i).first == id) + { + opt = reinterpret_cast(m_list_getOpt.at(i).second); + break; + } + + QAbstractSpinBox* spin = nullptr; + for(int i = 0; i < m_list_sliderSpinbox.size(); i++) + if (m_list_sliderSpinbox.at(i).first == slider) + { + spin = reinterpret_cast(m_list_sliderSpinbox.at(i).second); + break; + } + + if (spin != nullptr) + { + SANE_Int val = value, method = 0; + bool db_val = false; + if (typeid(*spin) == typeid(QSpinBox)) + { + QSpinBox* spin_ = reinterpret_cast(spin); + spin_->setValue(value); + + m_list_IdValueTitle.append(QPair, QString>(QPair(id, val), md5(opt->title))); + } + else + { + QDoubleSpinBox* spin_ = reinterpret_cast(spin); + double temp = value * spin_->singleStep(); + if(temp != spin_->value()) + spin_->setValue(temp); + + val = SANE_FIX(temp); + db_val = true; + + m_list_IdValueTitle.append(QPair, QString>(QPair(id, temp), md5(opt->title))); + } + m_saneAPI.sane_control_option_api(m_devHandle, id, SANE_ACTION_SET_VALUE, &val, &method); + if((method & SANE_INFO_RELOAD_OPTIONS) == SANE_INFO_RELOAD_OPTIONS) + updateUIStatus(); + else if(method & SANE_INFO_INEXACT) + { + if(db_val) + { + QDoubleSpinBox* spin_ = reinterpret_cast(spin); + double v = SANE_UNFIX(val); + spin_->setValue(v); + slider->setValue(spin_->value() / spin_->singleStep()); + } + else { + QSpinBox* spin_ = reinterpret_cast(spin); + spin_->setValue(val); + slider->setValue(spin_->value() / spin_->singleStep()); + } + } + cur_scheme_->config_changed(id, (char*)&val, sizeof(val)); + } +} + +void hg_settingdialog::slot_doubleSpinboxClicked(double value) +{ + QDoubleSpinBox* spinBox = qobject_cast(sender()); + QAbstractSlider* slider = nullptr; + int id = spinBox->property("controls_id").toInt(); + for (int i = 0; i < m_list_sliderSpinbox.size(); i++) + if (m_list_sliderSpinbox.at(i).second == spinBox) + { + slider = reinterpret_cast(m_list_sliderSpinbox.at(i).first); + break; + } + if(slider != nullptr) + { + int temp = static_cast(value / spinBox->singleStep() + 0.5); + QSlider* slider_ = reinterpret_cast(slider); + if (slider_->value() != temp) + slider_->setValue(temp); + } +} + +void hg_settingdialog::slot_spinBoxClicked(int value) +{ + QSpinBox* spinBox = qobject_cast(sender()); + int id = spinBox->property("controls_id").toInt(); + + const SANE_Option_Descriptor* opt = nullptr; + for(int i = 0; i < m_list_getOpt.size(); i++) + if (m_list_getOpt.at(i).first == id) + { + opt = reinterpret_cast(m_list_getOpt.at(i).second); + break; + } + + QAbstractSlider* slider = nullptr; + for (int i = 0; i < m_list_sliderSpinbox.size(); i++) + if (m_list_sliderSpinbox.at(i).second == spinBox) + { + slider = reinterpret_cast(m_list_sliderSpinbox.at(i).first); + break; + } + if(slider == nullptr) + { + SANE_Int temp = value; + + m_list_IdValueTitle.append(QPair, QString>(QPair(id, temp), md5(opt->title))); + + SANE_Int method = 0; + m_saneAPI.sane_control_option_api(m_devHandle, id, SANE_ACTION_SET_VALUE, &temp, &method); + if((method & SANE_INFO_RELOAD_OPTIONS) == SANE_INFO_RELOAD_OPTIONS) + updateUIStatus(); + else if(value != temp) + { + disconnect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(slot_spinBoxClicked(int))); + spinBox->setValue(temp); + connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(slot_spinBoxClicked(int))); + } + cur_scheme_->config_changed(id, (char*)&temp, sizeof(temp)); + }else + { + QSlider* slider_ = reinterpret_cast(slider); + slider_->setValue(spinBox->value()); + } +} + +void hg_settingdialog::slot_lineEditInput() +{ + QLineEdit* lineEdit = qobject_cast(sender()); + int id = lineEdit->property("controls_id").toInt(); + std::string lineEditCurrentText(lineEdit->text().toUtf8()); + + const SANE_Option_Descriptor* opt = nullptr; + for(int i = 0; i < m_list_getOpt.size(); i++) + if (m_list_getOpt.at(i).first == id) + { + opt = reinterpret_cast(m_list_getOpt.at(i).second); + break; + } + + m_list_IdValueTitle.append(QPair, QString>(QPair(id, &lineEditCurrentText.at(0)), md5(opt->title))); + + SANE_Int method = 0; + void *buf = NULL; + SANE_Int nv = 0; + if(opt->type == SANE_TYPE_INT) + { + nv = atoi(lineEditCurrentText.c_str()); + buf = &nv; + } + else if(opt->type == SANE_TYPE_FIXED) + { + nv = SANE_FIX(atof(lineEditCurrentText.c_str())); + buf = &nv; + } + else + { + buf = malloc(opt->size * 2 + 4); + strcpy((char*)buf, lineEditCurrentText.c_str()); + } + m_saneAPI.sane_control_option_api(m_devHandle, id, SANE_ACTION_SET_VALUE, buf, &method); + if((method & SANE_INFO_RELOAD_OPTIONS) == SANE_INFO_RELOAD_OPTIONS) + updateUIStatus(); + else if(method & SANE_INFO_INEXACT) + { + char mem[20], *v = mem; + if(opt->type == SANE_TYPE_INT) + sprintf(mem, "%d", nv); + else if(opt->type == SANE_TYPE_FIXED) + sprintf(mem, "%f", SANE_UNFIX(nv)); + else + v = (char*)buf; + lineEdit->setText(QString::fromStdString(v)); + } + + if(opt->type == SANE_TYPE_INT || opt->type == SANE_TYPE_FIXED) + { + cur_scheme_->config_changed(id, (char*)buf, sizeof(SANE_Int)); + } + else + { + std::string langCN(to_default_language((char*)buf, nullptr)); + cur_scheme_->config_changed(id, &langCN[0], langCN.length()); + free(buf); + } +} + +void hg_settingdialog::slot_buttonScanClicked() +{ + save_scheme(); + m_closeButton = closeButtonScan; + close(); +} + +void hg_settingdialog::slot_buttonOkClicked() +{ + save_ = true; + m_closeButton = closeButtonOk; + close(); +} + +void hg_settingdialog::slot_buttonCancelClicked() +{ + m_closeButton = closeButtonCancel; + close(); +} + +void hg_settingdialog::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_Escape) { + e->ignore(); + } + else { + QDialog::keyPressEvent(e); + } +} + +int hg_settingdialog::get_changed_items(void) +{ + return changed_count_; +} + +int hg_settingdialog::getCloseButtonCliked() +{ + return m_closeButton; +} + +//生成UTF-8编码的MD5值 +QString hg_settingdialog::md5(QString key) +{ + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(key.toUtf8()); + return QString(md5.result().toHex()); +} + +const void* hg_settingdialog::find_option_description(int id) +{ + for(int i = 0; i < m_list_getOpt.size(); i++) + { + if (m_list_getOpt.at(i).first == id) + return reinterpret_cast(m_list_getOpt.at(i).second); + } + + return nullptr; +} + +const void* hg_settingdialog::find_option_description(const std::string& title, int* id) +{ + for(int i = 0; i < m_list_getOpt.size(); i++) + { + std::string t((reinterpret_cast(m_list_getOpt.at(i).second))->name); + + if (title == t) + { + if(id) + *id = m_list_getOpt.at(i).first; + return reinterpret_cast(m_list_getOpt.at(i).second); + } + } + + return nullptr; +} + +void hg_settingdialog::closeEvent(QCloseEvent* e) +{ + if(e->type() == QEvent::Close) // consider as cancel ... + { + if(save_) + save_scheme(); + else + cancel_setting(); + } + + e->accept(); +} + +bool hg_settingdialog::createMsgBoxUi(bool add, std::string &name) +{ + QString text(tr("Please select to overwrite the original configuration:")); + text += QString::fromStdString(name); + text += tr(",or add a new configuration"); + + QDialog *dlg = new QDialog(this); + dlg->setWindowTitle(tr("save the configuration")); + QLabel *label_question = new QLabel; + label_question->setText(text); + + QRadioButton *radioButtonCover = new QRadioButton; + radioButtonCover->setText(tr("cover original configuration:") + QString::fromStdString(name)); + radioButtonCover->setChecked(true); + add = false; + QRadioButton *radioButtonNew = new QRadioButton; + radioButtonNew->setText(tr("add new configuration")); + + QHBoxLayout *hLayoutName = new QHBoxLayout; + QLabel *label_name = new QLabel; + label_name->setText(tr("rename:")); + m_lineEdit_name = new QLineEdit; + std::string name2; + m_lineEdit_name->setText(QString::fromStdString(getCurUiShemeName(name2))); + + QSpacerItem *spacer1 = new QSpacerItem(20, 20, QSizePolicy::Expanding); + hLayoutName->addWidget(label_name); + hLayoutName->addWidget(m_lineEdit_name); + hLayoutName->addSpacerItem(spacer1); + label_name->setVisible(false); + m_lineEdit_name->setVisible(false); + + bool cover = true; + connect(radioButtonCover, &QRadioButton::clicked, this, [=, &add, &cover](){ + cover = true; + add = false; + label_name->setVisible(false); + m_lineEdit_name->setVisible(false); + }); + connect(radioButtonNew, &QRadioButton::clicked, this, [=, &add, &cover](){ + cover = false; + add = true; + label_name->setVisible(true); + m_lineEdit_name->setVisible(true); + + m_lineEdit_name->setFocus(); + QTimer::singleShot(0, m_lineEdit_name, &QLineEdit::selectAll); + }); + + QSpacerItem *spacer2 = new QSpacerItem(20, 20, QSizePolicy::Expanding); + QPushButton *pbtnOk = new QPushButton; + pbtnOk->setText(tr("ok")); + connect(pbtnOk, &QPushButton::clicked, this, [=, &name, &cover](){ + + QString text = m_lineEdit_name->text(); + static QRegularExpression re("\\s"); + text.remove(re);//Remove space + + name = text.toStdString(); + + if(name.empty()) + { + QMessageBox::information(this, tr("tips"), tr("scheme name cannot be empty")); + m_lineEdit_name->setText(QString::fromStdString(getCurUiShemeName(name))); + return; + } + + if (!cover) + { + std::vector now; + cur_cfg_->get_all_schemes(now); + for(auto& v: now) + { + if(v == name) + { + + QMessageBox::information(this, tr("tips"), tr("scheme name: ") + QString::fromStdString(name) + tr(" already exists")); + m_lineEdit_name->setText(QString::fromStdString(getCurUiShemeName(name))); + return; + } + } + } + + dlg->close(); + }); + + QHBoxLayout *hLayout_pbtnOk = new QHBoxLayout; + hLayout_pbtnOk->addSpacerItem(spacer2); + hLayout_pbtnOk->addWidget(pbtnOk); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(label_question); + vLayout->addWidget(radioButtonCover); + vLayout->addWidget(radioButtonNew); + vLayout->addLayout(hLayoutName); + vLayout->addLayout(hLayout_pbtnOk); + dlg->setLayout(vLayout); + + dlg->exec(); + + return add; +} + +std::string hg_settingdialog::getCurUiShemeName(std::string name) +{ + std::string k(""), val(""); + int id = 0; + const SANE_Option_Descriptor* opt = nullptr; + + if (cur_scheme_->first_config(k, val)) + { + int count = 0; + do + { + id = cur_scheme_->id_from_name(k.c_str()); + opt = id == -1 ? nullptr : m_saneAPI.sane_get_option_descriptor_api(m_devHandle, id); + if (opt) + { + if (count++) + name += " + "; + + if (opt->type == SANE_TYPE_STRING) + name += from_default_language(val.c_str(), nullptr); + else + { + name += opt->title; + if (opt->type == SANE_TYPE_BOOL) + { + name += std::string("("); + if (*(SANE_Bool*)&val[0] == SANE_TRUE) + name += "true)"; + else + name += "false)"; + } + else if (opt->type == SANE_TYPE_INT) + { + char buf[128] = { 0 }; + sprintf(buf, "(%d)", *(int*)&val[0]); + name += buf; + } + else if (opt->type == SANE_TYPE_FIXED) + { + char buf[128] = { 0 }; + sprintf(buf, "(%.4f)", SANE_UNFIX(*(SANE_Fixed*)&val[0])); + name += buf; + } + } + } + } while (count < 3 && cur_scheme_->next_config(k, val)); + } + return name; +} + +void hg_settingdialog::save_scheme(void) +{ + std::string name(cur_scheme_->get_scheme_name()); + + bool add = name.empty(); + + if(add) + { + name = getCurUiShemeName(name); + } + else + { + int items = 0; + add = cur_scheme_->has_changed(&items); + if(add) + { + if(items == 0) // while shemes is default + { + cur_cfg_->select_scheme(nullptr); + return; + } + else + add = createMsgBoxUi(add, name); + } + } + if(add) + { + if(name.empty() && cur_scheme_->get_scheme_name().empty()) + { + cur_scheme_->end_setting(true); + return; + } + + gb::sane_config_schm* cp = cur_scheme_->copy(); + + cur_scheme_->end_setting(true); + cur_scheme_->release(); + cur_scheme_ = cp; + + size_t pos = name.rfind('-'); + int ind = 0; + char append[20] = {0}; + + if(pos != std::string::npos) + { + ind = atoi(name.c_str() + pos + 1); + if(ind > 0) + { + name.erase(pos); + sprintf(append, "-%d", ++ind); + } + } + while(!cur_cfg_->add_scheme(cur_scheme_, (name + append).c_str())) + { + sprintf(append, "-%d", ++ind); + } + } + else + { + cur_scheme_->end_setting(false); + } + + cur_cfg_->select_scheme(cur_scheme_->get_scheme_name().c_str()); + + cur_cfg_->save(); +} +void hg_settingdialog::cancel_setting(void) +{ + // restore changed value ... + cur_scheme_->end_setting(true); + dev_que::apply_scheme(&m_saneAPI, m_devHandle, cur_scheme_); +} + +void hg_settingdialog::getAppVersion() +{ + SANE_About *about = nullptr; + unsigned int len = 0; + std::string versionNum; + if (m_saneAPI.sane_io_control_api(m_devHandle, IO_CTRL_CODE_ABOUT_INFO, about, &len) == SANE_STATUS_NO_MEM) + { + about = (SANE_About*)malloc(len + 128); + if (about) + { + memset(about, 0, len + 128); + if (m_saneAPI.sane_io_control_api(m_devHandle, IO_CTRL_CODE_ABOUT_INFO, about, &len) == SANE_STATUS_GOOD) + { + versionNum = about->version; + } + } + } +} +void hg_settingdialog::apply_current_scheme(void) +{ + dev_que::apply_scheme(&m_saneAPI, m_devHandle, cur_scheme_); +} +std::string sane_val_to_string(const char* val, SANE_Value_Type type) +{ + char buf[128] = {0}; + std::string ret(""); + + switch(type) + { + case SANE_TYPE_BOOL: + ret = *(SANE_Bool*)val == SANE_TRUE ? "true" : "false"; + break; + case SANE_TYPE_INT: + sprintf(buf, "%d", *(int*)val); + ret = buf; + break; + case SANE_TYPE_FIXED: + sprintf(buf, "%.4f", SANE_UNFIX(*(SANE_Fixed*)val)); + ret = buf; + break; + default: + ret = val; + break; + } + + return ret; +} +void hg_settingdialog::on_current_scheme_changed() +{ + QString scheme(comb_->currentText()); + bool enabled = false; + gb::sane_config_schm *schm = cur_cfg_->get_scheme(scheme.toStdString().c_str()); + + if(schm) + enabled = true; + + rename_->setEnabled(enabled); + apply_->setEnabled(enabled); + del_this_->setEnabled(enabled); + del_all_->setEnabled(enabled); + memset(&m_gammaData, 0, sizeof(m_gammaData)); + for(int i = 0; i < sizeof(m_gammaData.table) / sizeof(m_gammaData.table[0]); ++i) + m_gammaData.table[i] = i & 0x0ff; + + QString info(tr("")); + std::string name(""), val(""); + if(schm && schm->first_config(name, val)) + { + do + { + QString title; + SANE_Value_Type type = SANE_TYPE_STRING; + for (int ii = 0; ii < m_list_defaultOptions.size(); ii++) + { + const SANE_Option_Descriptor* opt = reinterpret_cast(m_list_defaultOptions.at(ii).first); + if(strcmp(opt->name, name.c_str()) == 0) + { + title = QString::fromStdString(opt->title); + type = opt->type; + if(type == SANE_TYPE_STRING) + val = from_default_language(val.c_str(), nullptr); + break; + } + } + + if(title.length()) + { + info += tr("
") + title + tr(":
"); + info += tr("

") + QString::fromStdString(sane_val_to_string(val.c_str(), type)) + tr("

"); + } + else { + if(val.length() == sizeof(SANE_Gamma)) + memcpy(&m_gammaData, val.c_str(), sizeof(SANE_Gamma)); + } + }while(schm->next_config(name, val)); + } + if(schm) + schm->release(); + + sketch_->setHtml(info); +} +void hg_settingdialog::slot_pushButton_scheme_management(void) +{ + QPushButton* btn = qobject_cast(sender()); + + if(btn == rename_) + { + int id = 0; + QString text(find_current_scheme_menu(&id)); + if(!text.isEmpty() && id >= 0) + { + Dialog_Input dlg; + + dlg.init_value(text); + dlg.setWindowTitle(tr("configuration scheme name change")); + if(dlg.exec() && text != dlg.get_inputting_value()) + { + std::vector now; + std::string str = dlg.get_inputting_value().toStdString(); + + cur_cfg_->get_all_schemes(now); + for(auto& v: now) + { + if(v == str) + { + QMessageBox::information(this, tr("tips"), tr("scheme name: ") + QString::fromStdString(str) + tr(" already exists")); + return; + } + } + disconnect(comb_, SIGNAL(currentTextChanged(const QString)), this, SLOT(on_current_scheme_changed())); + comb_->removeItem(id); + comb_->insertItem(id, QString::fromStdString(str)); + comb_->setCurrentIndex(id); + connect(comb_, SIGNAL(currentTextChanged(const QString)), this, SLOT(on_current_scheme_changed())); + + cur_cfg_->rename_scheme(text.toStdString().c_str(), str.c_str()); + cur_cfg_->save(); + changed_count_++; + } + } + } + else if(btn == apply_) + { + QString text(find_current_scheme_menu()); + gb::sane_config_schm *cur = nullptr; + + cur_cfg_->select_scheme(text.toStdString().c_str()); + cur = cur_cfg_->get_scheme(); + if(!cur) + cur = new gb::sane_config_schm(); + cur->copy_default_value(cur_scheme_); + cur_scheme_->end_setting(true); + cur_scheme_->release(); + cur_scheme_ = cur; + cur_scheme_->begin_setting(); + + apply_current_scheme(); + updateUIStatus(); + changed_count_++; + } + else if(btn == del_this_) + { + int id = -1; + QString text(find_current_scheme_menu(&id)); + + if(text.isEmpty()) + return; + + QMessageBox msg(QMessageBox::Question, tr("be sure to delete the configuration"), + tr("Are you sure you want to delete the configuration \"") + text + tr("\" ?"), QMessageBox::Yes | QMessageBox::No, this); + msg.exec(); + if (msg.clickedButton() != msg.button(QMessageBox::Yes)) + return; + + gb::sane_config_schm *sch = cur_cfg_->get_scheme(text.toStdString().c_str()); + cur_cfg_->remove_scheme(text.toStdString().c_str()); + comb_->removeItem(id); + sch->release(); + if(sch == cur_scheme_) + { + restore_2_default_settings(); + updateUIStatus(); + } + + on_current_scheme_changed(); + changed_count_++; + cur_cfg_->save(); + } + else if(btn == del_all_) + { + QMessageBox msg(QMessageBox::Question, tr("be sure to delete the configuration"), + tr("Are you sure you want to delete the configuration?"), QMessageBox::Yes | QMessageBox::No, this); + msg.exec(); + if (msg.clickedButton() != msg.button(QMessageBox::Yes)) + return; + + restore_2_default_settings(); + updateUIStatus(); + comb_->clear(); + changed_count_++; + cur_cfg_->remove_all_schemes(); + cur_cfg_->save(); + } +} +void hg_settingdialog::restore_2_default_settings(void) +{ + cur_scheme_->end_setting(true); + cur_cfg_->select_scheme(nullptr); + dev_que_.apply_scheme(&m_saneAPI, nullptr); + cur_cfg_->save(); + + gb::sane_config_schm *s = new gb::sane_config_schm(); + s->copy_default_value(cur_scheme_); + cur_scheme_->release(); + cur_scheme_ = s; + cur_scheme_->begin_setting(); + + on_current_scheme_changed(); +} diff --git a/modules/twainui/hg_settingdialog.h b/modules/twainui/hg_settingdialog.h new file mode 100644 index 00000000..cfd7c318 --- /dev/null +++ b/modules/twainui/hg_settingdialog.h @@ -0,0 +1,152 @@ +#ifndef HG_SETTING_DIALOG_H +#define HG_SETTING_DIALOG_H + +#include +#include +#include +#include "HGSaneUI.h" +#include "cfg/gb_json.h" +#include "device_menu.h" + +class hg_settingdialog : public QDialog +{ + Q_OBJECT + + int changed_count_; + bool save_; + bool clicked_gamma_; + dev_que dev_que_; + gb::scanner_cfg *cur_cfg_; + gb::sane_config_schm *cur_scheme_; + + void refresh_control_value(int op_id); + void on_select_scheme(bool apply_to_dev = true); + QString gen_gamma_file_path(void); + + QMenu *top_menu_; + QLineEdit *edit_name_; + QPushButton *rename_; + QPushButton *apply_; + QPushButton *del_this_; + QPushButton *del_all_; + QLabel *custom_area_lable_; + QPushButton *btn_cut_area_; + QPushButton *btn_gamma_; + QTextEdit *sketch_; + QLineEdit *m_lineEdit_name; + void create_scheme_management_ui(QVBoxLayout* layout); + QString find_current_scheme_menu(int *scheme_id = nullptr); + + static std::string property_combox_data_type_; + enum _cbox_type + { + COMBO_VAL_STRING = 0, + COMBO_VAL_INT, + COMBO_VAL_FLOAT, + }; + +public: + explicit hg_settingdialog(SANE_Handle handle, const SANEAPI* saneApi, bool showScan, QWidget *parent = nullptr); + ~hg_settingdialog(); + +public: + void initUi(); + void updateOpt(); + void createUI(); + void updateUIStatus(); + QVector find_control(int opt_num); + void keyPressEvent(QKeyEvent *e); + int get_changed_items(void); + int getCloseButtonCliked(); + +public: + enum closeButtonClicked + { + closeButtonOk = 0, + closeButtonCancel, + closeButtonScan, + }; + + int m_closeButton; + +private: + SANEAPI m_saneAPI; + SANE_Handle m_devHandle; + bool m_showScan; + +private: + QString m_qstrFileName; + QSettings *m_configIniWrite; + QSettings *m_configIniRead; + +private: + QString md5(QString key); + const void* find_option_description(int id); // return const SANE_Option_Descriptor* pointer + const void* find_option_description(const std::string& title, int* id); // return const SANE_Option_Descriptor* pointer + + virtual void closeEvent(QCloseEvent* e); + bool createMsgBoxUi(bool add, std::string &name); + std::string getCurUiShemeName(std::string name); + void save_scheme(void); + void cancel_setting(void); + void getAppVersion(); + void apply_current_scheme(void); + +private: + QVector, QString>> m_list_IdValueTitle; + QVector> m_list_defaultOptions; // default values of device + QVector> m_list_sliderSpinbox; + QVector> m_list_getOpt; + QVector m_list_deviceNames; + QVector m_list_widgets; + +private slots: + void slot_checkedClicked(); + void slot_sliderClicked(int value); + void slot_spinBoxClicked(int value); + void slot_doubleSpinboxClicked(double value); + void slot_string_list_comboBoxClicked(); + void slot_pushButtonClicked(); + void slot_cutButtonClicked(); + void slot_gammaButtonClicked(); + void slot_word_list_comboBoxClicked(int value); + void slot_lineEditInput(); + void slot_buttonScanClicked(); + void slot_buttonOkClicked(); + void slot_buttonCancelClicked(); + void slot_pushButton_scheme_management(void); + void on_current_scheme_changed(void); + void restore_2_default_settings(void); + +private: + int m_dpiId; + int m_dpiValue; + int m_paperSizeId; + QString m_paperSizeValue; + int m_cutLeftId; + int m_cutTopId; + int m_cutRightId; + int m_cutBottomId; + double m_cutWidth; // 单位是毫米 + double m_cutHeight; // 单位是毫米 + double m_cutLeftValue; // 单位是毫米 + double m_cutTopValue; // 单位是毫米 + double m_cutRightValue; // 单位是毫米 + double m_cutBottomValue; // 单位是毫米 + + int m_colorModeId; + QString m_colorModeValue; + SANE_Gamma m_gammaData; + QComboBox *comb_; +}; + +#endif // HG_SETTING_DIALOG_H + + + + + + + + + diff --git a/modules/twainui/qmfcapp.cpp b/modules/twainui/qmfcapp.cpp new file mode 100644 index 00000000..68953d70 --- /dev/null +++ b/modules/twainui/qmfcapp.cpp @@ -0,0 +1,427 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +// Implementation of the QMfcApp classes + +#ifdef QT3_SUPPORT +#undef QT3_SUPPORT +#endif + +#ifdef UNICODE +#undef UNICODE +#endif + +#include "qmfcapp.hpp" + +#include +#include +#include + +#ifdef QTWINMIGRATE_WITHMFC +#include +#else +#include +#endif + +#ifdef QTWINMIGRATE_WITHMFC +CWinApp *QMfcApp::mfc_app = 0; +char **QMfcApp::mfc_argv = 0; +int QMfcApp::mfc_argc = 0; +#endif + +#if QT_VERSION >= 0x050000 +#define QT_WA(unicode, ansi) unicode + +QMfcAppEventFilter::QMfcAppEventFilter() : QAbstractNativeEventFilter() +{ +} + +bool QMfcAppEventFilter::nativeEventFilter(const QByteArray &, void *message, long *result) +{ + return static_cast(qApp)->winEventFilter((MSG*)message, result); +} +#endif + +/*! \class QMfcApp qmfcapp.h + \brief The QMfcApp class provides merging of the MFC and Qt event loops. + + QMfcApp is responsible for driving both the Qt and MFC event loop. + It replaces the standard MFC event loop provided by + CWinApp::Run(), and is used instead of the QApplication parent + class. + + To replace the MFC event loop reimplement the CWinApp::Run() + function in the CWinApp subclass usually created by the MFC + Application Wizard, and use either the static run() function, or + an instance of QMfcApp created earlier through the static + instance() function or the constructor. + + The QMfcApp class also provides a static API pluginInstance() that + drives the Qt event loop when loaded into an MFC or Win32 application. + This is useful for developing Qt based DLLs or plugins, or if the + MFC application's event handling can not be modified. +*/ + +static int modalLoopCount = 0; + +HHOOK hhook; +LRESULT CALLBACK QtFilterProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (qApp) { + // don't process deferred-deletes while in a modal loop + if (modalLoopCount) + qApp->sendPostedEvents(); + else + qApp->sendPostedEvents(0, -1); + } + + return CallNextHookEx(hhook, nCode, wParam, lParam); +} + +/*! + Inform Qt that a modal loop is about to be entered, and that DeferredDelete + events should not be processed. Call this function before calling Win32 + or MFC functions that enter a modal event loop (i.e. MessageBox). + + This is only required if the Qt UI code hooks into an existing Win32 + event loop using QMfcApp::pluginInstance. + + \sa exitModalLoop() +*/ +void QMfcApp::enterModalLoop() +{ + ++modalLoopCount; +} + +/*! + Inform Qt that a modal loop has been exited, and that DeferredDelete + events should not be processed. Call this function after the blocking + Win32 or MFC function (i.e. MessageBox) returned. + + This is only required if the Qt UI code hooks into an existing Win32 + event loop using QMfcApp::pluginInstance. + + \sa enterModalLoop() +*/ +void QMfcApp::exitModalLoop() +{ + --modalLoopCount; + Q_ASSERT(modalLoopCount >= 0); +} + +/*! + If there is no global QApplication object (i.e. qApp is null) this + function creates a QApplication instance and returns true; + otherwise it does nothing and returns false. + + The application installs an event filter that drives the Qt event + loop while the MFC or Win32 application continues to own the event + loop. + + Use this static function if the application event loop code can not be + easily modified, or when developing a plugin or DLL that will be loaded + into an existing Win32 or MFC application. If \a plugin is non-null then + the function loads the respective DLL explicitly to avoid unloading from + memory. + + \code + BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved) + { + if (dwReason == DLL_PROCESS_ATTACH) + QMfcApp::pluginInstance(hInstance); + + return TRUE; + } + \endcode + + Set \a plugin to 0 when calling this function from within the same executable + module. + + If this function is used, call enterModalLoop and exitModalLoop whenever you + call a Win32 or MFC function that opens a local event loop. + + \code + void Dialog::someSlot() + { + QMfcApp::enterModalLoop(); + MessageBox(...); + QMfcApp::exitModalLoop(); + } + \endcode +*/ +bool QMfcApp::pluginInstance(Qt::HANDLE plugin) +{ + if (qApp) + return FALSE; + + QT_WA({ + hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId()); + }, { + hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId()); + }); + + int argc = 0; + (void)new QApplication(argc, 0); + + if (plugin) { + char filename[256]; + if (GetModuleFileNameA((HINSTANCE)plugin, filename, 255)) + LoadLibraryA(filename); + } + + return TRUE; +} + +#if QT_VERSION >= 0x050000 +Q_GLOBAL_STATIC(QMfcAppEventFilter, qmfcEventFilter); +#endif + +#ifdef QTWINMIGRATE_WITHMFC +/*! + Runs the event loop for both Qt and the MFC application object \a + mfcApp, and returns the result. This function calls \c instance() + if no QApplication object exists and deletes the object it + created. + + Calling this static function in a reimplementation of + CWinApp::Run() is the simpliest way to use the QMfcApp class: + + \code + int MyMfcApp::Run() + { + return QMfcApp::run(this); + } + \endcode + + Since a QApplication object must exist before Qt widgets can be + created you cannot use this function if you want to use Qt-based + user interface elements in, for example, the InitInstance() + function of CWinApp. In such cases, create an instance of + QApplication explicitly using instance() or the constructor. + + \sa instance() +*/ +int QMfcApp::run(CWinApp *mfcApp) +{ + bool ownInstance = !qApp; + if (ownInstance) + instance(mfcApp); + int result = qApp->exec(); + + if (mfcApp) { + int mfcRes = mfcApp->ExitInstance(); + if (mfcRes && !result) + result = mfcRes; + } + + if (ownInstance) + delete qApp; + + return result; +} + +/*! + Creates an instance of QApplication, passing the command line of + \a mfcApp to the QApplication constructor, and returns the new + object. The returned object must be destroyed by the caller. + + Use this static function if you want to perform additional + initializations after creating the application object, or if you + want to create Qt GUI elements in the InitInstance() + reimplementation of CWinApp: + + \code + BOOL MyMfcApp::InitInstance() + { + // standard MFC initialization + // ... + + // This sets the global qApp pointer + QMfcApp::instance(this); + + // Qt GUI initialization + } + + BOOL MyMfcApp::Run() + { + int result = QMfcApp::run(this); + delete qApp; + return result; + } + \endcode + + \sa run() +*/ +QApplication *QMfcApp::instance(CWinApp *mfcApp) +{ + mfc_app = mfcApp; + if (mfc_app) { +#if defined(UNICODE) + QString exeName((QChar*)mfc_app->m_pszExeName, wcslen(mfc_app->m_pszExeName)); + QString cmdLine((QChar*)mfc_app->m_lpCmdLine, wcslen(mfc_app->m_lpCmdLine)); +#else + QString exeName = QString::fromLocal8Bit(mfc_app->m_pszExeName); + QString cmdLine = QString::fromLocal8Bit(mfc_app->m_lpCmdLine); +#endif + QStringList arglist = QString(exeName + " " + cmdLine).split(' '); + + mfc_argc = arglist.count(); + mfc_argv = new char*[mfc_argc+1]; + int a; + for (a = 0; a < mfc_argc; ++a) { + QString arg = arglist[a]; + mfc_argv[a] = new char[arg.length()+1]; + qstrcpy(mfc_argv[a], arg.toLocal8Bit().data()); + } + mfc_argv[a] = 0; + } + + return new QMfcApp(mfcApp, mfc_argc, mfc_argv); +} + + +static bool qmfc_eventFilter(void *message) +{ + long result = 0; + return static_cast(qApp)->winEventFilter((MSG*)message, &result); +} + +/*! + Creates an instance of QMfcApp. \a mfcApp must point to the + existing instance of CWinApp. \a argc and \a argv are passed on + to the QApplication constructor. + + Use the static function instance() to automatically use the + command line passed to the CWinApp. + + \code + QMfcApp *qtApp; + + BOOL MyMfcApp::InitInstance() + { + // standard MFC initialization + + int argc = ... + char **argv = ... + + qtApp = new QMfcApp(this, argc, argv); + + // Qt GUI initialization + } + + BOOL MyMfcApp::Run() + { + int result = qtApp->exec(); + delete qtApp; + qtApp = 0; + + return result; + } + \endcode + + \sa instance() run() +*/ +QMfcApp::QMfcApp(CWinApp *mfcApp, int &argc, char **argv) +: QApplication(argc, argv), idleCount(0), doIdle(FALSE) +{ + mfc_app = mfcApp; +#if QT_VERSION >= 0x050000 + QAbstractEventDispatcher::instance()->installNativeEventFilter(qmfcEventFilter()); +#else + QAbstractEventDispatcher::instance()->setEventFilter(qmfc_eventFilter); +#endif + setQuitOnLastWindowClosed(false); +} +#endif + +QMfcApp::QMfcApp(int &argc, char **argv) : QApplication(argc, argv) +{ +#if QT_VERSION >= 0x050000 + QAbstractEventDispatcher::instance()->installNativeEventFilter(qmfcEventFilter()); +#endif +} +/*! + Destroys the QMfcApp object, freeing all allocated resources. +*/ +QMfcApp::~QMfcApp() +{ + if (hhook) { + UnhookWindowsHookEx(hhook); + hhook = 0; + } + +#ifdef QTWINMIGRATE_WITHMFC + for (int a = 0; a < mfc_argc; ++a) { + char *arg = mfc_argv[a]; + delete[] arg; + } + delete []mfc_argv; + + mfc_argc = 0; + mfc_argv = 0; + mfc_app = 0; +#endif +} + +/*! + \reimp +*/ +bool QMfcApp::winEventFilter(MSG *msg, long *result) +{ + static bool recursion = false; + if (recursion) + return false; + + recursion = true; + + QWidget *widget = QWidget::find((WId)msg->hwnd); + HWND toplevel = 0; + if (widget) { + HWND parent = (HWND)widget->winId(); + while(parent) { + toplevel = parent; + parent = GetParent(parent); + } + HMENU menu = toplevel ? GetMenu(toplevel) : 0; + if (menu && GetFocus() == msg->hwnd) { + if (msg->message == WM_SYSKEYUP && msg->wParam == VK_MENU) { + // activate menubar on Alt-up and move focus away + SetFocus(toplevel); + SendMessage(toplevel, msg->message, msg->wParam, msg->lParam); + widget->setFocus(); + recursion = false; + return TRUE; + } else if (msg->message == WM_SYSKEYDOWN && msg->wParam != VK_MENU) { + SendMessage(toplevel, msg->message, msg->wParam, msg->lParam); + SendMessage(toplevel, WM_SYSKEYUP, VK_MENU, msg->lParam); + recursion = false; + return TRUE; + } + } + } +#ifdef QTWINMIGRATE_WITHMFC + else if (mfc_app) { + MSG tmp; + while (doIdle && !PeekMessage(&tmp, 0, 0, 0, PM_NOREMOVE)) { + if (!mfc_app->OnIdle(idleCount++)) + doIdle = FALSE; + } + if (mfc_app->IsIdleMessage(msg)) { + doIdle = TRUE; + idleCount = 0; + } + } + if (mfc_app && mfc_app->PreTranslateMessage(msg)) { + recursion = false; + return TRUE; + } +#endif + + recursion = false; +#if QT_VERSION < 0x050000 + return QApplication::winEventFilter(msg, result); +#else + Q_UNUSED(result); + return false; +#endif +} diff --git a/modules/twainui/qmfcapp.hpp b/modules/twainui/qmfcapp.hpp new file mode 100644 index 00000000..e11afa59 --- /dev/null +++ b/modules/twainui/qmfcapp.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + + +// Declaration of the QMfcApp classes + +#ifndef QMFCAPP_H +#define QMFCAPP_H + +#include + +#if defined(_AFXDLL) && defined(_MSC_VER) +#define QTWINMIGRATE_WITHMFC +class CWinApp; +#endif + +#if QT_VERSION >= 0x050000 +#include + +class QMfcAppEventFilter : public QAbstractNativeEventFilter +{ +public: + QMfcAppEventFilter(); + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); +}; +#endif + +class QMfcApp : public QApplication +{ +public: + static bool pluginInstance(Qt::HANDLE plugin = 0); + +#ifdef QTWINMIGRATE_WITHMFC + static int run(CWinApp *mfcApp); + static QApplication *instance(CWinApp *mfcApp); + QMfcApp(CWinApp *mfcApp, int &argc, char **argv); +#endif + QMfcApp(int &argc, char **argv); + ~QMfcApp(); + + bool winEventFilter(MSG *msg, long *result); + + static void enterModalLoop(); + static void exitModalLoop(); + +private: +#ifdef QTWINMIGRATE_WITHMFC + static char ** mfc_argv; + static int mfc_argc; + static CWinApp *mfc_app; +#endif + + int idleCount; + bool doIdle; +}; + +#endif // QMFCAPP_H diff --git a/modules/twainui/qt_zh_CN.qm b/modules/twainui/qt_zh_CN.qm new file mode 100644 index 00000000..e8d65305 Binary files /dev/null and b/modules/twainui/qt_zh_CN.qm differ diff --git a/modules/twainui/qt_zh_CN.ts b/modules/twainui/qt_zh_CN.ts new file mode 100644 index 00000000..f6a25d21 --- /dev/null +++ b/modules/twainui/qt_zh_CN.ts @@ -0,0 +1,8077 @@ + + + + + MAC_APPLICATION_MENU + + + Services + 服务 + + + + Hide %1 + 隐藏%1 + + + + Hide Others + 隐藏其他 + + + + Show All + 全部显示 + + + + Preferences... + 偏好设置… + + + + Quit %1 + 退出 %1 + + + + About %1 + 关于 %1 + + + + AudioOutput + + + <html>The audio playback device <b>%1</b> does not work.<br/>Falling back to <b>%2</b>.</html> + <html>音频回放设备 <b>%1</b> 没有工作。<br/>回滚到 <b>%2</b>。</html> + + + + <html>Switching to the audio playback device <b>%1</b><br/>which just became available and has higher preference.</html> + <html>切换到音频回放设备 <b>%1</b>,<br/>它刚刚变为可用并且具有更高的优先级。</html> + + + + Revert back to device '%1' + 恢复到设备“%1” + + + + CloseButton + + + Close Tab + 关闭标签页 + + + + Phonon:: + + + Notifications + 通知 + + + + Music + 音乐 + + + + Video + 视频 + + + + Communication + 通讯 + + + + Games + 游戏 + + + + Accessibility + 无障碍环境 + + + + Phonon::Gstreamer::Backend + + + Warning: You do not seem to have the package gstreamer0.10-plugins-good installed. + Some video features have been disabled. + 警告:看起来,您没有安装 gstreamer0.10-plugins-good 包。 + 一些视频特性已经被关闭。 + + + + Warning: You do not seem to have the base GStreamer plugins installed. + All audio and video support has been disabled + 警告:看起来,您没有安装基础的 GStreamer 插件。 + 所有的音频和视频支持都已经被关闭。 + + + + Phonon::Gstreamer::MediaObject + + + Cannot start playback. + +Check your Gstreamer installation and make sure you +have libgstreamer-plugins-base installed. + 不能开始回放。 + +请检查您的 Gstreamer 安装并且确认您 +已经安装 libgstreamer-plugins-base。 + + + + A required codec is missing. You need to install the following codec(s) to play this content: %0 + 缺少一个需要的解码器。您需要安装如下解码器来播放这个内容:%0 + + + + + + + + + + + Could not open media source. + 不能打开媒体源。 + + + + Invalid source type. + 无效的源类型。 + + + + Could not locate media source. + 不能定位媒体源。 + + + + Could not open audio device. The device is already in use. + 不能打开音频设备。这个设备正在被使用。 + + + + Could not decode media source. + 不能解码媒体源。 + + + + Phonon::VolumeSlider + + + + Volume: %1% + 音量:%1% + + + + + + Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1% + 请使用这个滑块调节音量。最左为%0,最右为%1% + + + + Q3Accel + + + %1, %2 not defined + %1,%2未定义 + + + + Ambiguous %1 not handled + 不明确的%1没有被处理 + + + + Q3DataTable + + + True + + + + + False + + + + + Insert + 插入 + + + + Update + 更新 + + + + Delete + 删除 + + + + Q3FileDialog + + + Copy or Move a File + 复制或者移动一个文件 + + + + Read: %1 + 读取:%1 + + + + + Write: %1 + 写入:%1 + + + + + Cancel + 取消 + + + + + + + All Files (*) + 所有文件 (*) + + + + Name + 名称 + + + + Size + 大小 + + + + Type + 类型 + + + + Date + 日期 + + + + Attributes + 属性 + + + + + &OK + 确定(&O) + + + + Look &in: + 查找范围(&I): + + + + + + File &name: + 文件名称(&N): + + + + File &type: + 文件类型(&T): + + + + Back + 后退 + + + + One directory up + 向上一级 + + + + Create New Folder + 创建新文件夹 + + + + List View + 列表视图 + + + + Detail View + 详细视图 + + + + Preview File Info + 预览文件信息 + + + + Preview File Contents + 预览文件内容 + + + + Read-write + 读写 + + + + Read-only + 只读 + + + + Write-only + 只写 + + + + Inaccessible + 不可访问的 + + + + Symlink to File + 文件的系统链接 + + + + Symlink to Directory + 目录的系统链接 + + + + Symlink to Special + 特殊的系统链接 + + + + File + 文件 + + + + Dir + 目录 + + + + Special + 特殊 + + + + + + Open + 打开 + + + + + Save As + 另存为 + + + + + + &Open + 打开(&O) + + + + + &Save + 保存(&S) + + + + &Rename + 重命名(&R) + + + + &Delete + 删除(&D) + + + + R&eload + 重新载入(&E) + + + + Sort by &Name + 按名称排列(&N) + + + + Sort by &Size + 按大小排列(&S) + + + + Sort by &Date + 按日期排列(&D) + + + + &Unsorted + 未排列的(&U) + + + + Sort + 排列 + + + + Show &hidden files + 显示隐藏文件(&H) + + + + the file + 文件 + + + + the directory + 目录 + + + + the symlink + 系统链接 + + + + Delete %1 + 删除%1 + + + + <qt>Are you sure you wish to delete %1 "%2"?</qt> + <qt>你确认你想删除%1,“%2”?</qt> + + + + &Yes + 是(&Y) + + + + &No + 否(&N) + + + + New Folder 1 + 新建文件夹1 + + + + New Folder + 新建文件夹 + + + + New Folder %1 + 新建文件夹%1 + + + + Find Directory + 查找目录 + + + + + Directories + 目录 + + + + Directory: + 目录: + + + + + Error + 错误 + + + + %1 +File not found. +Check path and filename. + 文件%1 +未找到。 +请检查路径和文件名。 + + + + + All Files (*.*) + 所有文件 (*.*) + + + + Open + 打开 + + + + Select a Directory + 选择一个目录 + + + + Q3LocalFs + + + + Could not read directory +%1 + 不能读取目录 +%1 + + + + Could not create directory +%1 + 不能创建目录 +%1 + + + + Could not remove file or directory +%1 + 不能移除文件或者目录 +%1 + + + + Could not rename +%1 +to +%2 + 不能把 +%1 +重命名为 +%2 + + + + Could not open +%1 + 不能打开 +%1 + + + + Could not write +%1 + 不能写入 +%1 + + + + Q3MainWindow + + + Line up + 排列 + + + + Customize... + 自定义... + + + + Q3NetworkProtocol + + + Operation stopped by the user + 操作被用户停止 + + + + Q3ProgressDialog + + + + Cancel + 取消 + + + + Q3TabDialog + + + + OK + 确认 + + + + Apply + 应用 + + + + Help + 帮助 + + + + Defaults + 默认 + + + + Cancel + 取消 + + + + Q3TextEdit + + + &Undo + 撤消(&U) + + + + &Redo + 恢复(&R) + + + + Cu&t + 剪切(&T) + + + + &Copy + 复制(&C) + + + + &Paste + 粘贴(&P) + + + + Clear + 清空 + + + + + Select All + 选择全部 + + + + Q3TitleBar + + + System + 系统 + + + + Restore up + 向上恢复 + + + + Minimize + 最小化 + + + + Restore down + 向下恢复 + + + + Maximize + 最大化 + + + + Close + 关闭 + + + + Contains commands to manipulate the window + 包含操作窗口的命令。 + + + + Puts a minimized back to normal + 把一个最小化窗口恢复为普通状态 + + + + Moves the window out of the way + 把窗口移到外面 + + + + Puts a maximized window back to normal + 把一个最大化窗口恢复为普通状态 + + + + Makes the window full screen + 窗口全屏化 + + + + Closes the window + 关闭窗口 + + + + Displays the name of the window and contains controls to manipulate it + 显示窗口名称并且包含维护它的控件 + + + + Q3ToolBar + + + More... + 更多... + + + + Q3UrlOperator + + + + + The protocol `%1' is not supported + 协议“%1”不被支持 + + + + The protocol `%1' does not support listing directories + 协议“%1”不支持列出目录 + + + + The protocol `%1' does not support creating new directories + 协议“%1”不支持创建新目录 + + + + The protocol `%1' does not support removing files or directories + 协议“%1”不支持移除文件或者目录 + + + + The protocol `%1' does not support renaming files or directories + 协议“%1”不支持重命名文件或者目录 + + + + The protocol `%1' does not support getting files + 协议“%1”不支持获取文件 + + + + The protocol `%1' does not support putting files + 协议“%1”不支持上传文件 + + + + + The protocol `%1' does not support copying or moving files or directories + 协议“%1”不支持复制或者移动文件或者目录 + + + + + (unknown) + (未知的) + + + + Q3Wizard + + + &Cancel + 取消(&C) + + + + < &Back + < 上一步(&B) + + + + &Next > + 下一步(&N) > + + + + &Finish + 完成(&F) + + + + &Help + 帮助(&H) + + + + QAbstractSocket + + + + + + Host not found + 主机未找到 + + + + + + Connection refused + 连接被拒绝 + + + + Connection timed out + 连接超时 + + + + + + Operation on socket is not supported + Socket操作不被支持 + + + + Socket operation timed out + 套接字操作超时 + + + + Socket is not connected + 套接字没有被连接 + + + + Network unreachable + 网络不能访问 + + + + QAbstractSpinBox + + + &Step up + 增加(&S) + + + + Step &down + 减少(&D) + + + + &Select All + 选择全部(&S) + + + + QApplication + + + Activate + 激活 + + + + Executable '%1' requires Qt %2, found Qt %3. + 执行“%1”需要Qt %2,只找到了Qt %3。 + + + + Incompatible Qt Library Error + 不兼容的Qt错误 + + + + Activates the program's main window + 激活这个程序的主窗口 + + + + QAxSelect + + + Select ActiveX Control + 选择ActiveX控件 + + + + OK + 确定 + + + + &Cancel + 取消(&C) + + + + COM &Object: + COM对象(&O): + + + + QCheckBox + + + Uncheck + 取消选中 + + + + Check + 选中 + + + + Toggle + 切换 + + + + QColorDialog + + + Hu&e: + 色调(&E): + + + + &Sat: + 饱和度(&S): + + + + &Val: + 亮度(&V): + + + + &Red: + 红色(&R): + + + + &Green: + 绿色(&G): + + + + Bl&ue: + 蓝色(&U): + + + + A&lpha channel: + Alpha通道(&A): + + + + Select Color + 选择颜色 + + + + &Basic colors + 基本颜色(&B) + + + + &Custom colors + 自定义颜色(&C) + + + + &Add to Custom Colors + 添加到自定义颜色(&A) + + + Select color + 选择颜色 + + + &Pick Screen Color + 拾取屏幕颜色(&P) + + + Cursor at %1, %2 +Press ESC to cancel + 光标位置 %1, %2 +按ESC键取消 + + + &HTML: + 颜色值(&H): + + + + QComboBox + + + + Open + 打开 + + + + False + + + + + True + + + + + Close + 关闭 + + + + QCoreApplication + + %1: permission denied + QSystemSemaphore + %1:权限被拒绝 + + + %1: already exists + QSystemSemaphore + %1:已经存在 + + + %1: doesn't exists + QSystemSemaphore + %1:不存在 + + + %1: out of resources + QSystemSemaphore + %1:资源耗尽了 + + + %1: unknown error %2 + QSystemSemaphore + %1:未知错误 %2 + + + + %1: key is empty + QSystemSemaphore + %1:键是空的 + + + + %1: unable to make key + QSystemSemaphore + %1:不能制造键 + + + + %1: ftok failed + QSystemSemaphore + %1:ftok 失败 + + + + QDB2Driver + + + Unable to connect + 不能连接 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + Unable to set autocommit + 不能设置自动提交 + + + + QDB2Result + + + + Unable to execute statement + 不能执行语句 + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to bind variable + 不能帮定变量 + + + + Unable to fetch record %1 + 不能获取记录%1 + + + + Unable to fetch next + 不能获取下一个 + + + + Unable to fetch first + 不能获取第一个 + + + + QDateTimeEdit + + + AM + AM + + + + am + am + + + + PM + PM + + + + pm + pm + + + + QDial + + + QDial + QDial + + + + SpeedoMeter + SpeedoMeter + + + + SliderHandle + SliderHandle + + + + QDialog + + + What's This? + 这是什么? + + + + Done + 完成 + + + + QDialogButtonBox + + + + + OK + 确定 + + + + Save + 保存 + + + + &Save + 保存(&S) + + + + Open + 打开 + + + + Cancel + 取消 + + + + &Cancel + 取消(&C) + + + + Close + 关闭 + + + + &Close + 关闭(&C) + + + + Apply + 应用 + + + + Reset + 重置 + + + + Help + 帮助 + + + + Don't Save + 不保存 + + + + Discard + 抛弃 + + + + &Yes + 是(&Y) + + + + Yes to &All + 全部是(&A) + + + + &No + 否(&N) + + + + N&o to All + 全部否(&O) + + + + Save All + 保存全部 + + + + Abort + 放弃 + + + + Retry + 重试 + + + + Ignore + 忽略 + + + + Restore Defaults + 恢复默认 + + + + Close without Saving + 不保存关闭 + + + + &OK + 确定(&O) + + + + QDirModel + + + Name + 名称 + + + + Size + 大小 + + + + Kind + Match OS X Finder + 类型 + + + + Type + All other platforms + 类型 + + + + Date Modified + 日期被修改 + + + + QDockWidget + + + Close + 关闭 + + + + Dock + 锚接 + + + + Float + 浮动 + + + + QDoubleSpinBox + + + More + 更多 + + + + Less + 更少 + + + + QErrorMessage + + + Debug Message: + 调试消息: + + + + Warning: + 警告: + + + + Fatal Error: + 致命错误: + + + + &Show this message again + 再次显示这个消息(&S) + + + + &OK + 确定(&O) + + + + QFile + + + + Destination file exists + 目标文件已存在 + + + + Cannot remove source file + + + + + Cannot open %1 for input + 无法输入 %1 + + + + Cannot open for output + 无法输出 + + + + Failure to write block + 写块失败 + + + + Cannot create %1 for output + 无法创建 %1 + + + + QFileDialog + + + + All Files (*) + 所有文件 (*) + + + + Directories + 目录 + + + + + + + &Open + 打开(&O) + + + + + &Save + 保存(&S) + + + + &Cancel + 取消(&S) + + + + Cancel + 取消 + + + + Open + 打开 + + + + %1 already exists. +Do you want to replace it? + %1已经存在。 +你想要替换它么? + + + + %1 +File not found. +Please verify the correct file name was given. + 文件%1 +没有找到。 +请核实已给定正确文件名。 + + + + My Computer + 我的计算机 + + + + &Rename + 重命名(&R) + + + + &Delete + 删除(&D) + + + + Show &hidden files + 显示隐藏文件(&H) + + + + + Back + 后退 + + + + + Parent Directory + 父目录 + + + + + List View + 列表视图 + + + + + Detail View + 详细视图 + + + + + Files of type: + 文件类型: + + + + + Directory: + 目录: + + + + + %1 +Directory not found. +Please verify the correct directory name was given. + 目录%1 +没有找到。 +请核实已给定正确目录名。 + + + + '%1' is write protected. +Do you want to delete it anyway? + “%1“是写保护的。 +你还是想删除它么? + + + + Are sure you want to delete '%1'? + 你确认你想删除“%1“? + + + + Could not delete directory. + 不能删除目录。 + + + + Recent Places + 最近的地方 + + + + Save As + 另存为 + + + + Drive + 驱动器 + + + + + File + 文件 + + + + Unknown + 未知的 + + + + Find Directory + 查找目录 + + + + Show + 显示 + + + + + Forward + 前进 + + + + New Folder + 新建文件夹 + + + + &New Folder + 新建文件夹(&N) + + + + + &Choose + 选择(&C) + + + + Remove + 移除 + + + + + File &name: + 文件名称(&N): + + + + + Look in: + 查看: + + + + + Create New Folder + 创建新文件夹 + + + + All Files (*.*) + 所有文件 (*.*) + + + + QFileSystemModel + + + %1 TB + %1 TB + + + + %1 GB + %1 GB + + + + %1 MB + %1 MB + + + + %1 KB + %1千字节 + + + + %1 bytes + %1字节 + + + + Invalid filename + 无效文件名 + + + + <b>The name "%1" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks. + <b>名称“%1“不能被使用。</b><p>请使用另外一个包含更少字符或者不含有标点符号的名称。 + + + + Name + 名称 + + + + Size + 大小 + + + + Kind + Match OS X Finder + 类型 + + + + Type + All other platforms + 类型 + + + + Date Modified + 日期被修改 + + + + My Computer + 我的计算机 + + + + Computer + 计算机 + + + + QFontDatabase + + + + Normal + 普通 + + + + + + Bold + 粗体 + + + + + Demi Bold + 半粗体 + + + + + + Black + 黑体 + + + + Demi + 半体 + + + + + Light + 轻体 + + + + + Italic + 意大利体 + + + + + Oblique + 斜体 + + + + Any + 任意 + + + + Latin + 拉丁文 + + + + Greek + 希腊文 + + + + Cyrillic + 西里尔文 + + + + Armenian + 亚美尼亚文 + + + + Hebrew + 希伯来文 + + + + Arabic + 阿拉伯文 + + + + Syriac + 叙利亚文 + + + + Thaana + 马尔代夫文 + + + + Devanagari + 梵文 + + + + Bengali + 孟加拉文 + + + + Gurmukhi + 旁遮普文 + + + + Gujarati + 古吉拉特文 + + + + Oriya + 奥里雅文 + + + + Tamil + 泰米尔文 + + + + Telugu + 泰卢固文 + + + + Kannada + 埃纳德文 + + + + Malayalam + 马拉亚拉姆文 + + + + Sinhala + 僧伽罗文 + + + + Thai + 泰国文 + + + + Lao + 老挝文 + + + + Tibetan + 藏文 + + + + Myanmar + 缅甸文 + + + + Georgian + 格鲁吉亚文 + + + + Khmer + 谷美尔文 + + + + Simplified Chinese + 简体中文 + + + + Traditional Chinese + 繁体中文 + + + + Japanese + 日文 + + + + Korean + 韩文 + + + + Vietnamese + 越南文 + + + + Symbol + 符号 + + + + Ogham + 欧甘文 + + + + Runic + 古北欧文 + + + + QFontDialog + + + &Font + 字体(&F) + + + + Font st&yle + 字体风格(&Y) + + + + &Size + 大小(&S) + + + + Effects + 效果 + + + + Stri&keout + 删除线(&K) + + + + &Underline + 下划线(&U) + + + + Sample + 实例 + + + + Wr&iting System + 书写系统(&I) + + + + + Select Font + 选择字体 + + + + QFtp + + + + Not connected + 没有连接 + + + + + Host %1 not found + 主机%1没有找到 + + + + + Connection refused to host %1 + 连接被主机 %1 拒绝 + + + + Connection timed out to host %1 + 主机%1连接超时 + + + + + + Connected to host %1 + 连接到主机%1了 + + + + + Connection refused for data connection + 因为数据连接而被拒绝连接 + + + + + + + Unknown error + 未知的错误 + + + + + Connecting to host failed: +%1 + 连接主机失败: +%1 + + + + + Login failed: +%1 + 登录失败: +%1 + + + + + Listing directory failed: +%1 + 列出目录失败: +%1 + + + + + Changing directory failed: +%1 + 改变目录失败: +%1 + + + + + Downloading file failed: +%1 + 下载文件失败: +%1 + + + + + Uploading file failed: +%1 + 上传文件失败: +%1 + + + + + Removing file failed: +%1 + 移除文件失败: +%1 + + + + + Creating directory failed: +%1 + 创建目录失败: +%1 + + + + + Removing directory failed: +%1 + 移除目录失败: +%1 + + + + + + Connection closed + 连接关闭了 + + + + Host %1 found + 主机%1找到了 + + + + Connection to %1 closed + 到%1的连接关闭了 + + + + Host found + 主机找到了 + + + + Connected to host + 连接到主机了 + + + + QGuiApplication + + + QT_LAYOUT_DIRECTION + Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. + LTR + + + + QHostInfo + + + Unknown error + 未知的错误 + + + + QHostInfoAgent + + + + + + + + + + Host not found + 主机未找到 + + + + + + + Unknown address type + 未知的地址类型 + + + + + + Unknown error + 未知的错误 + + + + QHttp + + + + + + Unknown error + 未知的错误 + + + + + Request aborted + 请求被放弃了 + + + + + No server set to connect to + 没有设置要连接的服务器 + + + + + Wrong content length + 错误的内容长度 + + + + + Server closed connection unexpectedly + 服务器异常地关闭了连接 + + + + Unknown authentication method + + + + + Error writing response to device + 向设备中进行写回复时发生错误 + + + + + Connection refused + 连接被拒绝 + + + + + + Host %1 not found + 主机%1没有找到 + + + + + + + HTTP request failed + HTTP请求失败 + + + + + Invalid HTTP response header + 无效的HTTP响应头 + + + + + + + Invalid HTTP chunked body + 无效的HTTP臃肿体 + + + + Host %1 found + 主机%1找到了 + + + + Connected to host %1 + 连接到%1主机了 + + + + Connection to %1 closed + 到%1的连接关闭了 + + + + Host found + 主机找到了 + + + + Connected to host + 连接到主机了 + + + + + Connection closed + 连接关闭了 + + + + Proxy authentication required + 代理需要认证 + + + + Authentication required + 需要认证 + + + + Connection refused (or timed out) + 连接被拒绝(或者超时) + + + + Proxy requires authentication + 代理需要验证 + + + + Host requires authentication + 主机需要验证 + + + + Data corrupted + 数据错误 + + + + Unknown protocol specified + 所指定的协议是未知的 + + + + SSL handshake failed + SSL 握手失败 + + + + HTTPS connection requested but SSL support not compiled in + HTTPS 连接需要 SSL,但它没有被编译进来 + + + + QHttpSocketEngine + + + Did not receive HTTP response from proxy + 未收到代理的HTTP响应 + + + + Error parsing authentication request from proxy + 解析代理的认证请求出错 + + + + Authentication required + 需要认证 + + + + Proxy denied connection + 代理拒绝连接 + + + + Error communicating with HTTP proxy + 和HTTP代理通讯时发生错误 + + + + Proxy server not found + 未找到代理服务器 + + + + Proxy connection refused + 代理连接被拒绝 + + + + Proxy server connection timed out + 代理服务器连接超时 + + + + Proxy connection closed prematurely + 代理连接过早关闭 + + + + QIBaseDriver + + + Error opening database + 打开数据库错误 + + + + Could not start transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QIBaseResult + + + Unable to create BLOB + 不能创建BLOB + + + + Unable to write BLOB + 不能写入BLOB + + + + Unable to open BLOB + 不能打开BLOB + + + + Unable to read BLOB + 不能读取BLOB + + + + + Could not find array + 不能找到数组 + + + + Could not get array data + 不能得到数组数据 + + + + Could not get query info + 不能得到查询信息 + + + + Could not start transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Could not allocate statement + 不能分配语句 + + + + Could not prepare statement + 不能准备语句 + + + + + Could not describe input statement + 不能描述输入语句 + + + + Could not describe statement + 不能描述语句 + + + + Unable to close statement + 不能关闭语句 + + + + Unable to execute query + 不能执行查询 + + + + Could not fetch next item + 不能获取下一项 + + + + Could not get statement info + 不能得到语句信息 + + + + QIODevice + + + Permission denied + 权限被拒绝 + + + + Too many open files + 太多打开的文件 + + + + No such file or directory + 没有这个文件或者目录 + + + + No space left on device + 设备上没有空间了 + + + + Unknown error + 未知的错误 + + + + QInputContext + + + XIM + XIM + + + + XIM input method + XIM输入法 + + + + Windows input method + Windows输入法 + + + + Mac OS X input method + Mac OS X输入法 + + + + QInputDialog + + + Enter a value: + 输入一个值: + + + + QLibrary + + QLibrary::load_sys: Cannot load %1 (%2) + QLibrary::load_sys: 不能载入%1 (%2) + + + QLibrary::unload_sys: Cannot unload %1 (%2) + QLibrary::unload_sys:不能卸载%1 (%2) + + + QLibrary::resolve_sys: Symbol "%1" undefined in %2 (%3) + QLibrary::resolve_sys: 符号“%1”在%2(%3)没有被定义 + + + + Could not mmap '%1': %2 + 不能映射”%1“:%2 + + + + Plugin verification data mismatch in '%1' + “%1“中的插件验证数据不匹配 + + + + Could not unmap '%1': %2 + 不能取消映射“%1“:%2 + + + + The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5] + 插件“%1”使用了不兼容的Qt库。(%2.%3.%4) [%5] + + + + The plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3" + 插件“%1“使用了不兼容的Qt库。期待的构建键是“%2“,得到的却是”%3“ + + + + Unknown error + 未知的错误 + + + + + The shared library was not found. + 共享库没有被找到。 + + + + The file '%1' is not a valid Qt plugin. + 文件“%1“不是有效的Qt插件。 + + + + The plugin '%1' uses incompatible Qt library. (Cannot mix debug and release libraries.) + 插件“%1“使用了不兼容的Qt库。(不能混合使用库的调试版本和发布版本。) + + + + + Cannot load library %1: %2 + 无法加载库%1:%2 + + + + + Cannot unload library %1: %2 + 无法卸载库%1:%2 + + + + + Cannot resolve symbol "%1" in %2: %3 + 无法解析%2中的符号“%1”:%3 + + + + QLineEdit + + + &Undo + 撤消(&U) + + + + &Redo + 恢复(&R) + + + + Cu&t + 剪切(&T) + + + + &Copy + 复制(&C) + + + + &Paste + 粘贴(&P) + + + + Delete + 删除 + + + + Select All + 选择全部 + + + + QLocalServer + + + + %1: Name error + %1: 名称错误 + + + + %1: Permission denied + %1:权限被拒绝 + + + + %1: Address in use + %1:地址正在被使用 + + + + + %1: Unknown error %2 + %1:未知错误 %2 + + + + QLocalSocket + + + + %1: Connection refused + %1:连接被拒绝 + + + + + %1: Remote closed + %1:远程已关闭 + + + + + + + %1: Invalid name + %1:无效名称 + + + + + %1: Socket access error + %1:套接字访问错误 + + + + + %1: Socket resource error + %1:套接字资源错误 + + + + + %1: Socket operation timed out + %1:套接字操作超时 + + + + + %1: Datagram too large + %1:数据报太大 + + + + + + %1: Connection error + %1:连接错误 + + + + + %1: The socket operation is not supported + %1:套接字操作不被支持 + + + + %1: Unknown error + %1:未知错误 + + + + + %1: Unknown error %2 + %1:未知错误 %2 + + + + QMYSQLDriver + + + Unable to open database ' + 不能打开数据库 + + + + Unable to connect + 不能连接 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QMYSQLResult + + + Unable to fetch data + 不能获取数据 + + + + Unable to execute query + 不能执行查询 + + + + Unable to store result + 不能存储结果 + + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to reset statement + 不能重置语句 + + + + Unable to bind value + 不能绑定值 + + + + Unable to execute statement + 不能执行语句 + + + + + Unable to bind outvalues + 不能绑定外值 + + + + Unable to store statement results + 不能存储语句结果 + + + + Unable to execute next query + 不能执行下一个查询 + + + + Unable to store next result + 不能存储下一个结果 + + + + QMdiArea + + + (Untitled) + (未命名的) + + + + QMdiSubWindow + + + %1 - [%2] + %1 - [%2] + + + + Close + 关闭 + + + + Minimize + 最小化 + + + + Restore Down + 向下恢复 + + + + &Restore + 恢复(&R) + + + + &Move + 移动(&M) + + + + &Size + 大小(&S) + + + + Mi&nimize + 最小化(&N) + + + + Ma&ximize + 最大化(&X) + + + + Stay on &Top + 总在最前(&T) + + + + &Close + 关闭(&C) + + + + - [%1] + - [%1] + + + + Maximize + 最大化 + + + + Unshade + 取消遮蔽 + + + + Shade + 遮蔽 + + + + Restore + 恢复 + + + + Help + 帮助 + + + + Menu + 菜单 + + + + QMenu + + + + Close + 关闭 + + + + + Open + 打开 + + + + + + Execute + 执行 + + + + QMenuBar + + About + 关于 + + + Config + 配置 + + + Preference + 首选项 + + + Options + 选项 + + + Setting + 设置 + + + Setup + 安装 + + + Quit + 退出 + + + Exit + 退出 + + + About %1 + 关于%1 + + + About Qt + 关于Qt + + + Preferences + 首选项 + + + Quit %1 + 退出%1 + + + + QMessageBox + + + Help + 帮助 + + + + + + + OK + 确定 + + + + About Qt + 关于Qt + + + <p>This program uses Qt version %1.</p> + <p>这个程序使用的是Qt %1版。</p> + + + + Show Details... + 显示细节…… + + + + Hide Details... + 隐藏细节…… + + + + <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.</p><p>Qt is available under three different licensing options designed to accommodate the needs of our various users.</p>Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 2.1 or GNU GPL version 3.0.</p><p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt applications (proprietary or open source) provided you can comply with the terms and conditions of the GNU LGPL version 2.1.</p><p>Qt licensed under the GNU General Public License version 3.0 is appropriate for the development of Qt applications where you wish to use such applications in combination with software subject to the terms of the GNU GPL version 3.0 or where you are otherwise willing to comply with the terms of the GNU GPL version 3.0.</p><p>Please see <a href="http://qt.nokia.com/products/licensing">qt.nokia.com/products/licensing</a> for an overview of Qt licensing.</p><p>Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).</p><p>Qt is a Nokia product. See <a href="http://qt.nokia.com/">qt.nokia.com</a> for more information.</p> + + + + <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.</p><p>Qt is a Nokia product. See <a href="http://qt.nokia.com/">qt.nokiae.com</a> for more information.</p> + <h3>关于Qt</h3>%1<p>Qt是一个用于跨平台应用程序开发的C++工具包。</p><p>对于MS&nbsp;Windows、Mac&nbsp;OS&nbsp;X、Linux和所有主流商业Unix,Qt提供了单一源程序的可移植性。Qt也有用于嵌入式Linux和Windows CE的版本。</p><p>Qt是Nokia的产品。有关更多信息,请参考<a href="http://qt.nokia.com/">qt.nokia.com</a>。</p> + + + <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <a href="http://qt.nokia.com/company/model/">qt.nokia.com/company/model/</a> for an overview of Qt licensing.</p> + <p>这个程序使用了Qt %1开源版本。</p><p>Qt开源版本只用于开源应用程序的开发。如果要开发私有(闭源)软件,你需要一个商业的Qt协议。</p><p>有关Qt协议的概览,请参考<a href="http://qt.nokia.com/company/model/">qt.nokia.com/company/model/</a>。</p> + + + <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt Embedded.</p><p>Qt is a Trolltech product. See <a href="http://qt.nokia.com/">qt.nokia.com</a> for more information.</p> + <h3>关于Qt</h3>%1<p>Qt是一个用于跨平台应用程序开发的C++工具包。</p><p>对于MS&nbsp;Windows、Mac&nbsp;OS&nbsp;X、Linux和所有主流商业Unix,Qt提供了单一源程序的可移植性。Qt对于嵌入式平台也是可用的,在嵌入式平台上它被称为Qt Embedded。</p><p>Qt是Trolltech的产品。有关更多信息,请参考<a href="http://qt.nokia.com/">qt.nokia.com</a>。</p> + + + + QMultiInputContext + + + Select IM + 选择输入法 + + + + QMultiInputContextPlugin + + + Multiple input method switcher + 多输入法切换器 + + + + Multiple input method switcher that uses the context menu of the text widgets + 使用文本窗口部件上下文菜单的多输入法切换器 + + + + QNativeSocketEngine + + + The remote host closed the connection + 远端主机关闭了这个连接 + + + + Network operation timed out + 网络操作超时 + + + + Out of resources + 资源耗尽了 + + + + Unsupported socket operation + 不被支持的套接字操作 + + + + Protocol type not supported + 协议类型不被支持 + + + + Invalid socket descriptor + 无效的套接字描述符 + + + + Network unreachable + 网络不能访问 + + + + Permission denied + 权限被拒绝 + + + + Connection timed out + 连接超时 + + + + Connection refused + 连接被拒绝 + + + + The bound address is already in use + 要启用的地址已经被使用 + + + + The address is not available + 这个地址不可用 + + + + The address is protected + 这个地址被保护了 + + + + Unable to send a message + 不能发送一个消息 + + + + Unable to receive a message + 不能接收一个消息 + + + + Unable to write + 不能写入 + + + + Network error + 网络错误 + + + + Another socket is already listening on the same port + 另一个套接字已经正在监听同一端口 + + + + Unable to initialize non-blocking socket + 不能初始化非阻塞套接字 + + + + Unable to initialize broadcast socket + 不能初始化广播套接字 + + + + Attempt to use IPv6 socket on a platform with no IPv6 support + 试图在不支持IPv6支持的平台上使用IPv6套接字 + + + + Host unreachable + 主机不能访问 + + + + Datagram was too large to send + 不能发送过大的数据报 + + + + Operation on non-socket + 对非套接字操作 + + + + Unknown error + 未知的错误 + + + + The proxy type is invalid for this operation + 对于这个操作代理类型是无效的。 + + + + QNetworkAccessCacheBackend + + + Error opening %1 + 打开%1发生错误 + + + + QNetworkAccessFileBackend + + + Request for opening non-local file %1 + 正在打开非本地文件 %1 的请求 + + + + Error opening %1: %2 + 打开 %1 错误:%2 + + + + Write error writing to %1: %2 + 写入 %1 错误:%2 + + + + Cannot open %1: Path is a directory + 无法打开 %1:路径是一个目录 + + + + Read error reading from %1: %2 + 读取 %1 错误:%2 + + + + QNetworkAccessFtpBackend + + + No suitable proxy found + 未找到合适的代理 + + + + Cannot open %1: is a directory + 无法读取 %1:是一个目录 + + + + Logging in to %1 failed: authentication required + 登入 %1 失败:需要验证 + + + + Error while downloading %1: %2 + 下载 %1 时错误:%2 + + + + Error while uploading %1: %2 + 上载 %1 时错误:%2 + + + + QNetworkAccessHttpBackend + + + No suitable proxy found + 未找到合适的代理 + + + + QNetworkReply + + + Error downloading %1 - server replied: %2 + 下载 %1 错误 - 服务器回复:%2 + + + + Protocol "%1" is unknown + 协议“%1”是未知的 + + + + QNetworkReplyImpl + + + + Operation canceled + 操作被取消 + + + + QOCIDriver + + + Unable to logon + 不能登录 + + + + Unable to initialize + QOCIDriver + 不能初始化 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QOCIResult + + + + + Unable to bind column for batch execute + 不能绑定批处理执行的列 + + + + Unable to execute batch statement + 不能执行批处理语句 + + + + Unable to goto next + 不能进入下一个 + + + + Unable to alloc statement + 不能分配语句 + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to bind value + 不能绑定值 + + + Unable to execute select statement + 不能执行选择语句 + + + + Unable to execute statement + 不能执行语句 + + + + QODBCDriver + + + Unable to connect + 不能连接 + + + + Unable to connect - Driver doesn't support all needed functionality + 不能连接—驱动程序不支持所有功能 + + + + Unable to disable autocommit + 不能禁止自动提交 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + Unable to enable autocommit + 不能打开自动提交 + + + + QODBCResult + + + + QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration + QODBCResult::reset: 不能把“SQL_CURSOR_STATIC”设置为语句属性。请检查你的ODBC驱动程序设置。 + + + + + Unable to execute statement + 不能执行语句 + + + + Unable to fetch next + 不能获取下一个 + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to bind variable + 不能帮定变量 + + + + + + Unable to fetch last + 不能获取最后一个 + + + + Unable to fetch + 不能获取 + + + + Unable to fetch first + 不能获取第一个 + + + + Unable to fetch previous + 不能获取上一个 + + + + QObject + + + Home + + + + + Operation not supported on %1 + 在 %1 上不被支持的操作 + + + + Invalid URI: %1 + 无效的 URI:%1 + + + + Write error writing to %1: %2 + 写入 %1 错误:%2 + + + + Read error reading from %1: %2 + 读取 %1 错误:%2 + + + + Socket error on %1: %2 + %1 上的套接字错误:%2 + + + + Remote host closed the connection prematurely on %1 + 远程主机过早地关闭了在 %1 上的这个连接 + + + + Protocol error: packet of size 0 received + 协议错误:收到了大小为 0 的包 + + + + + No host name given + 未指定主机名 + + + + QPPDOptionsModel + + + Name + 名称 + + + + Value + + + + + QPSQLDriver + + + Unable to connect + 不能连接 + + + + Could not begin transaction + 不能开始事务 + + + + Could not commit transaction + 不能提交事务 + + + + Could not rollback transaction + 不能回滚事务 + + + + Unable to subscribe + 不能订阅 + + + + Unable to unsubscribe + 不能取消订阅 + + + + QPSQLResult + + + Unable to create query + 不能创建查询 + + + + Unable to prepare statement + 不能准备语句 + + + + QPageSetupWidget + + + Centimeters (cm) + 厘米 (cm) + + + + Millimeters (mm) + 毫米 (mm) + + + + Inches (in) + 英寸 (in) + + + + Points (pt) + 点 (pt) + + + + Form + 窗体 + + + + Paper + 纸张 + + + + Page size: + 纸张大小: + + + + Width: + 宽度: + + + + Height: + 高度: + + + + Paper source: + 纸张源: + + + + Orientation + 方向 + + + + Portrait + 纵向 + + + + Landscape + 横向 + + + + Reverse landscape + 反向横向 + + + + Reverse portrait + 反向纵向 + + + + Margins + 边距 + + + + top margin + 上边距 + + + + left margin + 左边距 + + + + right margin + 右边距 + + + + bottom margin + 下边距 + + + + QPluginLoader + + + Unknown error + 未知的错误 + + + + The plugin was not loaded. + 插件没有被载入。 + + + + QPrintDialog + + + locally connected + 本地已经连接的 + + + + + Aliases: %1 + 别名:%1 + + + + + unknown + 未知的 + + + + Print all + 打印全部 + + + + Print selection + 打印选择 + + + + Print range + 打印范围 + + + + A0 (841 x 1189 mm) + A0 (841 x 1189 毫米) + + + + A1 (594 x 841 mm) + A1 (594 x 841 毫米) + + + + A2 (420 x 594 mm) + A2 (420 x 594 毫米) + + + + A3 (297 x 420 mm) + A3 (297 x 420 毫米) + + + + A4 (210 x 297 mm, 8.26 x 11.7 inches) + A4 (210 x 297 毫米,8.26 x 11.7 英寸) + + + + A5 (148 x 210 mm) + A5 (148 x 210 毫米) + + + + A6 (105 x 148 mm) + A6 (105 x 148 毫米) + + + + A7 (74 x 105 mm) + A7 (74 x 105 毫米) + + + + A8 (52 x 74 mm) + A8 (52 x 74 毫米) + + + + A9 (37 x 52 mm) + A9 (37 x 52 毫米) + + + + B0 (1000 x 1414 mm) + B0 (1000 x 1414 毫米) + + + + B1 (707 x 1000 mm) + B1 (707 x 1000 毫米) + + + + B2 (500 x 707 mm) + B2 (500 x 707 毫米) + + + + B3 (353 x 500 mm) + B3 (353 x 500 毫米) + + + + B4 (250 x 353 mm) + B4 (250 x 353 毫米) + + + + B5 (176 x 250 mm, 6.93 x 9.84 inches) + B5 (176 x 250 毫米,6.93 x 9.84 英寸) + + + + B6 (125 x 176 mm) + B6 (125 x 176 毫米) + + + + B7 (88 x 125 mm) + B7 (88 x 125 毫米) + + + + B8 (62 x 88 mm) + B8 (62 x 88 毫米) + + + + B9 (44 x 62 mm) + B9 (44 x 62 毫米) + + + + B10 (31 x 44 mm) + B10 (31 x 44 毫米) + + + + C5E (163 x 229 mm) + C5E (163 x 229 毫米) + + + + DLE (110 x 220 mm) + DLE (110 x 220 毫米) + + + + Executive (7.5 x 10 inches, 191 x 254 mm) + Executive (7.5 x 10 英寸,191 x 254 毫米) + + + + Folio (210 x 330 mm) + Folio (210 x 330 毫米) + + + + Ledger (432 x 279 mm) + Ledger (432 x 279 毫米) + + + + Legal (8.5 x 14 inches, 216 x 356 mm) + Legal (8.5 x 14 英寸,216 x 356 毫米) + + + + Letter (8.5 x 11 inches, 216 x 279 mm) + Letter (8.5 x 11 英寸,216 x 279 毫米) + + + + Tabloid (279 x 432 mm) + Tabloid (279 x 432 毫米) + + + + US Common #10 Envelope (105 x 241 mm) + 美国普通10号信封 (105 x 241 毫米) + + + + OK + 确定 + + + + + + Print + 打印 + + + + Print To File ... + 打印到文件…… + + + + File %1 is not writable. +Please choose a different file name. + 文件%1不可写。 +请选择一个不同的文件名。 + + + + %1 already exists. +Do you want to overwrite it? + %1已经存在。 +你想覆盖它么? + + + + File exists + 文件存在 + + + + <qt>Do you want to overwrite it?</qt> + <qt>你想覆盖它么?</qt> + + + + %1 is a directory. +Please choose a different file name. + %1是目录。 +请选择一个不同的文件名。 + + + + The 'From' value cannot be greater than the 'To' value. + “从”的数值不能大于“到”的数值。 + + + + A0 + A0 + + + + A1 + A1 + + + + A2 + A2 + + + + A3 + A3 + + + + A4 + A4 + + + + A5 + A5 + + + + A6 + A6 + + + + A7 + A7 + + + + A8 + A8 + + + + A9 + A9 + + + + B0 + B0 + + + + B1 + B1 + + + + B2 + B2 + + + + B3 + B3 + + + + B4 + B4 + + + + B5 + B5 + + + + B6 + B6 + + + + B7 + B7 + + + + B8 + B8 + + + + B9 + B9 + + + + B10 + B10 + + + + C5E + C5E + + + + DLE + DLE + + + + Executive + 决策文书 + + + + Folio + 对开纸 + + + + Ledger + 帐页 + + + + Legal + 法律文书 + + + + Letter + 信纸 + + + + Tabloid + 小型报纸 + + + + US Common #10 Envelope + 美国普通10号信封 + + + + Custom + 自定义 + + + + + &Options >> + 选项(&O) >> + + + + &Print + 打印(&P) + + + + &Options << + 选项(&O) << + + + + Print to File (PDF) + 打印到文件(PDF) + + + + Print to File (Postscript) + 打印到文件(Postscript) + + + + Local file + 本地文件 + + + + Write %1 file + 写入 %1 文件 + + + + QPrintPreviewDialog + + + + Page Setup + 页面设置 + + + + %1% + %1% + + + + Print Preview + 打印预览 + + + + Next page + 下一页 + + + + Previous page + 上一页 + + + + First page + 第一页 + + + + Last page + 最后一页 + + + + Fit width + 适应宽度 + + + + Fit page + 适应页面 + + + + Zoom in + 放大 + + + + Zoom out + 缩小 + + + + Portrait + 纵向 + + + + Landscape + 横向 + + + + Show single page + 显示单页 + + + + Show facing pages + 显示当前页 + + + + Show overview of all pages + 显示所有页的概览 + + + + Print + 打印 + + + + Page setup + 打印设置 + + + + Close + 关闭 + + + + Export to PDF + 导出为PDF + + + + Export to PostScript + 导出为PostScript + + + + QPrintPropertiesWidget + + + Form + 窗体 + + + + Page + + + + + Advanced + 高级 + + + + QPrintSettingsOutput + + + Form + 窗体 + + + + Copies + 拷贝 + + + + Print range + 打印范围 + + + + Print all + 打印全部 + + + + Pages from + 页数从 + + + + to + + + + + Selection + 选择 + + + + Output Settings + 输出设置 + + + + Copies: + 备份: + + + + Collate + 校对 + + + + Reverse + 反向 + + + + Options + 选项 + + + + Color Mode + 彩色模式 + + + + Color + 彩色 + + + + Grayscale + 灰度 + + + + Duplex Printing + 两部分打印 + + + + None + + + + + Long side + 长侧 + + + + Short side + 短侧 + + + + QPrintWidget + + + Form + 窗体 + + + + Printer + 打印机 + + + + &Name: + 名称(&N): + + + + P&roperties + 属性(&R) + + + + Location: + 位置: + + + + Preview + 预览 + + + + Type: + 类型: + + + + Output &file: + 输出文件(&F): + + + + ... + ... + + + + QProcess + + + + Could not open input redirection for reading + 无法打开用于读取的输入重定向 + + + + + Could not open output redirection for writing + 无法打开用于写入的输出重定向 + + + + Resource error (fork failure): %1 + 资源错误(fork失败):%1 + + + + + + + + + + + + Process operation timed out + 进程处理超时 + + + + + + + Error reading from process + 从进程中读取时发生错误 + + + + + + Error writing to process + 向进程写入时发生错误 + + + + Process crashed + 进程已崩溃 + + + + No program defined + + + + + Process failed to start + 启动进程失败 + + + + QProgressDialog + + + Cancel + 撤消 + + + + QPushButton + + + Open + 打开 + + + + QRadioButton + + + Check + 选中 + + + + QRegExp + + + no error occurred + 没有错误发生 + + + + disabled feature used + 使用了失效的特效 + + + + bad char class syntax + 错误的字符类语法 + + + + bad lookahead syntax + 错误的预测语法 + + + + bad repetition syntax + 错误的重复语法 + + + + invalid octal value + 无效的八进制数值 + + + + missing left delim + 找不到左分隔符 + + + + unexpected end + 意外的终止 + + + + met internal limit + 遇到内部限制 + + + + QSQLite2Driver + + + Error to open database + 打开数据库错误 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback Transaction + 不能回滚事务 + + + + QSQLite2Result + + + Unable to fetch results + 不能获取结果 + + + + Unable to execute statement + 不能执行语句 + + + + QSQLiteDriver + + + Error opening database + 打开数据库错误 + + + + Error closing database + 关闭数据库错误 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QSQLiteResult + + + + + Unable to fetch row + 不能获取行 + + + + Unable to execute statement + 不能执行语句 + + + + Unable to reset statement + 不能重置语句 + + + + Unable to bind parameters + 不能绑定参数 + + + + Parameter count mismatch + 参数数量不匹配 + + + + No query + 没有查询 + + + + QScrollBar + + + Scroll here + 滚动到这里 + + + + Left edge + 左边缘 + + + + Top + 顶部 + + + + Right edge + 右边缘 + + + + Bottom + 底部 + + + + Page left + 左一页 + + + + + Page up + 上一页 + + + + Page right + 右一页 + + + + + Page down + 下一页 + + + + Scroll left + 向左滚动 + + + + Scroll up + 向上滚动 + + + + Scroll right + 向右滚动 + + + + Scroll down + 向下滚动 + + + + Line up + 向上排列 + + + + Position + 位置 + + + + Line down + 向下排列 + + + + QSharedMemory + + + %1: unable to set key on lock + %1:无法设置锁定的键 + + + + %1: create size is less then 0 + %1:创建的大小小于 0 + + + + + %1: unable to lock + %1:无法锁定 + + + + %1: unable to unlock + %1:无法取消锁定 + + + + + %1: permission denied + %1:权限被拒绝 + + + + + %1: already exists + %1:已经存在 + + + + + %1: doesn't exists + %1:不存在 + + + + + %1: out of resources + %1:资源耗尽了 + + + + + %1: unknown error %2 + %1:未知错误 %2 + + + + %1: key is empty + %1:键是空的 + + + + %1: unix key file doesn't exists + %1:Unix 键文件不存在 + + + + %1: ftok failed + %1:ftok 失败 + + + + + %1: unable to make key + %1:不能制造键 + + + + %1: system-imposed size restrictions + %1:系统预设大小限制 + + + + %1: not attached + %1:没有附加 + + + + %1: invalid size + %1:无效大小 + + + + %1: key error + %1: 键错误 + + + + %1: size query failed + %1:大小查询失败 + + + + QShortcut + + + Space + 空格 + + + + Esc + Esc + + + + Tab + Tab + + + + Backtab + Backtab + + + + Backspace + Backspace + + + + Return + Return + + + + Enter + Enter + + + + Ins + Ins + + + + Del + Del + + + + Pause + Pause + + + + Print + Print + + + + SysReq + SysReq + + + + Home + Home + + + + End + End + + + + Left + Left + + + + Up + Up + + + + Right + Right + + + + Down + Down + + + + PgUp + PgUp + + + + PgDown + PgDown + + + + CapsLock + CapsLock + + + + NumLock + NumLock + + + + ScrollLock + ScrollLock + + + + Menu + Menu + + + + Help + Help + + + + Back + 后退 + + + + Forward + 前进 + + + + Stop + 停止 + + + + Refresh + 刷新 + + + + Volume Down + 调小音量 + + + + Volume Mute + 静音 + + + + Volume Up + 调大音量 + + + + Bass Boost + 低音增强 + + + + Bass Up + 调大低音 + + + + Bass Down + 调小低音 + + + + Treble Up + 调大高音 + + + + Treble Down + 调小高音 + + + + Media Play + 多媒体播放 + + + + Media Stop + 多媒体停止 + + + + Media Previous + 上一个多媒体 + + + + Media Next + 下一个多媒体 + + + + Media Record + 多媒体记录 + + + + Favorites + 最喜爱的 + + + + Search + 搜索 + + + + Standby + 等待 + + + + Open URL + 打开URL + + + + Launch Mail + 启动邮件 + + + + Launch Media + 启动多媒体 + + + + Launch (0) + 启动 (0) + + + + Launch (1) + 启动 (1) + + + + Launch (2) + 启动 (2) + + + + Launch (3) + 启动 (3) + + + + Launch (4) + 启动 (4) + + + + Launch (5) + 启动 (5) + + + + Launch (6) + 启动 (6) + + + + Launch (7) + 启动 (7) + + + + Launch (8) + 启动 (8) + + + + Launch (9) + 启动 (9) + + + + Launch (A) + 启动 (A) + + + + Launch (B) + 启动 (B) + + + + Launch (C) + 启动 (C) + + + + Launch (D) + 启动 (D) + + + + Launch (E) + 启动 (E) + + + + Launch (F) + 启动 (F) + + + + Print Screen + Print Screen + + + + Page Up + Page Up + + + + Page Down + Page Down + + + + Caps Lock + Caps Lock + + + + Num Lock + Num Lock + + + + Number Lock + Number Lock + + + + Scroll Lock + Scroll Lock + + + + Insert + Insert + + + + Delete + Delete + + + + Escape + Escape + + + + System Request + System Request + + + + Select + 选择 + + + + Yes + + + + + No + + + + + Context1 + 上下文1 + + + + Context2 + 上下文2 + + + + Context3 + 上下文3 + + + + Context4 + 上下文4 + + + + Call + 呼叫 + + + + Hangup + 挂起 + + + + Flip + 翻转 + + + + + Ctrl + Ctrl + + + + + Shift + Shift + + + + + Alt + Alt + + + + + Meta + Meta + + + + + + + + + + + F%1 + F%1 + + + + Home Page + 主页 + + + + QSlider + + + Page left + 左一页 + + + + Page up + 上一页 + + + + Position + 位置 + + + + Page right + 右一页 + + + + Page down + 下一页 + + + + QSocks5SocketEngine + + + Connection to proxy refused + 代理拒绝连接 + + + + Connection to proxy closed prematurely + 代理连接过早关闭 + + + + Proxy host not found + 代理主机未找到 + + + + Connection to proxy timed out + 代理连接超时 + + + + Proxy authentication failed + 代理认证失败 + + + + Proxy authentication failed: %1 + 代理认证失败: %1 + + + + SOCKS version 5 protocol error + SOCKS版本5协议错误 + + + + General SOCKSv5 server failure + 常规服务器失败 + + + + Connection not allowed by SOCKSv5 server + 连接不被SOCKSv5服务器允许 + + + + TTL expired + TTL已过期 + + + + SOCKSv5 command not supported + 不支持的SOCKSv5命令 + + + + Address type not supported + 不支持的地址类型 + + + + Unknown SOCKSv5 proxy error code 0x%1 + 未知SOCKSv5代理,错误代码 0x%1 + + + Socks5 timeout error connecting to socks server + 连接到套接字服务器的时候,Socks5超时错误 + + + + Network operation timed out + 网络操作超时 + + + + QSpinBox + + + More + 更多 + + + + Less + 更少 + + + + QSql + + + Delete + 删除 + + + + Delete this record? + 删除这条记录? + + + + + + Yes + + + + + + + No + + + + + Insert + 插入 + + + + Update + 更新 + + + + Save edits? + 保存编辑? + + + + Cancel + 取消 + + + + Confirm + 确认 + + + + Cancel your edits? + 取消您的编辑? + + + + QSslSocket + + + Unable to write data: %1 + 不能写入数据:%1 + + + + Error while reading: %1 + 读取时错误:%1 + + + + Error during SSL handshake: %1 + SSL握手错误:%1 + + + + Error creating SSL context (%1) + 创建SSL上下文错误(%1) + + + + Invalid or empty cipher list (%1) + 无效或者空白的密码列表(%1) + + + + Error creating SSL session, %1 + 创建SSL会话错误,%1 + + + + Error creating SSL session: %1 + 创建SSL会话错误:%1 + + + + Cannot provide a certificate with no key, %1 + 不能提供没有键的证书,%1 + + + + Error loading local certificate, %1 + 不能载入本地证书,%1 + + + + Error loading private key, %1 + 不能载入私有键,%1 + + + + Private key does not certificate public key, %1 + 私有键不能验证公有键,%1 + + + + QSystemSemaphore + + + + %1: out of resources + %1:资源耗尽了 + + + + + %1: permission denied + %1:权限被拒绝 + + + + %1: already exists + %1:已经存在 + + + + %1: does not exist + %1:不存在 + + + + + %1: unknown error %2 + %1:未知错误 %2 + + + + QTDSDriver + + + Unable to open connection + 不能打开连接 + + + + Unable to use database + 不能使用数据库 + + + + QTabBar + + + Scroll Left + 向左滚动 + + + + Scroll Right + 向右滚动 + + + + QTcpServer + + + Operation on socket is not supported + socket操作不被支持 + + + + QTextControl + + + &Undo + 撤消(&U) + + + + &Redo + 恢复(&R) + + + + Cu&t + 剪切(&T) + + + + &Copy + 复制(&C) + + + + Copy &Link Location + 复制链接位置(&L) + + + + &Paste + 粘贴(&P) + + + + Delete + 删除 + + + + Select All + 选择全部 + + + + QToolButton + + + + Press + 按下 + + + + + Open + 打开 + + + + QUdpSocket + + + This platform does not support IPv6 + 这个平台不支持IPv6 + + + + QUndoGroup + + + Undo + 撤销 + + + + Redo + 恢复 + + + + QUndoModel + + + <empty> + <空白> + + + + QUndoStack + + + Undo + 撤销 + + + + Redo + 恢复 + + + + QUnicodeControlCharacterMenu + + + LRM Left-to-right mark + LRM 从左到右标记 + + + + RLM Right-to-left mark + RLM 从右向左标记 + + + + ZWJ Zero width joiner + ZWJ 零宽度连接器 + + + + ZWNJ Zero width non-joiner + ZWNJ 零宽度非连接器 + + + + ZWSP Zero width space + ZWSP 零宽度空格 + + + + LRE Start of left-to-right embedding + LRE 开始从左到右嵌入 + + + + RLE Start of right-to-left embedding + RLE 开始从右向左嵌入 + + + + LRO Start of left-to-right override + LRO 开始从左向右覆盖 + + + + RLO Start of right-to-left override + RLO 开始从右向左覆盖 + + + + PDF Pop directional formatting + PDF 弹出方向格式 + + + + Insert Unicode control character + 插入Unicode控制字符 + + + + QWebFrame + + + Request cancelled + 请求被取消了 + + + + Request blocked + 请求被阻塞了 + + + + Cannot show URL + 无法显示 URL + + + + Frame load interruped by policy change + 因为策略调整打断了桢的加载 + + + + Cannot show mimetype + 无法显示 MIMETYPE + + + + File does not exist + 文件不存在 + + + + QWebPage + + + Bad HTTP request + 错误的 HTTP 请求 + + + + Submit + default label for Submit buttons in forms on web pages + 提交 + + + + Submit + Submit (input element) alt text for <input> elements with no alt, title, or value + 提交 + + + + Reset + default label for Reset buttons in forms on web pages + 重置 + + + + This is a searchable index. Enter search keywords: + text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index' + 这是一个可以搜索的索引。请输入要搜索的关键字: + + + + Choose File + title for file button used in HTML forms + 选择文件 + + + + No file selected + text to display in file button used in HTML forms when no file is selected + 没有文件被选择 + + + + Open in New Window + Open in New Window context menu item + 在新窗口中打开 + + + + Save Link... + Download Linked File context menu item + 保存链接... + + + + Copy Link + Copy Link context menu item + 复制链接 + + + + Open Image + Open Image in New Window context menu item + 打开图片 + + + + Save Image + Download Image context menu item + 保存图片 + + + + Copy Image + Copy Link context menu item + 复制图片 + + + + Open Frame + Open Frame in New Window context menu item + 打开框架 + + + + Copy + Copy context menu item + 复制 + + + + Go Back + Back context menu item + 后退 + + + + Go Forward + Forward context menu item + 前进 + + + + Stop + Stop context menu item + 停止 + + + + Reload + Reload context menu item + 重新载入 + + + + Cut + Cut context menu item + 剪切 + + + + Paste + Paste context menu item + 粘贴 + + + + No Guesses Found + No Guesses Found context menu item + 没有找到猜测 + + + + Ignore + Ignore Spelling context menu item + 忽略 + + + + Add To Dictionary + Learn Spelling context menu item + 添加到字典 + + + + Search The Web + Search The Web context menu item + 搜索网页 + + + + Look Up In Dictionary + Look Up in Dictionary context menu item + 在字典中查找 + + + + Open Link + Open Link context menu item + 打开链接 + + + + Ignore + Ignore Grammar context menu item + 忽略 + + + + Spelling + Spelling and Grammar context sub-menu item + 拼写 + + + + Show Spelling and Grammar + menu item title + 显示拼写和语法 + + + + Hide Spelling and Grammar + menu item title + 隐藏拼写和语法 + + + + Check Spelling + Check spelling context menu item + 检查拼写 + + + + Check Spelling While Typing + Check spelling while typing context menu item + 在输入时检查拼写 + + + + Check Grammar With Spelling + Check grammar with spelling context menu item + 检查语法和拼写 + + + + Fonts + Font context sub-menu item + 字体 + + + + Bold + Bold context menu item + 粗体 + + + + Italic + Italic context menu item + 意大利体 + + + + Underline + Underline context menu item + 下划线 + + + + Outline + Outline context menu item + 轮廓 + + + + Direction + Writing direction context sub-menu item + 方向 + + + + Text Direction + Text direction context sub-menu item + 文本方向 + + + + Default + Default writing direction context menu item + 默认 + + + + LTR + Left to Right context menu item + LTR + + + + RTL + Right to Left context menu item + RTL + + + + Inspect + Inspect Element context menu item + 检查 + + + + No recent searches + Label for only item in menu that appears when clicking on the search field image, when no searches have been performed + 没有最近的搜索 + + + + Recent searches + label for first item in the menu that appears when clicking on the search field image, used as embedded menu title + 最近的搜索 + + + + Clear recent searches + menu item in Recent Searches menu that empties menu's contents + 清除最近的搜索 + + + + Unknown + Unknown filesize FTP directory listing item + 未知的 + + + + %1 (%2x%3 pixels) + Title string for images + %1 (%2x%3 像素) + + + + Web Inspector - %2 + 网页检查员 - %2 + + + + Scroll here + 滚动到这里 + + + + Left edge + 左边缘 + + + + Top + 顶部 + + + + Right edge + 右边缘 + + + + Bottom + 底部 + + + + Page left + 左一页 + + + + Page up + 上一页 + + + + Page right + 右一页 + + + + Page down + 下一页 + + + + Scroll left + 向左滚动 + + + + Scroll up + 向上滚动 + + + + Scroll right + 向右滚动 + + + + Scroll down + 向下滚动 + + + + %n file(s) + number of chosen file + + %n 个文件 + + + + + JavaScript Alert - %1 + JavaScript警告 - %1 + + + + JavaScript Confirm - %1 + JavaScript确认 - %1 + + + + JavaScript Prompt - %1 + JavaScript提示 - %1 + + + + Move the cursor to the next character + 移动光标到下一个字符 + + + + Move the cursor to the previous character + 移动光标到上一个字符 + + + + Move the cursor to the next word + 移动光标到下一个单词 + + + + Move the cursor to the previous word + 移动光标到上一个单词 + + + + Move the cursor to the next line + 移动光标到下一行 + + + + Move the cursor to the previous line + 移动光标到上一行 + + + + Move the cursor to the start of the line + 移动光标到行首 + + + + Move the cursor to the end of the line + 移动光标到行尾 + + + + Move the cursor to the start of the block + 移动光标到块首 + + + + Move the cursor to the end of the block + 移动光标到块尾 + + + + Move the cursor to the start of the document + 移动光标到文件开头 + + + + Move the cursor to the end of the document + 移动光标到文件末尾 + + + + Select all + + + + + Select to the next character + 选中到下一个字符 + + + + Select to the previous character + 选中到上一个字符 + + + + Select to the next word + 选中到下一个单词 + + + + Select to the previous word + 选中到上一个单词 + + + + Select to the next line + 选中到下一行 + + + + Select to the previous line + 选中到上一行 + + + + Select to the start of the line + 选中到行首 + + + + Select to the end of the line + 选中到行尾 + + + + Select to the start of the block + 选中到块首 + + + + Select to the end of the block + 选中到块尾 + + + + Select to the start of the document + 选中到文件首 + + + + Select to the end of the document + 选中到文件尾 + + + + Delete to the start of the word + 删除到单词首 + + + + Delete to the end of the word + 删除到单词尾 + + + + Insert a new paragraph + + + + + Insert a new line + + + + + QWhatsThisAction + + + What's This? + 这是什么? + + + + QWidget + + + * + * + + + + QWizard + + + Go Back + 返回 + + + + Continue + 继续 + + + + Commit + 提交 + + + + Done + 完成 + + + Quit + 退出 + + + + Help + 帮助 + + + + < &Back + < 上一步(&B) + + + + &Finish + 完成(&F) + + + + Cancel + 取消 + + + + &Help + 帮助(&H) + + + + &Next + 下一步(&N) + + + + &Next > + 下一步(&N) > + + + + QWorkspace + + + &Restore + 恢复(&R) + + + + &Move + 移动(&M) + + + + &Size + 大小(&S) + + + + Mi&nimize + 最小化(&N) + + + + Ma&ximize + 最大化(&X) + + + + &Close + 关闭(&C) + + + + Stay on &Top + 总在最前(&T) + + + + + Sh&ade + 卷起(&A) + + + + + %1 - [%2] + %1 - [%2] + + + + Minimize + 最小化 + + + + Restore Down + 恢复 + + + + Close + 关闭 + + + + &Unshade + 展开(&U) + + + + QXml + + + no error occurred + 没有错误发生 + + + + error triggered by consumer + 由消费者出发的错误 + + + + unexpected end of file + 意外的文件终止 + + + + more than one document type definition + 多于一个的文档类型定义 + + + + error occurred while parsing element + 在解析元素的时候发生错误 + + + + tag mismatch + 标记不匹配 + + + + error occurred while parsing content + 在解析内容的时候发生错误 + + + + unexpected character + 意外的字符 + + + + invalid name for processing instruction + 无效的处理指令名称 + + + + version expected while reading the XML declaration + 在读取XML声明的时候,版本被期待 + + + + wrong value for standalone declaration + 错误的独立声明的值 + + + + encoding declaration or standalone declaration expected while reading the XML declaration + 在读取XML声明的时候,编码声明或者独立声明被期待 + + + + standalone declaration expected while reading the XML declaration + 在读取XML声明的时候,独立声明被期待 + + + + error occurred while parsing document type definition + 在解析文档类型定义的时候发生错误 + + + + letter is expected + 字符被期待 + + + + error occurred while parsing comment + 在解析注释的时候发生错误 + + + + error occurred while parsing reference + 在解析参考的时候发生错误 + + + + internal general entity reference not allowed in DTD + 在DTD中不允许使用内部解析的通用实体参考 + + + + external parsed general entity reference not allowed in attribute value + 在属性值中不允许使用外部解析的通用实体参考 + + + + external parsed general entity reference not allowed in DTD + 在DTD中不允许使用外部解析的通用实体参考 + + + + unparsed entity reference in wrong context + 没有解析的错误上下文中的实体参考 + + + + recursive entities + 嵌套实体 + + + + error in the text declaration of an external entity + 在一个外部实体的文本声明里有错误 + + + + QXmlStream + + + + Extra content at end of document. + 文档末尾有额外内容。 + + + + Invalid entity value. + 无效的实体值。 + + + + Invalid XML character. + 无效的XML字符。 + + + + Sequence ']]>' not allowed in content. + 内容中不允许有“]]>“序列。 + + + + Namespace prefix '%1' not declared + 命名空间的”%1“前缀没有被声明 + + + + Attribute redefined. + 属性重复定义。 + + + + Unexpected character '%1' in public id literal. + 在公有标识文本中有意外的字符”%1“。 + + + + Invalid XML version string. + 无效的XML版本字符串。 + + + + Unsupported XML version. + 不被支持的XML版本。 + + + + %1 is an invalid encoding name. + %1是无效的编码名称。 + + + + Encoding %1 is unsupported + 编码%1不被支持。 + + + + Standalone accepts only yes or no. + 独立运行只允许是或者否。 + + + + Invalid attribute in XML declaration. + 在XML声明中无效的属性。 + + + + Premature end of document. + 文档过早的结束。 + + + + Invalid document. + 无效的文档。 + + + + Expected + 期待的 + + + + , but got ' + ,但是得到的是“ + + + + Unexpected ' + 意外的“ + + + + Expected character data. + 期待的字符数据。 + + + + Recursive entity detected. + 检测到嵌套实体。 + + + + Start tag expected. + 开始期待的标记。 + + + + XML declaration not at start of document. + XML声明没有在文档的开始位置。 + + + + NDATA in parameter entity declaration. + 在参数实体声明中有NDATA。 + + + + %1 is an invalid processing instruction name. + %1 是无效的处理指令名称。 + + + + Invalid processing instruction name. + 无效的处理指令名称。 + + + + + + + Illegal namespace declaration. + 非法的命名空间声明。 + + + + Invalid XML name. + 无效的XML名称。 + + + + Opening and ending tag mismatch. + 开始标记和结束标记不匹配。 + + + + Reference to unparsed entity '%1'. + 未解析实体“%1“的引用。 + + + + + + Entity '%1' not declared. + 实体”%1“没有被声明。 + + + + Reference to external entity '%1' in attribute value. + 在属性值中的外部实体“%1”的引用。 + + + + Invalid character reference. + 无效的字符引用。 + + + + + Encountered incorrectly encoded content. + 遇到不正确的编码内容。 + + + + The standalone pseudo attribute must appear after the encoding. + 独立运行伪属性必须出现在编码之后。 + + + + %1 is an invalid PUBLIC identifier. + %1是一个无效的公有(PUBLIC)标识符。 + + + + QtXmlPatterns + + + An %1-attribute with value %2 has already been declared. + 带有值 %2 的 %1 属性已经声明过了。 + + + + An %1-attribute must have a valid %2 as value, which %3 isn't. + 一个 %1 属性必须带有一个有效的 %2 作为值,但 %3 却不是。 + + + + Network timeout. + 网络超时。 + + + + Element %1 can't be serialized because it appears outside the document element. + 元素 %1 不能被串行化,因为它出现在文档元素之外。 + + + Attribute element %1 can't be serialized because it appears at the top level. + 属性元素 %1 不能被串行化,因为它出现在最顶层。 + + + + Year %1 is invalid because it begins with %2. + %1 年是无效的,因为应该从 %2 开始。 + + + + Day %1 is outside the range %2..%3. + %1 日是在 %2...%3 范围之外的。 + + + + Month %1 is outside the range %2..%3. + %1 月是在 %2...%3 范围之外的。 + + + + Overflow: Can't represent date %1. + 溢出:无法呈现数据 %1。 + + + + Day %1 is invalid for month %2. + %1 日对于 %2 月是无效的。 + + + + Time 24:%1:%2.%3 is invalid. Hour is 24, but minutes, seconds, and milliseconds are not all 0; + 时间 24:%1:%2.%3 是无效的。小时是 24,但是分钟、秒和毫秒不全为 0; + + + + Time %1:%2:%3.%4 is invalid. + 时间 %1:%2:%3.%4 是无效的。 + + + + Overflow: Date can't be represented. + 溢出:数据无法被呈现。 + + + + + At least one component must be present. + 至少有一个组件被呈现。 + + + + At least one time component must appear after the %1-delimiter. + 至少一个时间组件必须出现在这个 %1 界限之后。 + + + + No operand in an integer division, %1, can be %2. + 在整数除法中没有操作数,%1,可以是 %2。 + + + + The first operand in an integer division, %1, cannot be infinity (%2). + 除法中的第一个操作数,%1,不能是无穷(%2)。 + + + + The second operand in a division, %1, cannot be zero (%2). + 除法中的第二个操作数,%1,不能是零(%2)。 + + + + %1 is not a valid value of type %2. + %1 不是类型为 %2 的有效值。 + + + + When casting to %1 from %2, the source value cannot be %3. + 当从 %2 抛出到 %1 时,源值不能是 %3。 + + + + Integer division (%1) by zero (%2) is undefined. + 整数除法(%1)除零(%2)是未定义的。 + + + + Division (%1) by zero (%2) is undefined. + 除法(%1)除零(%2)是未定义的。 + + + + Modulus division (%1) by zero (%2) is undefined. + 求模除法(%1)除零(%2)是未定义的。 + + + + + Dividing a value of type %1 by %2 (not-a-number) is not allowed. + 一个类型为 %1 的值除以 %2(不是一个数值)是不允许的。 + + + + Dividing a value of type %1 by %2 or %3 (plus or minus zero) is not allowed. + 一个类型为 %1 的值除以 %2 或者 %3(正负零)是不允许的。 + + + + Multiplication of a value of type %1 by %2 or %3 (plus or minus infinity) is not allowed. + 一个类型为 %1 的值乘以 %2 或者 %3(正负无穷)是不允许的。 + + + + A value of type %1 cannot have an Effective Boolean Value. + 一个类型为 %1 的值不能是一个有效的布尔值(Effective Boolean Value)。 + + + + Effective Boolean Value cannot be calculated for a sequence containing two or more atomic values. + 有效的布尔值(Effective Boolean Value)不能被用于计算一个包含两个或者更多原子值的序列。 + + + + Value %1 of type %2 exceeds maximum (%3). + 类型为 %2 的值 %1 超过了最大值(%3)。 + + + + Value %1 of type %2 is below minimum (%3). + 类型为 %2 的值 %1 超过了最小值(%3)。 + + + + A value of type %1 must contain an even number of digits. The value %2 does not. + 类型为 %1 的值必须包含偶数个数字。值 %2 不是这样的。 + + + + %1 is not valid as a value of type %2. + %1 不是类型为 %2 的有效值。 + + + + Operator %1 cannot be used on type %2. + 操作符 %1 不能被用于类型 %2。 + + + + Operator %1 cannot be used on atomic values of type %2 and %3. + 操作符 %1 不能被用于类型为 %2 和 %3 的原子值。 + + + + The namespace URI in the name for a computed attribute cannot be %1. + 一个被计算的属性的名称中的命名空间 URI 不能是 %1。 + + + + The name for a computed attribute cannot have the namespace URI %1 with the local name %2. + 一个被计算的属性的名称不能使用带有本地名称 %2 的命名空间 URI %1。 + + + + Type error in cast, expected %1, received %2. + 抛出类型错误,期望的是 %1,收到的是 %2。 + + + + When casting to %1 or types derived from it, the source value must be of the same type, or it must be a string literal. Type %2 is not allowed. + 当抛出到 %1 或者它的派生类时,源类型必须是同一类型,或者它必须是一个字符串类型。类型 %2 是不被允许的。 + + + + No casting is possible with %1 as the target type. + 无法以 %1 为目标类型进行抛出。 + + + + It is not possible to cast from %1 to %2. + 无法从 %1 抛出到 %2。 + + + + Casting to %1 is not possible because it is an abstract type, and can therefore never be instantiated. + 无法抛出到 %1,因为它是一个抽象类型,并且因此无法被实例化。 + + + + It's not possible to cast the value %1 of type %2 to %3 + 无法从类型为 %2 的值 %1 抛出到 %3 + + + + Failure when casting from %1 to %2: %3 + 从 %2 抛出到 %1 失败:%3 + + + + A comment cannot contain %1 + 注释不能包含 %1 + + + + A comment cannot end with a %1. + 注释不能以 %1 结尾。 + + + + No comparisons can be done involving the type %1. + 对于类型 %1 不能进行比较。 + + + + Operator %1 is not available between atomic values of type %2 and %3. + 在类型 %2 和 %3 的原子值之间,操作符 %1 是不可用的。 + + + + An attribute node cannot be a child of a document node. Therefore, the attribute %1 is out of place. + 一个属性节点不能是一个文档节点的子节点。因此,这个属性 %1 所在位置是不合适的。 + + + + A library module cannot be evaluated directly. It must be imported from a main module. + 一个库模块不能被直接评估。它必须从一个主模块中导入。 + + + + No template by name %1 exists. + 没有名为 %1 的模板存在。 + + + + A value of type %1 cannot be a predicate. A predicate must have either a numeric type or an Effective Boolean Value type. + 类型为 %1 的值不能被判断。一个判断必须是数值类型或者一个有效的布尔值(Effective Boolean Value)类型。 + + + + A positional predicate must evaluate to a single numeric value. + 一个定位判断必须评估一个单一数值。 + + + + The target name in a processing instruction cannot be %1 in any combination of upper and lower case. Therefore, is %2 invalid. + 一个处理指令中的目标名称不能是任何大小写混合的 %1。因此,%2 是无效的。 + + + + %1 is not a valid target name in a processing instruction. It must be a %2 value, e.g. %3. + %1 不是处理指令的有效目标名称。它必须是值 %2,例如 %3。 + + + + The last step in a path must contain either nodes or atomic values. It cannot be a mixture between the two. + 一个路径中的最后一步必须包含节点或者原子值。它不能是两者的一个组合。 + + + + The data of a processing instruction cannot contain the string %1 + 处理指令的数据不能包含字符串 %1 + + + + No namespace binding exists for the prefix %1 + 对于前缀 %1,没有存在绑定的命名空间。 + + + + No namespace binding exists for the prefix %1 in %2 + 对于 %2 中的前缀 %1,没有存在绑定的命名空间。 + + + + + %1 is an invalid %2 + %1 是一个无效的 %2。 + + + + %1 takes at most %n argument(s). %2 is therefore invalid. + + %1 最多可以有 %n 个参数。因此 %2 是无效的。 + + + + + %1 requires at least %n argument(s). %2 is therefore invalid. + + %1 需要至少 %n 个参数。因此 %2 是无效的。 + + + + + The first argument to %1 cannot be of type %2. It must be a numeric type, xs:yearMonthDuration or xs:dayTimeDuration. + %1 的第一个参数不能是类型 %2 的。它必须是数字类型的,xs:yearMonthDuration 或者 xs:dayTimeDuration。 + + + + The first argument to %1 cannot be of type %2. It must be of type %3, %4, or %5. + %1 的第一个参数不能是类型 %2 的。它必须是类型 %3、%4 或者 %5 的。 + + + + The second argument to %1 cannot be of type %2. It must be of type %3, %4, or %5. + %1 的第二个参数不能是类型 %2 的。它必须是类型 %3、%4 或者 %5 的。 + + + + %1 is not a valid XML 1.0 character. + %1 不是一个有效的 XML 1.0 字符。 + + + + The first argument to %1 cannot be of type %2. + %1 的第一个参数不能是类型 %2 的。 + + + + If both values have zone offsets, they must have the same zone offset. %1 and %2 are not the same. + 如果两个值都有区偏移(zone offset),它们必须拥有相同的区偏移。%1 和 %2 的区偏移是不同的。 + + + + %1 was called. + %1 被调用了。 + + + + %1 must be followed by %2 or %3, not at the end of the replacement string. + %1 必须被 %2 或者 %3 跟随,不能在替换字符串的末尾。 + + + + In the replacement string, %1 must be followed by at least one digit when not escaped. + 在这个替换字符串中,%1 在没有被转义的时候必须被至少一个数字跟随。 + + + + In the replacement string, %1 can only be used to escape itself or %2, not %3 + 在这个替换字符串中,%1 只能被用于转义它本身或者 %2,而不是 %3 + + + + %1 matches newline characters + %1 匹配了换行符 + + + + %1 and %2 match the start and end of a line. + %1 和 %2 匹配了一行的头和尾。 + + + + Matches are case insensitive + 匹配是大小写不敏感的 + + + + Whitespace characters are removed, except when they appear in character classes + 空白字符被移除了,除非当它们出现在字符类中 + + + + %1 is an invalid regular expression pattern: %2 + %1 是正则表达式中的一个无效模式:%2 + + + + %1 is an invalid flag for regular expressions. Valid flags are: + %1 是正则表达式中的一个无效标记。有效标记为: + + + + If the first argument is the empty sequence or a zero-length string (no namespace), a prefix cannot be specified. Prefix %1 was specified. + 如果第一个参数是空序列或者零长度字符串(无命名空间),那么就不能指定前缀。前缀 %1 被指定了。 + + + + It will not be possible to retrieve %1. + 将不能获取 %1。 + + + + The root node of the second argument to function %1 must be a document node. %2 is not a document node. + 函数 %1 的第二个参数的根节点必须是一个文档节点。%2 不是一个文档节点。 + + + + The default collection is undefined + 默认收集(collection)是未定义的 + + + + %1 cannot be retrieved + 无法获取 %1 + + + + The normalization form %1 is unsupported. The supported forms are %2, %3, %4, and %5, and none, i.e. the empty string (no normalization). + 不支持正规化(normalization)表单 %1。被支持的表单是 %2、%3、%4 和 %5,以及无,例如空字符串(无正规化)。 + + + + A zone offset must be in the range %1..%2 inclusive. %3 is out of range. + 区偏移(zone offset)必须在 %1...%2 范围之内。%3 是在范围之外的。 + + + + %1 is not a whole number of minutes. + %1 不是分钟的整数。 + + + + Required cardinality is %1; got cardinality %2. + 所需要的表间关系是 %1;得到的表间关系却是 %2。 + + + + The item %1 did not match the required type %2. + 项 %1 和所需的类型 %2 不匹配。 + + + + + %1 is an unknown schema type. + %1 是一个未知的方案类型。 + + + + Only one %1 declaration can occur in the query prolog. + 只有一个 %1 的声明可以出现在查询序言中。 + + + + The initialization of variable %1 depends on itself + 变量 %1 的初始化依赖于它本身 + + + + No variable by name %1 exists + 没有名称为 %1 的变量存在。 + + + + The variable %1 is unused + 变量 %1 没有被使用 + + + + Version %1 is not supported. The supported XQuery version is 1.0. + 不支持版本 %1。被支持的 XQuery 版本是 1.0。 + + + + The encoding %1 is invalid. It must contain Latin characters only, must not contain whitespace, and must match the regular expression %2. + 编码方式 %1 是无效的。它必须只包含拉丁字符,必须不包含空白符号,并且必须和正则表达式 %2 匹配。 + + + + No function with signature %1 is available + 没有签名为 %1 的可用函数。 + + + + + A default namespace declaration must occur before function, variable, and option declarations. + 默认命名空间声明必须出现在函数、变量和选项声明之前。 + + + + Namespace declarations must occur before function, variable, and option declarations. + 命名空间声明必须出现在函数、变量和选项声明之前。 + + + + Module imports must occur before function, variable, and option declarations. + 模块导入不能出现在函数、变量和选项声明之前。 + + + + It is not possible to redeclare prefix %1. + 不能重复声明前缀 %1。 + + + Only the prefix %1 can be declared to bind the namespace %2. By default, it is already bound to the prefix %1. + 至于前缀 %1 可以被声明为和命名空间 %2 绑定。默认情况下,它已经被绑定到前缀 %1。 + + + + Prefix %1 is already declared in the prolog. + 前缀 %1 在序言中已经声明过了。 + + + + The name of an option must have a prefix. There is no default namespace for options. + 一个选项的名称必须带有前缀。对于选项没有默认命名空间。 + + + + The Schema Import feature is not supported, and therefore %1 declarations cannot occur. + 不支持方案导入(Schema Import)特性,并且因此 %1 声明不能出现。 + + + + The target namespace of a %1 cannot be empty. + %1 的目标命名空间不能为空。 + + + + The module import feature is not supported + 不支持模块导入特性 + + + A variable by name %1 has already been declared in the prolog. + 名称为 %1 的变量已经在序言中声明过了。 + + + + No value is available for the external variable by name %1. + 名称为 %1 的外部变量并没有可用的值。 + + + The namespace for a user defined function cannot be empty(try the predefined prefix %1 which exists for cases like this) + 用户定义的函数的命名空间不能为空(请试试预定义的前缀 %1,它就是用于这种情况的)。 + + + + A construct was encountered which only is allowed in XQuery. + 遇到了一个只允许在XQuery中出现的构造。 + + + + A template by name %1 has already been declared. + 模板%1已被声明 + + + + The keyword %1 cannot occur with any other mode name. + 任何其他模式名称不能出现关键字%1。 + + + + The value of attribute %1 must of type %2, which %3 isn't. + 属性%1的值必须是类型%2,但%3不是。 + + + + The prefix %1 can not be bound. By default, it is already bound to the namespace %2. + 前缀%1不能被绑定。默认的,它已被绑定到名字空间%2。 + + + + A variable by name %1 has already been declared. + 变量%1已被声明。 + + + + A stylesheet function must have a prefixed name. + 样式表函数必须有一个前缀名。 + + + + The namespace for a user defined function cannot be empty (try the predefined prefix %1 which exists for cases like this) + 用户定义函数的名字空间不能为空(试用为这种情况而存在的预定义前缀%1) + + + + The namespace %1 is reserved; therefore user defined functions may not use it. Try the predefined prefix %2, which exists for these cases. + 命名空间 %1 是保留的;因此用户定义的函数不能使用它。请试试预定义的前缀 %2,它就是用于这种情况的。 + + + + The namespace of a user defined function in a library module must be equivalent to the module namespace. In other words, it should be %1 instead of %2 + 用户在一个库模块中定义的函数的命名空间必须和这个模块的命名空间一致。也就是说,它应该是 %1,而不是 %2 + + + + A function already exists with the signature %1. + 一个带有签名 %1 的函数已经存在。 + + + + No external functions are supported. All supported functions can be used directly, without first declaring them as external + 不支持外部函数。所有支持的函数必须可以被直接使用,不能把它们声明为外部的 + + + + An argument by name %1 has already been declared. Every argument name must be unique. + 名称为 %1 的参数已经被声明了。每个参数名称必须唯一。 + + + + When function %1 is used for matching inside a pattern, the argument must be a variable reference or a string literal. + 当函数%1被用于样式匹配时,参数必须是变量参考或者字符串。 + + + + In an XSL-T pattern, the first argument to function %1 must be a string literal, when used for matching. + 在XSL-T样式中,函数%1的第一个参数必须是字符串,以便用于匹配。 + + + + In an XSL-T pattern, the first argument to function %1 must be a literal or a variable reference, when used for matching. + 在XSL-T样式中,函数%1的第一个参数必须是文字或者变量参考,以便用于匹配。 + + + + In an XSL-T pattern, function %1 cannot have a third argument. + 在XSL-T样式中,函数%1不能有第三个参数。 + + + + In an XSL-T pattern, only function %1 and %2, not %3, can be used for matching. + 在XSL-T样式中,只用函数%1和%2可以用于匹配,%3不可以。 + + + + In an XSL-T pattern, axis %1 cannot be used, only axis %2 or %3 can. + 在XSL-T仰视中,不能使用%1轴,只能使用%2轴或者%3轴。 + + + + %1 is an invalid template mode name. + %1不是一个合法的模板模式名称。 + + + + The name of a variable bound in a for-expression must be different from the positional variable. Hence, the two variables named %1 collide. + 一个在 for 表达式中绑定的变量的名称必须和这个定位变量不同。因此,这两个名称为 %1 的变量冲突。 + + + + The Schema Validation Feature is not supported. Hence, %1-expressions may not be used. + 不支持方案验证特性(Schema Validation Feature)。因此,也许不能使用 %1 表达式。 + + + + None of the pragma expressions are supported. Therefore, a fallback expression must be present + 不支持任何编译指示表达式(pragma expression)。因此,必须呈现一个回调表达式(fallback expression)。 + + + + Each name of a template parameter must be unique; %1 is duplicated. + 每一个模板参数的名称都必须是唯一的;%2是重复的。 + + + + The %1-axis is unsupported in XQuery + 这个 %1 轴在 XQuery 中是不被支持的。 + + + + %1 is not a valid name for a processing-instruction. + %1不是一个处理指令的合法名称。 + + + + %1 is not a valid numeric literal. + %1 不是一个有效的数字语义。 + + + + No function by name %1 is available. + 没有名称为 %1 的可用函数。 + + + + The namespace URI cannot be the empty string when binding to a prefix, %1. + 当这个命名空间 URI 被绑定到一个前缀 %1 时,它不能是空字符串。 + + + + %1 is an invalid namespace URI. + %1 是一个无效的命名空间 URI。 + + + + It is not possible to bind to the prefix %1 + 无法绑定到这个前缀 %1。 + + + + Namespace %1 can only be bound to %2 (and it is, in either case, pre-declared). + 命名空间 %1 只能和 %2 绑定(并且如果是这种情况,需要提前声明)。 + + + + Prefix %1 can only be bound to %2 (and it is, in either case, pre-declared). + 前缀 %1 只能和 %2 绑定(并且如果是这种情况,需要提前声明)。 + + + + Two namespace declaration attributes have the same name: %1. + 两个命名空间声明属性使用了相同的名称:%1。 + + + + The namespace URI must be a constant and cannot use enclosed expressions. + 命名空间 URI 必须是一个常量并且不能使用封闭的表达式。 + + + + An attribute by name %1 has already appeared on this element. + 一个名称为 %1 的属性已经出现在这个元素中了。 + + + + A direct element constructor is not well-formed. %1 is ended with %2. + 一个直接元素构造器没有很好地形成。%1 后面跟着 %2。 + + + + The name %1 does not refer to any schema type. + 名称 %1 没有指向任何方案类型。 + + + + %1 is an complex type. Casting to complex types is not possible. However, casting to atomic types such as %2 works. + %1 是一个复杂类型。无法抛出到复杂类型。因此,抛出到例如 %2 这样的原子类型是可以的。 + + + + %1 is not an atomic type. Casting is only possible to atomic types. + %1 不是原子类型。只能抛出到原子类型。 + + + %1 is not a valid name for a processing-instruction. Therefore this name test will never match. + %1 不是处理指令的有效名称。因此这个名称测试永远不会匹配。 + + + + + %1 is not in the in-scope attribute declarations. Note that the schema import feature is not supported. + %1 不是范围内属性声明。注意方案导入特性是不被支持的。 + + + + The name of an extension expression must be in a namespace. + 一个扩展表达式的名称必须在一个命名空间中。 + + + + empty + 空白 + + + + zero or one + 零或者一 + + + + exactly one + 确切地一 + + + + one or more + 一或者更多 + + + + zero or more + 零或者更多 + + + + Required type is %1, but %2 was found. + 需要的类型是 %1,但是找到的是 %2。 + + + + Promoting %1 to %2 may cause loss of precision. + 把 %1 升级为 %2 会导致精度的损失。 + + + + The focus is undefined. + 焦点未定义。 + + + + It's not possible to add attributes after any other kind of node. + 不能在任何其它类型节点后添加属性。 + + + + An attribute by name %1 has already been created. + 一个名称为 %1 的属性已经被创建。 + + + + Only the Unicode Codepoint Collation is supported(%1). %2 is unsupported. + 只支持 Unicode 代码点校验(Unicode Codepoint Collation)(%1)。%2 是不被支持的。 + + + + Attribute %1 can't be serialized because it appears at the top level. + 属性 %1 不能被串行化,因为它出现在最顶层。 + + + + %1 is an unsupported encoding. + %1 是不被支持的编码。 + + + + %1 contains octets which are disallowed in the requested encoding %2. + %1包含了在请求编码%2中不允许的八进位值。 + + + + The codepoint %1, occurring in %2 using encoding %3, is an invalid XML character. + 在使用编码%3的%2中出现的代码点%1不是一个有效的XML字符。 + + + + Ambiguous rule match. + 含糊规则匹配。 + + + In a namespace constructor, the value for a namespace value cannot be an empty string. + 在一个命名空间构造中,命名空间的值不能为空字符串。 + + + + In a namespace constructor, the value for a namespace cannot be an empty string. + + + + + The prefix must be a valid %1, which %2 is not. + 前缀必须是有效的%1,而%2不是。 + + + + The prefix %1 cannot be bound. + 前缀%1不能被绑定。 + + + + Only the prefix %1 can be bound to %2 and vice versa. + 只有前缀%1可以绑定到%2,反之也一样 + + + + Circularity detected + 检测到环 + + + + The parameter %1 is required, but no corresponding %2 is supplied. + 需要参数%1,但是没有提供对应的%2。 + + + + The parameter %1 is passed, but no corresponding %2 exists. + 参数%1已传递,但没有相应的%2存在。 + + + + The URI cannot have a fragment + URI不能有片段 + + + + Element %1 is not allowed at this location. + 元素%1不能在这个位置。 + + + + Text nodes are not allowed at this location. + 文本节点不能在这个位置。 + + + + Parse error: %1 + 解析错误:%1 + + + + The value of the XSL-T version attribute must be a value of type %1, which %2 isn't. + XSL-T版本属性的值必须是%1类型的值,而%2不是。 + + + + Running an XSL-T 1.0 stylesheet with a 2.0 processor. + 在XSL-T 2.0处理器中运行一个1.0的样式表。 + + + + Unknown XSL-T attribute %1. + 未知的XSL-T属性%1。 + + + + Attribute %1 and %2 are mutually exclusive. + 属性%1和%2彼此互斥。 + + + + In a simplified stylesheet module, attribute %1 must be present. + 在一个简化样式表模块中,属性%1必须存在。 + + + + If element %1 has no attribute %2, it cannot have attribute %3 or %4. + 如果元素%1没有属性%2,那么它也不能有属性%3或者%4。 + + + + Element %1 must have at least one of the attributes %2 or %3. + 元素%1必须至少有属性%2或者%3其中一个。 + + + + At least one mode must be specified in the %1-attribute on element %2. + 在元素%2的%1属性中至少要指定一个模式。 + + + + Attribute %1 cannot appear on the element %2. Only the standard attributes can appear. + 属性%1不能出现在元素%2上。只有标准属性可以出现。 + + + + Attribute %1 cannot appear on the element %2. Only %3 is allowed, and the standard attributes. + 属性%1不能出现在元素%2上。只有%3和标准属性是允许的。 + + + + Attribute %1 cannot appear on the element %2. Allowed is %3, %4, and the standard attributes. + 属性%1不能出现在元素%2上。只有%3、%4和标准属性是允许的。 + + + + Attribute %1 cannot appear on the element %2. Allowed is %3, and the standard attributes. + 属性%1不能出现在元素%2上。只有%3和标准属性是允许的。 + + + + XSL-T attributes on XSL-T elements must be in the null namespace, not in the XSL-T namespace which %1 is. + XSL-T元素中的XSL-T属性必须放在空(null)命名空间中,而不是在XSL-T命名空间中,%1却是这个样子。 + + + + The attribute %1 must appear on element %2. + 属性%1必须出现在元素%2中。 + + + + The element with local name %1 does not exist in XSL-T. + 有本地名称%1的元素在XSL-T中不存在。 + + + + Element %1 must come last. + 元素%1必须最后出现。 + + + + At least one %1-element must occur before %2. + 至少一个元素%1要出现在%2之前。 + + + + Only one %1-element can appear. + 只能出现一个元素%1。 + + + + At least one %1-element must occur inside %2. + 至少一个元素%1要出现在%2之内。 + + + + When attribute %1 is present on %2, a sequence constructor cannot be used. + 当属性%1出现在%2中时,不能使用顺序构造。 + + + + Element %1 must have either a %2-attribute or a sequence constructor. + 元素%1必须有在一个%2属性或者顺序构造。 + + + + When a parameter is required, a default value cannot be supplied through a %1-attribute or a sequence constructor. + 当需要参数时,不能通过属性%1或者顺序构造提供默认值。 + + + + Element %1 cannot have children. + 元素%1不能有子元素。 + + + + Element %1 cannot have a sequence constructor. + 元素%1不能有顺序构造。 + + + + + The attribute %1 cannot appear on %2, when it is a child of %3. + 属性%1不能出现在%2中,因为它是%3的子元素。 + + + + A parameter in a function cannot be declared to be a tunnel. + 函数内的参数不能被声明为通道(tunnel)。 + + + + This processor is not Schema-aware and therefore %1 cannot be used. + 这个处理器不能感知Schema,因此%1不能被使用。 + + + + Top level stylesheet elements must be in a non-null namespace, which %1 isn't. + 顶级样式表元素必须是在非空命名空间中的,而%1不是。 + + + + The value for attribute %1 on element %2 must either be %3 or %4, not %5. + 元素%2中属性%1的值必须是%3或者%4,而不是%5。 + + + + Attribute %1 cannot have the value %2. + 属性%1的值不能是%2。 + + + + The attribute %1 can only appear on the first %2 element. + 属性%1只能出现在前%2个元素中。 + + + + At least one %1 element must appear as child of %2. + %2必须至少又一个子元素%1。 + + + + VolumeSlider + + + Muted + 已静音 + + + + + Volume: %1% + 音量:%1% + + + + WebCore::PlatformScrollbar + + Scroll here + 滚动到这里 + + + Left edge + 左边缘 + + + Top + 顶部 + + + Right edge + 右边缘 + + + Bottom + 底部 + + + Page left + 左一页 + + + Page up + 上一页 + + + Page right + 右一页 + + + Page down + 下一页 + + + Scroll left + 向左滚动 + + + Scroll up + 向上滚动 + + + Scroll right + 向右滚动 + + + Scroll down + 向下滚动 + + + + QPlatformTheme + + OK + 确定 + + + &OK + 确定(&O) + + + Cancel + 取消 + + + &Cancel + 取消(&C) + + + Yes + + + + &Yes + 是(&Y) + + + No + + + + &No + 否(&N) + + + Yes to All + 应用到所有 + + + Yes to &All + 应用到所有(&A) + + + + QGnomeTheme + + OK + 确定 + + + &OK + 确定(&O) + + + Cancel + 取消 + + + &Cancel + 取消(&C) + + + Yes + + + + &Yes + 是(&Y) + + + No + + + + &No + 否(&N) + + + Yes to All + 应用到所有 + + + Yes to &All + 应用到所有(&A) + + + diff --git a/modules/twainui/qwinhost.cpp b/modules/twainui/qwinhost.cpp new file mode 100644 index 00000000..86b81f36 --- /dev/null +++ b/modules/twainui/qwinhost.cpp @@ -0,0 +1,325 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +// Implementation of the QWinHost classes + +#ifdef QT3_SUPPORT +#undef QT3_SUPPORT +#endif + +#include "qwinhost.hpp" + +#include +#include + +#if QT_VERSION >= 0x050000 +#define QT_WA(unicode, ansi) unicode +#endif + +/*! + \class QWinHost qwinhost.h + \brief The QWinHost class provides an API to use native Win32 + windows in Qt applications. + + QWinHost exists to provide a QWidget that can act as a parent for + any native Win32 control. Since QWinHost is a proper QWidget, it + can be used as a toplevel widget (e.g. 0 parent) or as a child of + any other QWidget. + + QWinHost integrates the native control into the Qt user interface, + e.g. handles focus switches and laying out. + + Applications moving to Qt may have custom Win32 controls that will + take time to rewrite with Qt. Such applications can use these + custom controls as children of QWinHost widgets. This allows the + application's user interface to be replaced gradually. + + When the QWinHost is destroyed, and the Win32 window hasn't been + set with setWindow(), the window will also be destroyed. +*/ + +/*! + Creates an instance of QWinHost. \a parent and \a f are + passed on to the QWidget constructor. The widget has by default + no background. + + \warning You cannot change the parent widget of the QWinHost instance + after the native window has been created, i.e. do not call + QWidget::setParent or move the QWinHost into a different layout. +*/ +QWinHost::QWinHost(QWidget *parent, Qt::WindowFlags f) +: QWidget(parent, f), wndproc(0),own_hwnd(false), hwnd(0) +{ + setAttribute(Qt::WA_NoBackground); + setAttribute(Qt::WA_NoSystemBackground); +} + +/*! + Destroys the QWinHost object. If the hosted Win32 window has not + been set explicitly using setWindow() the window will be + destroyed. +*/ +QWinHost::~QWinHost() +{ + if (wndproc) { +#if defined(GWLP_WNDPROC) + QT_WA({ + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc); + },{ + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc); + }) +#else + QT_WA({ + SetWindowLong(hwnd, GWL_WNDPROC, (LONG)wndproc); + },{ + SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)wndproc); + }) +#endif + } + + if (hwnd && own_hwnd) + DestroyWindow(hwnd); +} + +/*! + Reimplement this virtual function to create and return the native + Win32 window. \a parent is the handle to this widget, and \a + instance is the handle to the application instance. The returned HWND + must be a child of the \a parent HWND. + + The default implementation returns null. The window returned by a + reimplementation of this function is owned by this QWinHost + instance and will be destroyed in the destructor. + + This function is called by the implementation of polish() if no + window has been set explicitly using setWindow(). Call polish() to + force this function to be called. + + \sa setWindow() +*/ +HWND QWinHost::createWindow(HWND parent, HINSTANCE instance) +{ + Q_UNUSED(parent); + Q_UNUSED(instance); + return 0; +} + +/*! + Ensures that the window provided a child of this widget, unless + it is a WS_OVERLAPPED window. +*/ +void QWinHost::fixParent() +{ + if (!hwnd) + return; + if (!::IsWindow(hwnd)) { + hwnd = 0; + return; + } + if (::GetParent(hwnd) == (HWND)winId()) + return; + long style = GetWindowLong(hwnd, GWL_STYLE); + if (style & WS_OVERLAPPED) + return; + ::SetParent(hwnd, (HWND)winId()); +} + +/*! + Sets the native Win32 window to \a window. If \a window is not a child + window of this widget, then it is reparented to become one. If \a window + is not a child window (i.e. WS_OVERLAPPED is set), then this function does nothing. + + The lifetime of the window handle will be managed by Windows, QWinHost does not + call DestroyWindow. To verify that the handle is destroyed when expected, handle + WM_DESTROY in the window procedure. + + \sa window(), createWindow() +*/ +void QWinHost::setWindow(HWND window) +{ + if (hwnd && own_hwnd) + DestroyWindow(hwnd); + + hwnd = window; + fixParent(); + + own_hwnd = false; +} + +/*! + Returns the handle to the native Win32 window, or null if no + window has been set or created yet. + + \sa setWindow(), createWindow() +*/ +HWND QWinHost::window() const +{ + return hwnd; +} + +void *getWindowProc(QWinHost *host) +{ + return host ? host->wndproc : 0; +} + +LRESULT CALLBACK WinHostProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + QWinHost *widget = qobject_cast(QWidget::find((WId)::GetParent(hwnd))); + WNDPROC oldproc = (WNDPROC)getWindowProc(widget); + if (widget) { + switch(msg) { + case WM_LBUTTONDOWN: + if (::GetFocus() != hwnd && (widget->focusPolicy() & Qt::ClickFocus)) { + widget->setFocus(Qt::MouseFocusReason); + } + break; + + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + QT_WA({ + SendMessage((HWND)widget->winId(), msg, wParam, lParam); + }, { + SendMessageA((HWND)widget->winId(), msg, wParam, lParam); + }) + break; + + case WM_KEYDOWN: + if (wParam == VK_TAB) { + QT_WA({ + SendMessage((HWND)widget->winId(), msg, wParam, lParam); + }, { + SendMessageA((HWND)widget->winId(), msg, wParam, lParam); + }) + } + break; + + default: + break; + } + } + + QT_WA({ + if (oldproc) + return CallWindowProc(oldproc, hwnd, msg, wParam, lParam); + return DefWindowProc(hwnd,msg,wParam,lParam); + }, { + if (oldproc) + return CallWindowProcA(oldproc, hwnd, msg, wParam, lParam); + return DefWindowProcA(hwnd,msg,wParam,lParam); + }) +} + +/*! + \reimp +*/ +bool QWinHost::event(QEvent *e) +{ + switch(e->type()) { + case QEvent::Polish: + if (!hwnd) { + hwnd = createWindow(HWND(winId()), GetModuleHandle(0)); + fixParent(); + own_hwnd = hwnd != 0; + } + if (hwnd && !wndproc && GetParent(hwnd) == (HWND)winId()) { +#if defined(GWLP_WNDPROC) + QT_WA({ + wndproc = (void*)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WinHostProc); + }, { + wndproc = (void*)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)WinHostProc); + }) +#else + QT_WA({ + wndproc = (void*)GetWindowLong(hwnd, GWL_WNDPROC); + SetWindowLong(hwnd, GWL_WNDPROC, (LONG)WinHostProc); + }, { + wndproc = (void*)GetWindowLongA(hwnd, GWL_WNDPROC); + SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)WinHostProc); + }) +#endif + + LONG style; + QT_WA({ + style = GetWindowLong(hwnd, GWL_STYLE); + }, { + style = GetWindowLongA(hwnd, GWL_STYLE); + }) + if (style & WS_TABSTOP) + setFocusPolicy(Qt::FocusPolicy(focusPolicy() | Qt::StrongFocus)); + } + break; + case QEvent::WindowBlocked: + if (hwnd) + EnableWindow(hwnd, false); + break; + case QEvent::WindowUnblocked: + if (hwnd) + EnableWindow(hwnd, true); + break; + } + return QWidget::event(e); +} + +/*! + \reimp +*/ +void QWinHost::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + + if (hwnd) + SetWindowPos(hwnd, HWND_TOP, 0, 0, width(), height(), SWP_SHOWWINDOW); +} + +/*! + \reimp +*/ +void QWinHost::focusInEvent(QFocusEvent *e) +{ + QWidget::focusInEvent(e); + + if (hwnd) + ::SetFocus(hwnd); +} + +/*! + \reimp +*/ +void QWinHost::resizeEvent(QResizeEvent *e) +{ + QWidget::resizeEvent(e); + + if (hwnd) + SetWindowPos(hwnd, HWND_TOP, 0, 0, width(), height(), 0); +} + +/*! + \reimp +*/ +#if QT_VERSION >= 0x050000 +bool QWinHost::nativeEvent(const QByteArray &eventType, void *message, long *result) +#else +bool QWinHost::winEvent(MSG *msg, long *result) +#endif +{ +#if QT_VERSION >= 0x050000 + MSG *msg = (MSG *)message; +#endif + switch (msg->message) + { + case WM_SETFOCUS: + if (hwnd) { + ::SetFocus(hwnd); + return true; + } + default: + break; + } +#if QT_VERSION >= 0x050000 + return QWidget::nativeEvent(eventType, message, result); +#else + return QWidget::winEvent(msg, result); +#endif +} diff --git a/modules/twainui/qwinhost.hpp b/modules/twainui/qwinhost.hpp new file mode 100644 index 00000000..7e4e1de6 --- /dev/null +++ b/modules/twainui/qwinhost.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + + +// Declaration of the QWinHost classes + +#ifndef QWINHOST_H +#define QWINHOST_H + +#include + +class QWinHost : public QWidget +{ + Q_OBJECT +public: + QWinHost(QWidget *parent = 0, Qt::WindowFlags f = 0); + ~QWinHost(); + + void setWindow(HWND); + HWND window() const; + +protected: + virtual HWND createWindow(HWND parent, HINSTANCE instance); + + bool event(QEvent *e); + void showEvent(QShowEvent *); + void focusInEvent(QFocusEvent*); + void resizeEvent(QResizeEvent*); + +#if QT_VERSION >= 0x050000 + bool nativeEvent(const QByteArray &eventType, void *message, long *result); +#else + bool winEvent(MSG *msg, long *result); +#endif + +private: + void fixParent(); + friend void* getWindowProc(QWinHost*); + + void *wndproc; + bool own_hwnd; + HWND hwnd; +}; + +#endif // QWINHOST_H diff --git a/modules/twainui/qwinwidget.cpp b/modules/twainui/qwinwidget.cpp new file mode 100644 index 00000000..2c0334e1 --- /dev/null +++ b/modules/twainui/qwinwidget.cpp @@ -0,0 +1,359 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +// Implementation of the QWinWidget classes + +#ifdef QT3_SUPPORT +#undef QT3_SUPPORT +#endif + +#ifdef UNICODE +#undef UNICODE +#endif + +#include "qmfcapp.hpp" + +#ifdef QTWINMIGRATE_WITHMFC +#include +#endif + +#include + +#include "qwinwidget.hpp" + +#include + +#if QT_VERSION >= 0x050000 +#include +#include +#define QT_WA(unicode, ansi) unicode +#endif + +/*! + \class QWinWidget qwinwidget.h + \brief The QWinWidget class is a Qt widget that can be child of a + native Win32 widget. + + The QWinWidget class is the bridge between an existing application + user interface developed using native Win32 APIs or toolkits like + MFC, and Qt based GUI elements. + + Using QWinWidget as the parent of QDialogs will ensure that + modality, placement and stacking works properly throughout the + entire application. If the child widget is a top level window that + uses the \c WDestructiveClose flag, QWinWidget will destroy itself + when the child window closes down. + + Applications moving to Qt can use QWinWidget to add new + functionality, and gradually replace the existing interface. +*/ + +/*! + Creates an instance of QWinWidget. \a hParentWnd is the handle to + the native Win32 parent. If a \a parent is provided the object is + owned by that QObject. \a f is passed on to the QWidget constructor. +*/ +QWinWidget::QWinWidget(HWND hParentWnd, QObject *parent, Qt::WindowFlags f) +: QWidget(0, f), hParent(hParentWnd), prevFocus(0), reenable_parent(false) +{ + if (parent) + QObject::setParent(parent); + + init(); +} + +#ifdef QTWINMIGRATE_WITHMFC +/*! + \overload + + Creates an instance of QWinWidget. \a parentWnd is a pointer to an + MFC window object. If a \a parent is provided the object is owned + by that QObject. \a f is passed on to the QWidget constructor. +*/ +QWinWidget::QWinWidget(CWnd *parentWnd, QObject *parent, Qt::WindowFlags f) +: QWidget(0, f), hParent(parentWnd ? parentWnd->m_hWnd : 0), prevFocus(0), reenable_parent(false) +{ + if (parent) + QObject::setParent(parent); + + init(); +} +#endif + + +void QWinWidget::init() +{ + //Q_ASSERT(hParent); + + if (hParent) { +#if QT_VERSION >= 0x050000 + setProperty("_q_embedded_native_parent_handle", WId(hParent)); +#endif + // make the widget window style be WS_CHILD so SetParent will work + QT_WA({ + SetWindowLong((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + }, { + SetWindowLongA((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + }) +#if QT_VERSION >= 0x050000 + QWindow *window = windowHandle(); + HWND h = static_cast(QGuiApplication::platformNativeInterface()-> + nativeResourceForWindow("handle", window)); + SetParent(h, hParent); + window->setFlags(Qt::FramelessWindowHint); +#else + SetParent(winId(), hParent); +#endif + QEvent e(QEvent::EmbeddingControl); + QApplication::sendEvent(this, &e); + } +} + +/*! + Destroys this object, freeing all allocated resources. +*/ +QWinWidget::~QWinWidget() +{ +} + +/*! + Returns the handle of the native Win32 parent window. +*/ +HWND QWinWidget::parentWindow() const +{ + return hParent; +} + +/*! + \reimp +*/ +void QWinWidget::childEvent(QChildEvent *e) +{ + QObject *obj = e->child(); + if (obj->isWidgetType()) { + if (e->added()) { + if (obj->isWidgetType()) { + obj->installEventFilter(this); + } + } else if (e->removed() && reenable_parent) { + reenable_parent = false; + EnableWindow(hParent, true); + obj->removeEventFilter(this); + } + } + QWidget::childEvent(e); +} + +/*! \internal */ +void QWinWidget::saveFocus() +{ + if (!prevFocus) + prevFocus = ::GetFocus(); + if (!prevFocus) + prevFocus = parentWindow(); +} + +/*! + Shows this widget. Overrides QWidget::show(). + + \sa showCentered() +*/ +void QWinWidget::show() +{ + saveFocus(); + QWidget::show(); +} + +/*! + Centers this widget over the native parent window. Use this + function to have Qt toplevel windows (i.e. dialogs) positioned + correctly over their native parent windows. + + \code + QWinWidget qwin(hParent); + qwin.center(); + + QMessageBox::information(&qwin, "Caption", "Information Text"); + \endcode + + This will center the message box over the client area of hParent. +*/ +void QWinWidget::center() +{ + const QWidget *child = findChild(); + if (child && !child->isWindow()) { + qWarning("QWinWidget::center: Call this function only for QWinWidgets with toplevel children"); + } + RECT r; + GetWindowRect(hParent, &r); + setGeometry((r.right-r.left)/2+r.left, (r.bottom-r.top)/2+r.top,0,0); +} + +/*! + \obsolete + + Call center() instead. +*/ +void QWinWidget::showCentered() +{ + center(); + show(); +} + +/*! + Sets the focus to the window that had the focus before this widget + was shown, or if there was no previous window, sets the focus to + the parent window. +*/ +void QWinWidget::resetFocus() +{ + if (prevFocus) + ::SetFocus(prevFocus); + else + ::SetFocus(parentWindow()); +} + +/*! \reimp +*/ +#if QT_VERSION >= 0x050000 +bool QWinWidget::nativeEvent(const QByteArray &, void *message, long *) +#else +bool QWinWidget::winEvent(MSG *msg, long *) +#endif +{ +#if QT_VERSION >= 0x050000 + MSG *msg = (MSG *)message; +#endif + if (msg->message == WM_SETFOCUS) { + Qt::FocusReason reason; + if (::GetKeyState(VK_LBUTTON) < 0 || ::GetKeyState(VK_RBUTTON) < 0) + reason = Qt::MouseFocusReason; + else if (::GetKeyState(VK_SHIFT) < 0) + reason = Qt::BacktabFocusReason; + else + reason = Qt::TabFocusReason; + QFocusEvent e(QEvent::FocusIn, reason); + QApplication::sendEvent(this, &e); + } + + return false; +} + +/*! + \reimp +*/ +bool QWinWidget::eventFilter(QObject *o, QEvent *e) +{ + QWidget *w = (QWidget*)o; + + switch (e->type()) { + case QEvent::WindowDeactivate: + if (w->isModal() && w->isHidden()) + BringWindowToTop(hParent); + break; + + case QEvent::Hide: + if (reenable_parent) { + EnableWindow(hParent, true); + reenable_parent = false; + } + resetFocus(); + if (w->testAttribute(Qt::WA_DeleteOnClose) && w->isWindow()) + deleteLater(); + break; + + case QEvent::Show: + if (w->isWindow()) { + saveFocus(); + hide(); + if (w->isModal() && !reenable_parent) { + EnableWindow(hParent, false); + reenable_parent = true; + } + } + break; + + case QEvent::Close: + ::SetActiveWindow(hParent); + if (w->testAttribute(Qt::WA_DeleteOnClose)) + deleteLater(); + break; + + default: + break; + } + + return QWidget::eventFilter(o, e); +} + +/*! \reimp +*/ +void QWinWidget::focusInEvent(QFocusEvent *e) +{ + QWidget *candidate = this; + + switch (e->reason()) { + case Qt::TabFocusReason: + case Qt::BacktabFocusReason: + while (!(candidate->focusPolicy() & Qt::TabFocus)) { + candidate = candidate->nextInFocusChain(); + if (candidate == this) { + candidate = 0; + break; + } + } + if (candidate) { + candidate->setFocus(e->reason()); + if (e->reason() == Qt::BacktabFocusReason || e->reason() == Qt::TabFocusReason) { + candidate->setAttribute(Qt::WA_KeyboardFocusChange); + candidate->window()->setAttribute(Qt::WA_KeyboardFocusChange); + } + if (e->reason() == Qt::BacktabFocusReason) + QWidget::focusNextPrevChild(false); + } + break; + default: + break; + } +} + +/*! \reimp +*/ +bool QWinWidget::focusNextPrevChild(bool next) +{ + QWidget *curFocus = focusWidget(); + if (!next) { + if (!curFocus->isWindow()) { + QWidget *nextFocus = curFocus->nextInFocusChain(); + QWidget *prevFocus = 0; + QWidget *topLevel = 0; + while (nextFocus != curFocus) { + if (nextFocus->focusPolicy() & Qt::TabFocus) { + prevFocus = nextFocus; + topLevel = 0; + } else if (nextFocus->isWindow()) { + topLevel = nextFocus; + } + nextFocus = nextFocus->nextInFocusChain(); + } + + if (!topLevel) { + return QWidget::focusNextPrevChild(false); + } + } + } else { + QWidget *nextFocus = curFocus; + while (1) { + nextFocus = nextFocus->nextInFocusChain(); + if (nextFocus->isWindow()) + break; + if (nextFocus->focusPolicy() & Qt::TabFocus) { + return QWidget::focusNextPrevChild(true); + } + } + } + + ::SetFocus(hParent); + + return true; +} diff --git a/modules/twainui/qwinwidget.hpp b/modules/twainui/qwinwidget.hpp new file mode 100644 index 00000000..ed47d1f8 --- /dev/null +++ b/modules/twainui/qwinwidget.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + + +// Declaration of the QWinWidget classes + +#ifndef QWINWIDGET_H +#define QWINWIDGET_H + +#include +#include "qmfcapp.hpp" + +class CWnd; + +class QWinWidget : public QWidget +{ + Q_OBJECT +public: + QWinWidget( HWND hParentWnd, QObject *parent = 0, Qt::WindowFlags f = 0 ); +#ifdef QTWINMIGRATE_WITHMFC + QWinWidget( CWnd *parnetWnd, QObject *parent = 0, Qt::WindowFlags f = 0 ); +#endif + ~QWinWidget(); + + void show(); + void center(); + void showCentered(); + + HWND parentWindow() const; + +protected: + void childEvent( QChildEvent *e ); + bool eventFilter( QObject *o, QEvent *e ); + + bool focusNextPrevChild(bool next); + void focusInEvent(QFocusEvent *e); +#if QT_VERSION >= 0x050000 + bool nativeEvent(const QByteArray &eventType, void *message, long *result); +#else + bool winEvent(MSG *msg, long *result); +#endif + +private: + void init(); + + void saveFocus(); + void resetFocus(); + + HWND hParent; + HWND prevFocus; + bool reenable_parent; +}; + +#endif // QWINWIDGET_H diff --git a/modules/twainui/setpicclrtool.cpp b/modules/twainui/setpicclrtool.cpp new file mode 100644 index 00000000..78597d89 --- /dev/null +++ b/modules/twainui/setpicclrtool.cpp @@ -0,0 +1,315 @@ +#include "setpicclrtool.h" +#include "ui_setpicclrtool.h" +#include "widget.h" +#include +#include + +setPicClrTool::setPicClrTool(QWidget *parent) : + QDialog(parent), + ui(new Ui::setPicClrTool) +{ + ui->setupUi(this); + setMouseTracking(true); + ui->inputEdt->setEnabled(false); + ui->outputEdt->setEnabled(false); + ui->inputEdt->setValidator(new QIntValidator(0, 255, this)); + ui->outputEdt->setValidator(new QIntValidator(0, 255, this)); + ui->widget->setFocus(Qt::MouseFocusReason); + connect(ui->widget,SIGNAL(mouseCoordSig(QPoint)),this,SLOT(mouseCoordSlot(QPoint))); + connect(ui->widget,SIGNAL(dragPointChecked(bool)),this,SLOT(lineEditEnable(bool))); + connect(ui->widget,SIGNAL(lineChangeSig()),this,SLOT(lineChangeSlot())); +} + +setPicClrTool::~setPicClrTool() +{ + delete ui; +} + +void setPicClrTool::getGrayTable(uchar *table, size_t length) +{ + QVector gray = getGrayALLPoint(); + for (size_t i = 0; i < length; i++) + table[i] = static_cast(gray[static_cast(i)]); +} + +void setPicClrTool::getRGBTable(uchar *table, size_t length) +{ + if (length != 768) + throw "length is not 768."; + + QVector rgb = getRgbALLPoint(); + QVector red = getRedALLPoint(); + QVector green = getGreenALLPoint(); + QVector blue = getBlueALLPoint(); + + + for (size_t i = 0; i < 256; i++) + { + //if (i == 255) + // int a = 0; + //table member order is B\G\R + table[i * 3 + 0] = static_cast(blue[rgb[static_cast(i)]]); + table[i * 3 + 1] = static_cast(green[rgb[static_cast(i)]]); + table[i * 3 + 2] = static_cast(red[rgb[static_cast(i)]]); + } +} + +//void setPicClrTool::setGrayTable(const uchar *table, size_t length) +//{ +// QVector gray; +// for (size_t i = 0; i < length; i++) +// gray[static_cast(i)] = int(table[i]); +// //ui->widget->setGrayALLPoint(gray); +//} + +//void setPicClrTool::setRGBTable(const uchar *table, size_t length) +//{ +// QVector rgb; +// QVector red; +// QVector green; +// QVector blue; +// for(int i = 0; i < 256; i++){ +// rgb.append(i); +// } +// for (size_t i = 0; i < length; i++){ +// red.append(int(table[i * 3 + 0])); +// green.append(int(table[i * 3 + 1])); +// blue.append(int(table[i * 3 + 2])); +// } + +//} + +void setPicClrTool::setColorMode(int colorMode) +{ + QVariant v(6); + if(colorMode == 0) + { + ui->colorSetCmb->setItemData(1,v,Qt::UserRole - 1); + } + else + { + ui->comboBox->setItemData(2,v,Qt::UserRole - 1); + ui->colorSetCmb->setItemData(0,v,Qt::UserRole - 1); + ui->colorSetCmb->setItemData(2,v,Qt::UserRole - 1); + ui->colorSetCmb->setItemData(3,v,Qt::UserRole - 1); + ui->colorSetCmb->setItemData(4,v,Qt::UserRole - 1); + ui->colorSetCmb->setCurrentIndex(1); + } +} + +QVector > setPicClrTool::getRGBKeyTable() +{ + QVector> plv; + plv.append(getRgbKeyPoint()); + plv.append(getRedKeyPoint()); + plv.append(getGreenKeyPoint()); + plv.append(getBlueKeyPoint()); + return plv; +} + +void setPicClrTool::setRGBKeyTable(QVector > &plv) +{ + setRgbKeyPoint(plv[0]); + setRedKeyPoint(plv[1]); + setGreenKeyPoint(plv[2]); + setBlueKeyPoint(plv[3]); +} + +QList setPicClrTool::getGrayKeyTable() +{ + return getGrayKeyPoint(); +} + +void setPicClrTool::setGrayKeyTable(QList &plv) +{ + setGrayKeyPoint(plv); +} + +QVector setPicClrTool::getRgbALLPoint() +{ + return ui->widget->getRgbALLPoint(); +} + +QList setPicClrTool::getRgbKeyPoint() const +{ + qDebug() << "setRgb" << ui->widget->getRgbKeyPoint(); + return ui->widget->getRgbKeyPoint(); +} + +void setPicClrTool::setRgbKeyPoint(const QList &pVec) +{ + qDebug() << "setRgb" << pVec; + ui->widget->setRgbKeyPoint(pVec); +} + +QList setPicClrTool::getRedKeyPoint() const +{ + return ui->widget->getRedKeyPoint(); +} + +void setPicClrTool::setRedKeyPoint(const QList &pVec) +{ + ui->widget->setRedKeyPoint(pVec); +} + +QList setPicClrTool::getBlueKeyPoint() const +{ + return ui->widget->getBlueKeyPoint(); +} + +void setPicClrTool::setBlueKeyPoint(const QList &pVec) +{ + ui->widget->setBlueKeyPoint(pVec); +} + +QList setPicClrTool::getGreenKeyPoint() const +{ + return ui->widget->getGreenKeyPoint(); +} + +void setPicClrTool::setGreenKeyPoint(const QList &pVec) +{ + ui->widget->setGreenKeyPoint(pVec); +} + +QList setPicClrTool::getGrayKeyPoint() const +{ + return ui->widget->getGrayKeyPoint(); +} + +void setPicClrTool::setGrayKeyPoint(const QList &pVec) +{ + ui->widget->setGrayKeyPoint(pVec); +} + +QVector setPicClrTool::getRedALLPoint() +{ + return ui->widget->getRedALLPoint(); +} + +QVector setPicClrTool::getBlueALLPoint() +{ + return ui->widget->getBlueALLPoint(); +} + +QVector setPicClrTool::getGreenALLPoint() +{ + return ui->widget->getGreenALLPoint(); +} + +QVector setPicClrTool::getGrayALLPoint() +{ + return ui->widget->getGrayALLPoint(); +} + +void setPicClrTool::mouseCoordSlot(QPoint pos) +{ + ui->inputEdt->setText(QString::number(pos.x())); + ui->outputEdt->setText(QString::number(pos.y())); +} + +void setPicClrTool::lineEditEnable(bool a) +{ + ui->inputEdt->setEnabled(a); + ui->outputEdt->setEnabled(a); +} + +void setPicClrTool::lineChangeSlot() +{ + ui->comboBox->setCurrentIndex(0); +} + +void setPicClrTool::on_colorSetCmb_currentIndexChanged(int index) +{ + (void)index; + /* switch(index){ + case RED: + ui->widget->updateCurLinePnt(RED); + break; + case GREEN: + ui->widget->updateCurLinePnt(GREEN); + break; + case BLUE: + ui->widget->updateCurLinePnt(BLUE); + break; + case RGB: + ui->widget->updateCurLinePnt(RGB); + break; + case GRAY: + ui->widget->updateCurLinePnt(GRAY); + break; + }*/ +} + +void setPicClrTool::on_comboBox_currentIndexChanged(int index) +{ + if(index == 0){ + ui->widget->initAllLstPnt(); + ui->widget->updateCurLinePnt(ui->colorSetCmb->currentIndex()); + return ; + } + ui->widget->initAllLstPnt(); + if(index == 1){ + rgbLine.clear(); + rgbLine.append(QPoint(0,255)); + rgbLine.append(QPoint(255,0)); + ui->widget->setLstPnt_RGB(rgbLine); + }else if(index == 2){ + redLine.clear(); + redLine.append(QPoint(33,255)); + redLine.append(QPoint(185,0)); + redLine.append(QPoint(119,127)); + greenLine.clear(); + greenLine.append(QPoint(28,255)); + greenLine.append(QPoint(132,0)); + greenLine.append(QPoint(77,127)); + blueLine.clear(); + blueLine.append(QPoint(25,255)); + blueLine.append(QPoint(108,0)); + blueLine.append(QPoint(60,127)); + ui->widget->setLstPnt_RED(redLine); + ui->widget->setLstPnt_GREEN(greenLine); + ui->widget->setLstPnt_BLUE(blueLine); + }else if(index == 4){ + rgbLine.clear(); + rgbLine.append(QPoint(0,0)); + rgbLine.append(QPoint(255,255)); + rgbLine.append(QPoint(103,125)); + ui->widget->setLstPnt_RGB(rgbLine); + }else if(index == 3){ + rgbLine.clear(); + rgbLine.append(QPoint(0,0)); + rgbLine.append(QPoint(255,255)); + rgbLine.append(QPoint(130,101)); + ui->widget->setLstPnt_RGB(rgbLine); + } + ui->widget->updateCurLinePnt(ui->colorSetCmb->currentIndex()); +} + +void setPicClrTool::on_inputEdt_textChanged(const QString &arg1) +{ + ui->widget->setXCoorVal(arg1.toInt()); +} + +void setPicClrTool::on_outputEdt_textChanged(const QString &arg1) +{ + ui->widget->setYCoorVal(arg1.toInt()); +} + +void setPicClrTool::on_pushButton_clicked() +{ + ui->widget->initSelectColLine(ui->colorSetCmb->currentIndex()); +} + +void setPicClrTool::on_buttonBox_accepted() +{ + //close(); + accept(); +} + +void setPicClrTool::on_buttonBox_rejected() +{ + ui->widget->initAllLstPnt(); + //close(); + reject(); +} diff --git a/modules/twainui/setpicclrtool.h b/modules/twainui/setpicclrtool.h new file mode 100644 index 00000000..59c4c25b --- /dev/null +++ b/modules/twainui/setpicclrtool.h @@ -0,0 +1,82 @@ +#ifndef SETPICCLRTOOL_H +#define SETPICCLRTOOL_H + +//#include "colorlinesetdef.h" +#include + +namespace Ui { +class setPicClrTool; +} + +class setPicClrTool : public QDialog +{ + Q_OBJECT + +public: + explicit setPicClrTool(QWidget *parent = nullptr); + ~setPicClrTool(); + + void getGrayTable(uchar* table, size_t length = 256); + + void getRGBTable(uchar* table, size_t length = 768); + +// void setGrayTable(const uchar* table, size_t length = 256); + +// void setRGBTable(const uchar* table, size_t length = 768); + + void setColorMode(int colorMode); + + QVector> getRGBKeyTable(); + void setRGBKeyTable(QVector>& plv); + QList getGrayKeyTable(); + void setGrayKeyTable(QList &plv); + + +private: + QVector getRgbALLPoint(); + QVector getRedALLPoint(); + QVector getBlueALLPoint(); + QVector getGreenALLPoint(); + QVector getGrayALLPoint(); + + QList getRgbKeyPoint()const; + void setRgbKeyPoint(const QList& pVec); + QList getRedKeyPoint()const; + void setRedKeyPoint(const QList& pVec); + QList getBlueKeyPoint()const; + void setBlueKeyPoint(const QList& pVec); + QList getGreenKeyPoint()const; + void setGreenKeyPoint(const QList& pVec); + QList getGrayKeyPoint()const; + void setGrayKeyPoint(const QList& pVec); + +private slots: + void mouseCoordSlot(QPoint);//set QLineEdit value by QPoint setting + void lineEditEnable(bool);//set 2 LineEdit enable status + void lineChangeSlot(); + + void on_colorSetCmb_currentIndexChanged(int index); + + void on_comboBox_currentIndexChanged(int index); + + void on_inputEdt_textChanged(const QString &arg1); + + void on_outputEdt_textChanged(const QString &arg1); + + void on_pushButton_clicked(); + + void on_buttonBox_accepted(); + + void on_buttonBox_rejected(); + +private: + Ui::setPicClrTool *ui; + QList linePoint; + QList greenLine; + QList redLine; + QList blueLine; + QList rgbLine; + QList grayLine; +}; + +#endif // SETPICCLRTOOL_H diff --git a/modules/twainui/setpicclrtool.ui b/modules/twainui/setpicclrtool.ui new file mode 100644 index 00000000..5ba412a6 --- /dev/null +++ b/modules/twainui/setpicclrtool.ui @@ -0,0 +1,167 @@ + + + setPicClrTool + + + + 0 + 0 + 259 + 341 + + + + 自定义色调曲线 + + + + + + + + + 自定义 + + + + + 负片(RGB) + + + + + 彩色负片(RGB) + + + + + 较暗(RGB) + + + + + 较亮(RGB) + + + + + + + + + + + + false + + + + RGB + + + + + + + + + + + + + + + + + + + + 绿 + + + + + + + + 初始化 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + true + + + Qt::StrongFocus + + + + + + + + + 输入: + + + + + + + true + + + + + + + 输出: + + + + + + + true + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + Widget + QWidget +
widget.h
+ 1 +
+
+ + +
diff --git a/modules/twainui/twainui.cpp b/modules/twainui/twainui.cpp new file mode 100644 index 00000000..71957e9b --- /dev/null +++ b/modules/twainui/twainui.cpp @@ -0,0 +1,99 @@ +#include "twainui.h" +#include "dialog_device_select.h" +#include "dialog_progress_ui.h" +#include "hg_settingdialog.h" + +#ifdef HG_CMP_MSC +#include "qwinwidget.hpp" +extern HINSTANCE g_hInst; +extern bool g_ownApplication; +#endif + +int choose_scanner(const std::vector &devs) +{ + Dialog_device_select dlg(devs); + if (dlg.exec()) + { + return dlg.getDevId(); + } + else + { + return -1; + } +} + +char *apply_current_config(const char *dev_name, SANE_Handle device, LPSANEAPI api) +{ + return NULL; +} + +void twain_ui_free(void *buf) +{ + if (buf != nullptr) + { + delete buf; + buf = nullptr; + } +} + +int show_setting_ui(SANE_Handle device, HWND parent, LPSANEAPI api, bool with_scan) +{ + if (nullptr == api || nullptr == device) + return -1; + + QWidget *qParent = nullptr; +#ifdef HG_CMP_MSC + if (!g_ownApplication) + g_ownApplication = QMfcApp::pluginInstance(g_hInst); + QWinWidget win(parent); + if (nullptr != parent) + { + win.showCentered(); + qParent = &win; + } +#else + qParent = parent; +#endif + + QTranslator translator; + int cp = lang_get_cur_code_page(); + if (20127 == cp) + translator.load(":translation/TwainUI_zh_EN.qm"); + else + translator.load(":translation/TwainUI_zh_CN.qm"); + QCoreApplication::installTranslator(&translator); + + hg_settingdialog dlg(device, api, with_scan, qParent); + dlg.exec(); + QCoreApplication::removeTranslator(&translator); + + int ret = dlg.getCloseButtonCliked(); + if (ret == dlg.closeButtonScan) + return UI_RESULT_START_SCAN; + else if (ret == dlg.closeButtonCancel) + return UI_RESULT_CLOSE_CANCEL; + else + return UI_RESULT_CLOSE_NORMAL; +} + +int show_progress_ui(HWND parent, std::function callback, std::function *notify) +{ + QWidget *qParent = nullptr; +#ifdef HG_CMP_MSC + if (!g_ownApplication) + g_ownApplication = QMfcApp::pluginInstance(g_hInst); + QWinWidget win(parent); + if (nullptr != parent) + { + win.showCentered(); + qParent = &win; + } +#else + qParent = parent; +#endif + + Dialog_progress_ui dlg(callback, notify, qParent); + dlg.show(); + + return 0; +} diff --git a/modules/twainui/twainui.h b/modules/twainui/twainui.h new file mode 100644 index 00000000..18e443b6 --- /dev/null +++ b/modules/twainui/twainui.h @@ -0,0 +1,78 @@ +#pragma once + + +#include +#include +#include +#include "sane/sane_ex.h" + +#include + +typedef struct _dev_que +{ + int id; // ID,用户选中后返回该值 + std::string name; // 设备名称 + std::string sn; // 设备序列号 +}DEVQUE; + +// 功能: 选择多个同型设备中的一个,模态 +// +// 参数: devs - 设备队列列表 +// +// 返回: 用户选择的设备所对应的,DEVQUE::id;或者-1代表用户放弃选择设备 +int choose_scanner(const std::vector& devs); // blocked. return selected DEVQUE::id or -1 if user cancelled + + +// 功能: 应用当前设备对应的用户配置,同步 +// +// 参数: dev_name - 设备名称 +// +// device - 设备打开的句柄 +// +// api - sane_xxx API函数指针 +// +// 返回: 当前设备配置方案的名称。返回指针通过调用函数twain_ui_free来释放 +char* apply_current_config(const char* dev_name, SANE_Handle device, LPSANEAPI api); + +// 功能: 释放由界面模块返回的动态分配的内存,同步 +// +// 参数: buf - 内存地址 +// +// 返回: 无 +void twain_ui_free(void* buf); + +enum ui_result +{ + UI_RESULT_FAILED = -1, // 一般用于界面初始化失败 + UI_RESULT_OK, // 界面正常显示 + UI_RESULT_CLOSE_NORMAL, // 界面正常关闭 + UI_RESULT_CLOSE_CANCEL, // 用户取消操作,如取消扫描…… + UI_RESULT_START_SCAN, // 用户点击了开始扫描 +}; +// 功能: 释放由界面模块返回的动态分配的内存,模态 +// +// 参数: device - 当前打开的设备句柄 +// +// parent - 父窗口句柄 +// +// api - sane_xxx API函数指针 +// +// with_scan - 是否显示“扫描”按钮 +// +// 返回: ui_result 类型, UI_RESULT_CLOSE_NORMAL or UI_RESULT_START_SCAN +int show_setting_ui(SANE_Handle device, HWND parent, LPSANEAPI api, bool with_scan/*是否显示“扫描”按钮*/); + +// 功能: 显示扫描进度界面,非模态 +// +// 参数: parent - 父窗口句柄 +// +// callback - 用户界面操作事件回调(主要为取消扫描事件) +// +// notify - ui接收进度通知函数,外部通过该返回的函数来通知当前扫描进度或事件 +// notify events: SANE_EVENT_WORKING - void*: unused, be NULL, flag - unused, be 0 +// SANE_EVENT_SCAN_FINISHED - void*: (utf8*)message, flag - error code (0 is success) +// SANE_EVENT_USB_DATA_RECEIVED- void* unused, be NULL, flag - unused, be 0 +// SANE_EVENT_IMAGE_OK - void* unused, be NULL, flag - unused, be 0 +// +// 返回: ui_result 类型, UI_RESULT_FAILED or UI_RESULT_OK +int show_progress_ui(HWND parent, std::function callback, std::function* notify); diff --git a/modules/twainui/widget.cpp b/modules/twainui/widget.cpp new file mode 100644 index 00000000..71c943bf --- /dev/null +++ b/modules/twainui/widget.cpp @@ -0,0 +1,855 @@ +#include "widget.h" +#include "ui_widget.h" +#include "gaosixy.h" +#include +#include +#include +#include +using namespace std; + + +enum COLOR_TPYE +{ + RGB, + GRAY, + RED, + BLUE, + GREEN +}; + +Widget::Widget(QWidget *parent) : + QWidget(parent), + ui(new Ui::Widget) +{ + ui->setupUi(this); + setWindowTitle(tr("zuobiaozhou")); //设置标题栏标题 + //resize(300,300); //设置窗口初始大小 + //ui->table->setWindowFlags(Qt::WindowStaysOnTopHint); + initAllLstPnt(); + initInterface(); +} + +Widget::~Widget() +{ + delete ui; +} + +void Widget::setLstPnt_RGB(const QList &plst) +{ + rgbLine = QList(plst); +} + +QList Widget::getLstPnt_RGB() const +{ + return rgbLine; +} + +void Widget::setLstPnt_RED(const QList &plst) +{ + redLine = QList(plst); +} + +void Widget::setLstPnt_BLUE(const QList &plst) +{ + blueLine = QList(plst); +} + +QList Widget::getLstPnt_BLUE() const +{ + return blueLine; +} + +void Widget::setLstPnt_GREEN(const QList &plst) +{ + greenLine = QList(plst); +} + +QList Widget::getLstPnt_GREEN() const +{ + return greenLine; +} + +void Widget::setLstPnt_GRAY(const QList &plst) +{ + grayLine = QList(plst); +} + +QList Widget::getLstPnt_GRAY() const +{ + return grayLine; +} + +QVector Widget::getRgbALLPoint() +{ + return rgbALLPoint; +} + +QList Widget::getRgbKeyPoint() const +{ + return rgbLine; +} + +void Widget::setRgbKeyPoint(const QList &pLst) +{ + if(pLst.size() > 4) return; + rgbLine = QList(pLst); + pointLst.clear(); + pointLst = QList(rgbLine); + drawLineFromPoint(rgbLine, RGB); + update(); +} + +QVector Widget::getRedALLPoint() +{ + return redALLPoint; +} + +QList Widget::getRedKeyPoint() const +{ + return redLine; +} + +void Widget::setRedKeyPoint(const QList &pLst) +{ + if(pLst.size() > 4) return; + redLine = QList(pLst); + drawLineFromPoint(redLine, RED); + update(); +} + +QVector Widget::getBlueALLPoint() +{ + return blueALLPoint; +} + +QList Widget::getBlueKeyPoint() const +{ + return blueLine; +} + +void Widget::setBlueKeyPoint(const QList &pLst) +{ + if(pLst.size() > 4) return; + blueLine = QList(pLst); + drawLineFromPoint(blueLine, BLUE); + update(); +} + +QVector Widget::getGreenALLPoint() +{ + return greenALLPoint; +} + +QList Widget::getGreenKeyPoint() const +{ + return greenLine; +} + +void Widget::setGreenKeyPoint(const QList &pLst) +{ + if(pLst.size() > 4) return; + greenLine = QList(pLst); + drawLineFromPoint(greenLine, GREEN); + update(); +} + +QVector Widget::getGrayALLPoint() +{ + return grayALLPoint; +} + +QList Widget::getGrayKeyPoint() const +{ + return grayLine; +} + +void Widget::setGrayKeyPoint(const QList &pLst) +{ + if(pLst.size() > 4) return; + grayLine = QList(pLst); + pointLst.clear(); + pointLst = QList(grayLine); + drawLineFromPoint(grayLine, GRAY); + update(); +} + +void Widget::initAllLstPnt() +{ + pointLst.clear(); + pointLst.append(QPoint(0,0)); + pointLst.append(QPoint(255,255)); + redLine.clear(); + redLine.append(QPoint(0,0)); + redLine.append(QPoint(255,255)); + blueLine.clear(); + blueLine.append(QPoint(0,0)); + blueLine.append(QPoint(255,255)); + greenLine.clear(); + greenLine.append(QPoint(0,0)); + greenLine.append(QPoint(255,255)); + rgbLine.clear(); + rgbLine.append(QPoint(0,0)); + rgbLine.append(QPoint(255,255)); + grayLine.clear(); + grayLine.append(QPoint(0,0)); + grayLine.append(QPoint(255,255)); + drawLineFromPoint(redLine, RED); + drawLineFromPoint(rgbLine, RGB); + drawLineFromPoint(greenLine, GREEN); + drawLineFromPoint(blueLine, BLUE); + drawLineFromPoint(grayLine, GRAY); +} + +void Widget::initInterface() +{ + color = Qt::gray; + selectCol = RGB; + leftMouseMv = false; + newPoint = false; + clickLine = false; + dragPoint = -1; + setMouseTracking(true); + ui->widget_2->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:0, x2:1, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))}"); + ui->widget->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:1, x2:0, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))}"); +} + +void Widget::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing,true); //开启抗锯齿 + painter.translate(ui->widget->width(),ui->widget->height()); //坐标系统平移变换,把原点平移 + painter.scale(ui->table->width() / 258.0,ui->table->height() / 258.0); //坐标系统比例变换,使绘制的图形随窗口的放大而放大 + painter.scale(1,-1); + + drawCoordinate(painter); + drawBackColorBySlc(painter); + drawCoorScale(painter); + drawCurveByColor(painter); + drawAllPoint(painter); + + if(dragPoint < 0){ + setMouseTracking(true); + emit dragPointChecked(false); + } + painter.end(); +} + +void Widget::mousePressEvent(QMouseEvent *event) +{ + int x = (event->x() - ui->widget->width())*258/ui->table->width(); + int y = (height() - event->y()-ui->widget_2->height())*258/ui->table->height(); + //qDebug() << x << y; + if(event->button() == Qt::LeftButton){ + newPoint = false; + dragPoint = -1; + clickLine = false; + for(int i = 0; i < linePoint.size();i++){ + int px = linePoint.at(i).x(); + int py = linePoint.at(i).y(); + if(qAbs(x-px) <= 6 && qAbs(y-py) <= 6) + { + newPoint = true; + for(int j = 0; j < pointLst.size(); j++){ + int lx = pointLst.at(j).x(); + int ly = pointLst.at(j).y(); + if(qAbs(x-lx) <= 6 && qAbs(y-ly) <= 6){ + dragPoint = j; + clickLine = true; + leftMouseMv = true; + newPoint = false; + emit dragPointChecked(true); + setMouseTracking(false); + update(); + break; + } + } + if(newPoint && pointLst.size() < 4 && x > pointLst.at(0).x() && x < pointLst.at(1).x()){ + pointLst.append(QPoint(x,y)); + dragPoint = pointLst.size()-1; + leftMouseMv = true; + clickLine = true; + emit dragPointChecked(true); + setMouseTracking(false); + update(); + } + } + } + } + else if(event->button() == Qt::RightButton){ + for(int j = 0; j < pointLst.size(); j++){ + int lx = pointLst.at(j).x(); + int ly = pointLst.at(j).y(); + if(qAbs(x-lx) <= 7 && qAbs(y-ly) <= 5){ + if(j > 1) + pointLst.removeAt(j); + if(j == dragPoint){ + dragPoint = -1; + emit dragPointChecked(false); + }else if(j > dragPoint){ + dragPoint = dragPoint; + }else { + dragPoint = dragPoint-1; + } + update(); + break; + } + } + } + if(!clickLine){ + dragPoint = -1; + emit dragPointChecked(false); + setMouseTracking(true); + update(); + } + emit mouseCoordSig(QPoint(x,y)); +} + +void Widget::mouseMoveEvent(QMouseEvent *event) +{ + int x = (event->x() - ui->widget->width())*258/ui->table->width(); + int y = (height() - event->y()-ui->widget_2->height())*258/ui->table->height(); + if(x < 0) x = 0; + if(y < 0) y = 0; + if(x >= 255) x = 255; + if(y >= 255) y = 255; + //qDebug() << x << y; + if(leftMouseMv && dragPoint >= 0) + { + if(pointLst[dragPoint] != pointLst.at(0) && pointLst[dragPoint] != pointLst.at(1)){ + if(x <= pointLst.at(0).x()) x = pointLst.at(0).x() + 1; + if(x >= pointLst.at(1).x()) x = pointLst.at(1).x() - 1; + + if(pointLst.size() == 4){ + if(dragPoint == 2){ + if(pointLst[2].x() > pointLst[3].x() && x <= pointLst[3].x()) + x = pointLst[3].x() + 1; + if(pointLst[2].x() < pointLst[3].x() && x >= pointLst[3].x()) + x = pointLst[3].x() - 1; + } + else if(dragPoint == 3){ + if(pointLst[2].x() < pointLst[3].x() && x <= pointLst[2].x()) + x = pointLst[2].x() + 1; + if(pointLst[2].x() > pointLst[3].x() && x >= pointLst[2].x()) + x = pointLst[2].x() - 1; + } + } + } + else if(pointLst[dragPoint] == pointLst.at(0)){ + int min = 999; + for(int i = 1; i < pointLst.size(); i++){ + if(min > pointLst[i].x()) min = pointLst[i].x(); + } + if(x >= min) x = min-1; + } + else if(pointLst[dragPoint] == pointLst.at(1)){ + if(pointLst.size() > 2){ + int max = 0; + for(int i = 2; i < pointLst.size(); i++){ + if(max < pointLst[i].x()) max = pointLst[i].x(); + } + if(x <= max) x = max+1; + } + else if(pointLst.size() <= 2) + if(x <= pointLst.at(0).x()) x = pointLst.at(0).x()+1; + } + pointLst[dragPoint].setX(x); + pointLst[dragPoint].setY(y); + emit lineChangeSig(); + update(); + } + emit mouseCoordSig(QPoint(x,y)); +} + +void Widget::mouseReleaseEvent(QMouseEvent *) +{ + leftMouseMv = false; +} + +void Widget::enterEvent(QEvent *) +{ + setFocus(Qt::MouseFocusReason); +} + +void Widget::leaveEvent(QEvent *) +{ + if(dragPoint < 0) + emit mouseLeaveSig(); +} + +void Widget::setHist_RGB(const QVector &hist) +{ + rgbBackColor = QVector(hist); +} + +QVector Widget::getHist_RED() const +{ + return redBackColor; +} + +void Widget::setHist_RED(const QVector &hist) +{ + redBackColor = QVector(hist); +} + +QVector Widget::getHist_RGB() const +{ + return rgbBackColor; +} + +void Widget::setHist_GREEN(const QVector &hist) +{ + greenBackColor = QVector(hist); +} + +QVector Widget::getHist_GREEN() const +{ + return greenBackColor; +} + +void Widget::setHist_BLUE(const QVector &hist) +{ + blueBackColor = QVector(hist); +} + +QVector Widget::getHist_BLUE() const +{ + return blueBackColor; +} + +void Widget::setHist_GRAY(const QVector &hist) +{ + grayBackColor = QVector(hist); +} + +QVector Widget::getHist_GRAY() const +{ + return grayBackColor; +} + +void Widget::drawCoordinate(QPainter &painter) +{ + painter.setBrush(QColor(79,79,79)); + painter.drawRect(0, 0, 260, 260); + painter.drawLine(-2000,0,2000,0); + painter.drawLine(0,1500,0,-1500); +} + +void Widget::drawBackgroudColor(QPainter &painter,QVector &curCol) +{ + painter.setPen(QPen(color,1)); + painter.setBrush(color); + int max = 0; + for(int i = 0; i < curCol.size(); i++) + { + if(curCol.at(i) > max) + { + max = curCol.at(i); + } + } + for(int i = 0; i < curCol.size(); i++) + { + painter.drawRect(i, 0, 1, curCol.at(i)*255/max); + } + +} + +void Widget::drawBackColorBySlc(QPainter &painter) +{ + switch(selectCol){ + case RGB: + drawBackgroudColor(painter,rgbBackColor); + break; + case GREEN: + drawBackgroudColor(painter,greenBackColor); + break; + case BLUE: + drawBackgroudColor(painter,blueBackColor); + break; + case RED: + drawBackgroudColor(painter,redBackColor); + break; + case GRAY: + drawBackgroudColor(painter,grayBackColor); + break; + } +} + +void Widget::drawCoorScale(QPainter &painter) +{ + painter.setPen(QPen(Qt::gray,1)); + for(int i = 0; i < 260 ; i+=50) + { + if(i%50 == 0 && i >=50) + { + QVector dashes; + qreal space = 3; + dashes << 5 << space << 5 < &plst, const int& col) +{ + double **a; + int len = plst.size(); + a = new double *[len]; + for(int i = 0; i < len; i++){ + a[i] = new double[len+1]; + } + /*******通过pointLst的所有点给二维数组赋值生成行列式*******/ + for(int i = 0; i < len; i++){ + for(int j = 0;j < len + 1; j++){ + if(j < len) + a[i][j] = caculateAllMi(plst.at(i).x(),len-j-1); + if(j == len) + a[i][j] = plst.at(i).y(); + } + } + + /*******调用高斯消元法计算曲线方程的系数值********/ + GaoSiXY gaoSi; + double *result = new double[len] ; + gaoSi.solve(a,len,result); + + /********保存曲线方程 x 的系数(a,b,c,d....)********/ + QList xiNum; + for(int i = 0; i < len; i++){ + xiNum.append(*(result+i)); + } + + linePoint.clear(); + linePoints.clear(); + for(int i = 0; i < 256; i++){ + int x = i; + double yVal = 0; + for(int j = 0; j < len; j++){ + yVal += xiNum.at(j)*caculateAllMi(x,len-j-1); + } + int y = (int)yVal; + if(y > 255) y = 255; + if(y < 0) y = 0; + if(x < plst.at(0).x()) y = plst.at(0).y(); + if(x > plst.at(1).x()) y = plst.at(1).y(); + allLinePoints[x] = y; + linePoints.append(y); + linePoint.append(QPoint(x,y)); + } + + + if(col == RED){ + redALLPoint.clear(); + for(int i = 0; i < linePoint.size(); i++) + redALLPoint.append(linePoint.at(i).y()); + } + if(col == GREEN){ + greenALLPoint.clear(); + for(int i = 0; i < linePoint.size(); i++) + greenALLPoint.append(linePoint.at(i).y()); + } + if(col == BLUE){ + blueALLPoint.clear(); + for(int i = 0; i < linePoint.size(); i++) + blueALLPoint.append(linePoint.at(i).y()); + } + if(col == GRAY){ + grayALLPoint.clear(); + for(int i = 0; i < linePoint.size(); i++) + grayALLPoint.append(linePoint.at(i).y()); + } + if(col == RGB){ + rgbALLPoint.clear(); + for(int i = 0; i < linePoint.size(); i++) + { + rgbALLPoint.append(linePoint.at(i).y()); + } + } + + + for(int i = 0;i < len; i++){ + delete[] a[i]; + } + delete []a; +} + +void Widget::drawAllPoint(QPainter &painter) +{ + if(pointLst.size() > 0) + { + painter.setPen(QPen(Qt::white,1)); + painter.setBrush(Qt::white); + for(int i = 0; i < pointLst.size(); i++){ + painter.drawEllipse(pointLst.at(i),3,3); + } + if(dragPoint >= 0){ + painter.setPen(QPen(QColor(0, 245, 255),2)); + painter.drawEllipse(pointLst[dragPoint],4,4); + } + } + + if(selectCol == GREEN){ + greenLine.clear(); + greenLine = QList(pointLst); + } + else if(selectCol == RED){ + redLine.clear(); + redLine = QList(pointLst); + }else if(selectCol == BLUE){ + blueLine.clear(); + blueLine = QList(pointLst); + }else if(selectCol == RGB){ + rgbLine.clear(); + rgbLine = QList(pointLst); + }else if(selectCol == GRAY){ + grayLine.clear(); + grayLine = QList(pointLst); + } +} + +void Widget::drawCurveByColor(QPainter &painter) +{ + qDebug() << selectCol; + switch (selectCol) { + case RGB: + painter.setPen(QPen(Qt::white,1)); + drawLineFromPoint(rgbLine, RGB); + drawLineByVector(painter,rgbALLPoint); + if(redLine.size()>2 || redLine.at(0)!= QPoint(0,0) || redLine.at(1)!= QPoint(255,255)){ + painter.setPen(QPen(Qt::red,1)); + drawLineFromPoint(redLine,RED); + drawLineByVector(painter,redALLPoint); + } + if(blueLine.size()>2 || blueLine.at(0)!= QPoint(0,0) || blueLine.at(1)!= QPoint(255,255)){ + painter.setPen(QPen(Qt::blue,1)); + drawLineFromPoint(blueLine, BLUE); + drawLineByVector(painter,blueALLPoint); + } + if(greenLine.size()>2 || greenLine.at(0)!= QPoint(0,0) || greenLine.at(1)!= QPoint(255,255)){ + painter.setPen(QPen(Qt::green,1)); + drawLineFromPoint(greenLine, BLUE); + drawLineByVector(painter,greenALLPoint); + } + break; + case RED: + painter.setPen(QPen(Qt::red,1)); + drawLineFromPoint(redLine,RED); + drawLineByVector(painter,redALLPoint); + break; + case BLUE: + painter.setPen(QPen(Qt::blue,1)); + drawLineFromPoint(blueLine, BLUE); + drawLineByVector(painter,blueALLPoint); + break; + case GREEN: + painter.setPen(QPen(Qt::green,1)); + drawLineFromPoint(greenLine, GREEN); + drawLineByVector(painter,greenALLPoint); + break; + case GRAY: + painter.setPen(QPen(Qt::white,1)); + drawLineFromPoint(grayLine, GRAY); + drawLineByVector(painter,grayALLPoint); + break; + default: + break; + } + drawLineFromPoint(pointLst, -1); +} + +void Widget::drawLineByVector(QPainter &painter,QVector &pVec) +{ + for(int i = 0; i < pVec.size()-1; i++){ + painter.drawLine(QPoint(i,pVec.at(i)),QPoint(i+1,pVec.at(i+1))); + } + update(); +} + +int Widget::caculateAllMi(int num, int n) +{ + int val = 1; + if(n == 0) return 1; + for(int i = 0; i < n; i++){ + val *= num; + } + return val; +} + +void Widget::getCurLineLUT(uchar *table, size_t length) +{ + for(size_t i = 0; i < length; i++) + { + table[i] = allLinePoints[i]; + } +} + +QVector Widget::getCurLinePntVec() +{ + return linePoints; +} + +void Widget::updateCurLinePnt(const int& colType) +{ + dragPoint = -1; + selectCol = colType; + if(selectCol == GREEN){ + color = QColor(202, 255, 112); + pointLst.clear(); + pointLst = QList(greenLine); + ui->widget_2->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:0, x2:1, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(0, 255, 0, 255))}"); + ui->widget->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:1, x2:0, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(0, 255, 0, 255))}"); + }else if(selectCol == BLUE){ + color = QColor(131, 111, 255); + pointLst.clear(); + pointLst = QList(blueLine); + ui->widget_2->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:0, x2:1, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(0, 0, 255, 255))}"); + ui->widget->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:1, x2:0, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(0, 0, 255, 255))}"); + }else if(selectCol == RED){ + color = QColor(255, 160, 122); + pointLst.clear(); + pointLst = QList(redLine); + ui->widget_2->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:0, x2:1, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 0, 0, 255))}"); + ui->widget->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:1, x2:0, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 0, 0, 255))}"); + }else if(selectCol == GRAY){ + color = Qt::gray; + pointLst.clear(); + pointLst = QList(grayLine); + ui->widget_2->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:0, x2:1, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))}"); + ui->widget->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:1, x2:0, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))}"); + }else if(selectCol == RGB){ + color = Qt::gray; + pointLst.clear(); + pointLst = QList(rgbLine); + ui->widget_2->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:0, x2:1, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))}"); + ui->widget->setStyleSheet("QWidget{background-color:qlineargradient(" + "spread:pad, x1:0, y1:1, x2:0, y2:0, " + "stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))}"); + } + update(); +} + +void Widget::setXCoorVal(const int &xVal) +{ + if(dragPoint >= 0){ + int x = xVal; + if(pointLst[dragPoint] != pointLst.at(0) && pointLst[dragPoint] != pointLst.at(1)){ + if(pointLst.size() == 3 && x > pointLst.at(0).x() && x < pointLst.at(1).x()) + pointLst[dragPoint].setX(x); + + if(pointLst.size() == 4){ + if(dragPoint == 2){ + if(pointLst[2].x() > pointLst[3].x() && x > pointLst[3].x() && x < pointLst[1].x()) + pointLst[dragPoint].setX(x); + if(pointLst[2].x() < pointLst[3].x() && x < pointLst[3].x() && x > pointLst[0].x()) + pointLst[dragPoint].setX(x); + } + else if(dragPoint == 3){ + if(pointLst[2].x() < pointLst[3].x() && x > pointLst[2].x() && x < pointLst[1].x()) + pointLst[dragPoint].setX(x); + if(pointLst[2].x() > pointLst[3].x() && x < pointLst[2].x() && x > pointLst[0].x()) + pointLst[dragPoint].setX(x); + } + } + } + else if(pointLst[dragPoint] == pointLst.at(0)){ + int min = 999; + for(int i = 1; i < pointLst.size(); i++){ + if(min > pointLst[i].x()) min = pointLst[i].x(); + } + if(x < min) pointLst[dragPoint].setX(x); + } + else if(pointLst[dragPoint] == pointLst.at(1)){ + if(pointLst.size() > 2){ + int max = 0; + for(int i = 2; i < pointLst.size(); i++){ + if(max < pointLst[i].x()) max = pointLst[i].x(); + } + if(x > max) pointLst[dragPoint].setX(x); + } + else if(pointLst.size() <= 2) + if(x > pointLst.at(0).x()) pointLst[dragPoint].setX(x); + } + update(); + } +} + +void Widget::setYCoorVal(const int &yVal) +{ + if(dragPoint >= 0){ + pointLst[dragPoint].setY(yVal); + update(); + } +} + +void Widget::initSelectColLine(const int& colType) +{ + pointLst.clear(); + pointLst.append(QPoint(0,0)); + pointLst.append(QPoint(255,255)); + switch(colType){ + case RED: + redLine.clear(); + redLine.append(QPoint(0,0)); + redLine.append(QPoint(255,255)); + break; + case BLUE: + blueLine.clear(); + blueLine.append(QPoint(0,0)); + blueLine.append(QPoint(255,255)); + break; + case GREEN: + greenLine.clear(); + greenLine.append(QPoint(0,0)); + greenLine.append(QPoint(255,255)); + break; + case GRAY: + grayLine.clear(); + grayLine.append(QPoint(0,0)); + grayLine.append(QPoint(255,255)); + break; + case RGB: + initAllLstPnt(); + break; + } + dragPoint = -1; + leftMouseMv = false; + newPoint = false; + clickLine = false; + setMouseTracking(true); + qDebug() << "init"; + updateCurLinePnt(colType); +} + +void Widget::SetAllLinePnt(QVector &all) +{ + allLinePntSet = QVector(all); +} + diff --git a/modules/twainui/widget.h b/modules/twainui/widget.h new file mode 100644 index 00000000..0ff62115 --- /dev/null +++ b/modules/twainui/widget.h @@ -0,0 +1,132 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include +#include +//#include "colorlinesetdef.h" + +namespace Ui { +class Widget; +} +// +//enum COLOR_TPYE +//{ +// RGB, +// GRAY, +// RED, +// BLUE, +// GREEN +//}; + +class Widget : public QWidget +{ + Q_OBJECT + +public: + explicit Widget(QWidget *parent = nullptr); + ~Widget(); + void initAllLstPnt(); //初始化所有颜色曲线 + void setLstPnt_RGB(const QList& plst); //设置生成RGB曲线的关键点(<=4) + QList getLstPnt_RGB()const; //获取生成RGB曲线的关键点 + void setLstPnt_RED(const QList& plst); + QList getLstPnt_RED()const; + void setLstPnt_BLUE(const QList& plst); + QList getLstPnt_BLUE()const; + void setLstPnt_GREEN(const QList& plst); + QList getLstPnt_GREEN()const; + void setLstPnt_GRAY(const QList& plst); + QList getLstPnt_GRAY()const; + + QVector getRgbALLPoint(); + QList getRgbKeyPoint()const; + void setRgbKeyPoint(const QList& pVec); + QVector getRedALLPoint(); + QList getRedKeyPoint()const; + void setRedKeyPoint(const QList& pVec); + QVector getBlueALLPoint(); + QList getBlueKeyPoint()const; + void setBlueKeyPoint(const QList& pVec); + QVector getGreenALLPoint(); + QList getGreenKeyPoint()const; + void setGreenKeyPoint(const QList& pVec); + QVector getGrayALLPoint(); + QList getGrayKeyPoint()const; + void setGrayKeyPoint(const QList& pVec); + + void setHist_RGB(const QVector& hist);//设置RGB的背景直方图 + QVector getHist_RGB()const;//获取RGB的背景直方图 + void setHist_RED(const QVector& hist); + QVector getHist_RED()const; + void setHist_BLUE(const QVector& hist); + QVector getHist_BLUE()const; + void setHist_GREEN(const QVector& hist); + QVector getHist_GREEN()const; + void setHist_GRAY(const QVector& hist); + QVector getHist_GRAY()const; + + void getCurLineLUT(uchar* table, size_t length = 256);//获取当前曲线上的所有点并存入table + QVector getCurLinePntVec();//获取当前曲线上的所有点 + void setXCoorVal(const int &xVal);//设置被选中的点的X坐标 + void setYCoorVal(const int &yVal);//设置被选中的点的Y坐标 + void updateCurLinePnt(const int& colType);//根据当前所选颜色(colType)重绘界面 + void initSelectColLine(const int& colType);//初始化当前所选颜色(colType)界面的曲线 + void SetAllLinePnt(QVector& all);//设置自定义曲线的所有点 + +signals: + void dragPointChecked(bool);//曲线上的点被选中的信号 + void mouseLeaveSig();//鼠标离开控件的信号 + void mouseCoordSig(QPoint pos);//鼠标的坐标信号 + void lineChangeSig(); + +private: + void initInterface();//初始化界面 + void paintEvent(QPaintEvent *); + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void enterEvent(QEvent*); + void leaveEvent(QEvent*); + void drawCoordinate(QPainter&);//画直角坐标 + void drawBackgroudColor(QPainter&,QVector&);//画背景直方图 + void drawBackColorBySlc(QPainter&);//画不同的背景直方图 + void drawCoorScale(QPainter&);//画虚线刻度 + void drawLineFromPoint(QList &plst, const int &col);//根据多点求出曲线方程,并画出曲线 + void drawAllPoint(QPainter&);//画出生成曲线的关键点 + void drawCurveByColor(QPainter&);//画不同的颜色曲线 + void drawLineByVector(QPainter&,QVector&);//将数组的所有点连接绘制曲线 + int caculateAllMi(int num,int n);//计算num的n次方的值 + +private: + Ui::Widget *ui; + QVector rgbBackColor; + QVector redBackColor; + QVector blueBackColor; + QVector greenBackColor; + QVector grayBackColor; + QVector rgbALLPoint; + QVector redALLPoint; + QVector blueALLPoint; + QVector greenALLPoint; + QVector grayALLPoint; + QVector allLinePntSet; + QVector linePoints; + + //QList points; + QList pointLst; + QList linePoint; + QList greenLine; + QList redLine; + QList blueLine; + QList rgbLine; + QList grayLine; + QColor color; + + unsigned char allLinePoints[256]; + bool leftMouseMv; + bool newPoint; + bool clickLine; + int dragPoint; + int selectCol; +}; + +#endif // WIDGET_H diff --git a/modules/twainui/widget.ui b/modules/twainui/widget.ui new file mode 100644 index 00000000..aaf5af1c --- /dev/null +++ b/modules/twainui/widget.ui @@ -0,0 +1,91 @@ + + + Widget + + + + 0 + 0 + 556 + 484 + + + + Widget + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + Qt::WheelFocus + + + QWidget{background-color:qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))} + + + + + + + + 0 + 20 + + + + true + + + Qt::NoFocus + + + + + + + + 0 + 0 + + + + QWidget{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255))} + + + + + + + + +