diff --git a/README.md b/README.md index 113e6fd8e9d75dcb2dd7127ba0d2be918cd7a1d5..2c56ca52d3036b7bb0d4203e4c0a380db3d0722f 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,35 @@ win32 : Qt 4.8.6 + MinGW 4.8.2 `windows 10 ` `ubuntu 16.04` `中标麒麟6.0` ## 功能需求 -1. 创建文档:生成基本OFD框架; -2. 页面设置与分页:设置纸张形式和分页机制; -3. 文字录入:在控制区域内实现文字的增、改、删; -4. 版面控制:设置版心、字体、颜色、字号、行距、字距等; -5. 段落控制:实现段落缩进、居左、居中、居右、撑满等。 -6. 图像控制:实现图像的插入和文字环绕; -7. 表格编辑:实现表格插入、绘制和文字表格内排版。 -8. 账号管理:能够注册、登录、注销用户账号; -9. 文件云端备份功能:能够将文件备份在云端、实现多版本保存; -10. ~~协同编辑:两个或多个用户能够同时编辑同一份文档。~~ + +1. 创建文档 +>创建文当是本系统的最基本的功能,即新建一个OFD类型的文档。新建的文档应该是一个只有页空白页的,默认纸张大小、默认页边距的文档。 +为了方便用户使用,在创建OFD文档时,应考虑增加几个常用板式模板。这样比如用户,创建完成后,只需要简单的改改自己需要的部分即可。 + +2. 页面设置与分页 +>页面设置与分页也是比较常用的功能,它要做的是设置纸张的大小与形式,之后再设置纸张的分页机制。本系统在实现时,应该设置到能够快速切换到常用纸张大小,比如:A3、A4、A5等纸张大小。 + +3. 文字录入 +>文字录入功能可以说是OFD文档原型系统必须实现的功能。本系统需要实现的是如同记事本一样非常自然的输入方式,让用户能够录入文字后立马看到效果,并且要能够做到在通用的OFD阅读器上打开也具有同样的效果。 + +4. 版面控制 +>版面控制需要实现设置版心、字体、颜色、字号、行距、字距等功能,这些功能都是版面布局时所需要的。同样,版面控制的效果需要在所有的OFD阅读器上都能够看到。 + +5. 图像控制 +>图像控制功能,即实现插入图片,设置常用的文字环绕方式。这里我们需要能够设置图片的尺寸,长宽比;需要设置文字环绕方式为包围式、嵌入文本行中等。 + +6. 表格编辑 +>表格编辑功能,需要能够插入表格,在表格中调节文字排版。并且,插入表格时要能够设置表格的行列数量,在后面也要能够对表格的单元格进行大小调整,分离或合并不同单元格。 + +7. 撤销恢复功能 +>用户在操作中常常遇到需要撤销恢复的情况,为此需要设置撤销恢复功能,最好撤销恢复次数需要大于10次。撤销恢复的功能目前可以说是商用编辑软件的必备功能了。 + +8. 查找替换功能 +>用户在编辑文档时,当文档过于长时,需要用查找功能查询到某处关键字,或者是需要进行关键词的批量替换。 + +9. 视图缩放功能 +>有的用户可能会嫌弃页面显示的内容太小;有的用户会觉得应用内容文字过大;而有的用户需要快速的浏览文档的内容。为此,系统需要包含浏览视图的放大缩小功能。此功能能够方便用户浏览,为用户的使用提供很大的便利性。 + ## 工程布局(实时更新) 本工程将采用Qt 多工程组织的形式,将按文件功能将代码文件分为若干个不同的子工程。
@@ -29,30 +48,27 @@ win32 : Qt 4.8.6 + MinGW 4.8.2 ``` |-model -> 系统工作时的数据模型及显示渲染 |-ofd -> ofd,主要用与ofd文件读取导出,以及ofd读取初期所使用的数据结构 -|-start -> start,主要存放启动程序已经程序的一些基本的界面文件。 +|-start -> start,程序的启动工程,存放关于主界面相关的 + +``` -|-test_chaoqun -> 江超群的测试工程 -|-test_pan -> 潘言星的测试工程 -|-test_yang -> 杨语晨的测试工程 +## 软件效果图 +![浏览样例](doc/imgs/image40.png) +![页面设置](doc/imgs/image41.png) +![查找替换](doc/imgs/image51.png) + +## 工程引用外部库 +工程引用了 `quazip 0.73`作为本工程的zip压缩工具,他人在编译本工程时,请预先配置好`quazip 0.73` 的环境,之后才可以正常编译本工程。 + +## 翻译文件 +本系统编写时设置语言为英文。在`model`和`start`工程下设置了翻译文件。 +``` +\ofdEditor + \-model + \-cn_model.ts + \-start + \-cn_start.ts ``` +编译时,使用Qt自带的Linguist程序生成relesae的翻译文件,放在编译完成的bin目录下。 -## Qt 帮助文档 -Qt的帮助文档极为丰富,看完之后能够对Qt的功能产生系统性的了解,这样设计软件时,思路就会更加的清晰。 - -| 文件名 | 作用 | -| --- | --- | -| Qt Data Types.pdf | Qt的一些基础数据类型 | -| Creating Custom Qt Types.pdf | 创建自定义的Qt 类 | -| MainWindow.pdf | 主窗口相关的 | -| Widget Tutorial.pdf | Widget 的简要教程 | -| Layout.pdf | 布局 | -| State Machine.pdf | 状态机 | -| Sighals and Slots.pdf | 信号槽 | -| Event System.pdf | 事件系统 | -| Drag and Drop.pdf | 拖拽操作处理 | -| Painting System.pdf | 绘画系统 | -| Qgraphics view framework.pdf | Qt的快速响应的图形渲染方式 | -| Qt 富文本框架.pdf | Qt富文本系统 | -| Creating Qt Plugins.pdf | 制作Qt插件 | -| Model View Programming.pdf | 模型视图结构编程 | -| Model View Tutorial.pdf | 模型视图结构教学 | +[QuaZip官网](http://quazip.sourceforge.net/) diff --git a/doc/imgs/image1.png b/doc/imgs/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..1ae63bdb683779dde2480cf2cb4f3c9adc50e487 Binary files /dev/null and b/doc/imgs/image1.png differ diff --git a/doc/imgs/image33.png b/doc/imgs/image33.png new file mode 100644 index 0000000000000000000000000000000000000000..b7399de910e22ad535602d8616230a776bd6c4cc Binary files /dev/null and b/doc/imgs/image33.png differ diff --git a/doc/imgs/image34.png b/doc/imgs/image34.png new file mode 100644 index 0000000000000000000000000000000000000000..c93c988903edd3c285fb59a0cbc6ec5104e1dbd2 Binary files /dev/null and b/doc/imgs/image34.png differ diff --git a/doc/imgs/image35.png b/doc/imgs/image35.png new file mode 100644 index 0000000000000000000000000000000000000000..720b71a77985aab42bdd6db3378fb75fecb0e410 Binary files /dev/null and b/doc/imgs/image35.png differ diff --git a/doc/imgs/image36.png b/doc/imgs/image36.png new file mode 100644 index 0000000000000000000000000000000000000000..8310efd832f93ed407f8c7cea029a1296aabb7b8 Binary files /dev/null and b/doc/imgs/image36.png differ diff --git a/doc/imgs/image37.png b/doc/imgs/image37.png new file mode 100644 index 0000000000000000000000000000000000000000..32827ecc644c24a85ec16c6fb8ab40b3cd24f256 Binary files /dev/null and b/doc/imgs/image37.png differ diff --git a/doc/imgs/image38.png b/doc/imgs/image38.png new file mode 100644 index 0000000000000000000000000000000000000000..12519fd615481c3d924a8694e59fa576682b8c54 Binary files /dev/null and b/doc/imgs/image38.png differ diff --git a/doc/imgs/image39.png b/doc/imgs/image39.png new file mode 100644 index 0000000000000000000000000000000000000000..561dcb9760034020fde327fce8367119d83c55b1 Binary files /dev/null and b/doc/imgs/image39.png differ diff --git a/doc/imgs/image40.png b/doc/imgs/image40.png new file mode 100644 index 0000000000000000000000000000000000000000..9dfc19ec98f6e99b24c1303f6b1034195ee9979e Binary files /dev/null and b/doc/imgs/image40.png differ diff --git a/doc/imgs/image41.png b/doc/imgs/image41.png new file mode 100644 index 0000000000000000000000000000000000000000..e16d914c40de0a1c3cffe56d9c35e4697eaddc7f Binary files /dev/null and b/doc/imgs/image41.png differ diff --git a/doc/imgs/image42.png b/doc/imgs/image42.png new file mode 100644 index 0000000000000000000000000000000000000000..f5a8404d5c718bc7d39344f9dcdc7685a2140930 Binary files /dev/null and b/doc/imgs/image42.png differ diff --git a/doc/imgs/image43.png b/doc/imgs/image43.png new file mode 100644 index 0000000000000000000000000000000000000000..85b88bf90ac730a73ab59a20309cbcf1c995704a Binary files /dev/null and b/doc/imgs/image43.png differ diff --git a/doc/imgs/image44.png b/doc/imgs/image44.png new file mode 100644 index 0000000000000000000000000000000000000000..ea8387acad19e1fa84006014a42e569730b34821 Binary files /dev/null and b/doc/imgs/image44.png differ diff --git a/doc/imgs/image45.png b/doc/imgs/image45.png new file mode 100644 index 0000000000000000000000000000000000000000..7f4f62e78cabc539a9fc75efaebf6e7bda7e9605 Binary files /dev/null and b/doc/imgs/image45.png differ diff --git a/doc/imgs/image46.png b/doc/imgs/image46.png new file mode 100644 index 0000000000000000000000000000000000000000..6acdd455c217b17c5d15167250e14e8e39346d60 Binary files /dev/null and b/doc/imgs/image46.png differ diff --git a/doc/imgs/image47.png b/doc/imgs/image47.png new file mode 100644 index 0000000000000000000000000000000000000000..d9e4f656c943056217fe62d2e0dbc76f8adfe797 Binary files /dev/null and b/doc/imgs/image47.png differ diff --git a/doc/imgs/image48.png b/doc/imgs/image48.png new file mode 100644 index 0000000000000000000000000000000000000000..3cbd2b1d9661c234a52308c7acbb4065bd263f27 Binary files /dev/null and b/doc/imgs/image48.png differ diff --git a/doc/imgs/image50.png b/doc/imgs/image50.png new file mode 100644 index 0000000000000000000000000000000000000000..384c180df9501433ead33ffdb40930cce6b0ddf1 Binary files /dev/null and b/doc/imgs/image50.png differ diff --git a/doc/imgs/image51.png b/doc/imgs/image51.png new file mode 100644 index 0000000000000000000000000000000000000000..072d0b321a268467edb9cfd620049a50fdcaffef Binary files /dev/null and b/doc/imgs/image51.png differ diff --git a/doc/imgs/image52.png b/doc/imgs/image52.png new file mode 100644 index 0000000000000000000000000000000000000000..ae91d2b0e254040a01b7040e31670e84c26ce6d3 Binary files /dev/null and b/doc/imgs/image52.png differ diff --git a/doc/imgs/image53.png b/doc/imgs/image53.png new file mode 100644 index 0000000000000000000000000000000000000000..383a2bf2db47b377452f95eff4e22a05b5dd1a35 Binary files /dev/null and b/doc/imgs/image53.png differ diff --git a/doc/imgs/image54.png b/doc/imgs/image54.png new file mode 100644 index 0000000000000000000000000000000000000000..5391aefea0e99d9cb1ebde9b9c0b087f0acb8454 Binary files /dev/null and b/doc/imgs/image54.png differ diff --git a/doc/imgs/image55.png b/doc/imgs/image55.png new file mode 100644 index 0000000000000000000000000000000000000000..eb50f782a5d36839f27bcdce39d4ddf19d9006dd Binary files /dev/null and b/doc/imgs/image55.png differ diff --git a/ofdEditor/AppSetting.json b/ofdEditor/AppSetting.json new file mode 100644 index 0000000000000000000000000000000000000000..2cd00f0894aa17d9ada42789ae38eec6bb461a5f --- /dev/null +++ b/ofdEditor/AppSetting.json @@ -0,0 +1,31 @@ +{ + "App": { + "Creator": "OFDEditor", + "CreatorVersion": "1.0", + "DocType": "OFD", + "DocVersion": "1.0", + "ViewMode": "Edit" + }, + "Font": { + "FontFamily": "黑体", + "FontSize": 12 + }, + "Page": { + "Width": 230, + "Height": 330, + "WorkWidth": 230, + "WorkHeight": 330, + "WorkX": 0, + "WoekY": 0, + "PageType": "A4" + }, + "Paragraph": { + "Horizontal": "AlignLeft", + "ParaIndent": 0, + "FirstIndent": 0, + "SpaceBefore": 0, + "SpaceAfter": 0, + "LineHeight": "SingleHeight", + "LineHeightValue": 0 + } +} \ No newline at end of file diff --git a/ofdEditor/libs/jsoncpp/json/json-forwards.h b/ofdEditor/libs/jsoncpp/json/json-forwards.h new file mode 100644 index 0000000000000000000000000000000000000000..ccbdb2b13c3843ae6e0465a25acd5fc72cff649a --- /dev/null +++ b/ofdEditor/libs/jsoncpp/json/json-forwards.h @@ -0,0 +1,255 @@ +/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +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. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED +# define JSON_FORWARD_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__clang__) && defined(__has_feature) +#if __has_feature(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#endif +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff --git a/ofdEditor/libs/jsoncpp/json/json.h b/ofdEditor/libs/jsoncpp/json/json.h new file mode 100644 index 0000000000000000000000000000000000000000..6859137eff66e094332cda3c5827169efe57cd7f --- /dev/null +++ b/ofdEditor/libs/jsoncpp/json/json.h @@ -0,0 +1,1981 @@ +/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +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. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGATED_H_INCLUDED +# define JSON_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "0.10.6" +# define JSONCPP_VERSION_MAJOR 0 +# define JSONCPP_VERSION_MINOR 10 +# define JSONCPP_VERSION_PATCH 6 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__clang__) && defined(__has_feature) +#if __has_feature(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#endif +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_; +}; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(std::string const& msg); + virtual ~Exception() throw(); + virtual char const* what() const throw(); +protected: + std::string const msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(std::string const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(std::string const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(std::string const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(std::string const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +#if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + static const Value& nullRef; +#if !defined(__ARMEL__) + /// \deprecated This exists for binary compatibility only. Use nullRef. + static const Value null; +#endif + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); + ~CZString(); + CZString& operator=(CZString other); + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. +This is useful since clear() and resize() will not alter types. + + Examples: +\code +Json::Value null_value; // null +Json::Value arr_value(Json::arrayValue); // [] +Json::Value obj_value(Json::objectValue); // {} +\endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value &operator=(const Value &other); + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! + std::string asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex size); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](int index); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](int index) const; + + /// If the array contains at least index+1 elements, returns the element + /// value, + /// otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const std::string& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const std::string& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const std::string& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + /// \deprecated + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + Value removeMember(const std::string& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(std::string const& key, Value* removed); + /// Same as removeMember(std::string const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const std::string& key) const; + /// Same as isMember(std::string const& key)const + bool isMember(const char* begin, const char* end) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const std::string& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + std::string getComment(CommentPlacement placement) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + +private: + void initBasic(ValueType type, bool allocated = false); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + char* comment_; + }; + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. + CommentInfo* comments_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const std::string& key); + +private: + enum Kind { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + ArrayIndex index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class JSON_API Path { +public: + Path(const std::string& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const std::string& path, const InArgs& in); + void addPathInArg(const std::string& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + void invalidPath(const std::string& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + std::string name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + Value& deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + //typedef unsigned int size_t; + //typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +} // namespace Json + + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +#define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + * back during + * serialization, \c false to discard comments. + * This parameter is ignored if + * Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON + document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + back during + * serialization, \c false to discard comments. + * This parameter is ignored if + Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(std::istream& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + std::string getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + */ + std::string getFormattedErrorMessages() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, std::string& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const std::string& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + std::string getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a JSON + document. + * The document must be a UTF-8 encoded string containing the document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, std::string* errs) = 0; + + class Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + std::string errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + virtual ~CharReaderBuilder(); + + virtual CharReader* newCharReader() const; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](std::string key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream( + CharReader::Factory const&, + std::istream&, + Value* root, std::string* errs); + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +JSON_API std::istream& operator>>(std::istream&, Value&); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + std::ostream* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, std::ostream* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + virtual ~StreamWriterBuilder(); + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](std::string key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual std::string write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API FastWriter : public Writer { + +public: + FastWriter(); + virtual ~FastWriter() {} + + void enableYAMLCompatibility(); + +public: // overridden from Writer + virtual std::string write(const Value& root); + +private: + void writeValue(const Value& value); + + std::string document_; + bool yamlCompatiblityEnabled_; +}; + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + virtual ~StyledWriter() {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write(const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const std::string& value); + void writeIndent(); + void writeWithIndent(const std::string& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static std::string normalizeEOL(const std::string& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledStreamWriter { +public: + StyledStreamWriter(std::string indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(std::ostream& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const std::string& value); + void writeIndent(); + void writeWithIndent(const std::string& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static std::string normalizeEOL(const std::string& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#if defined(JSON_HAS_INT64) +std::string JSON_API valueToString(Int value); +std::string JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +std::string JSON_API valueToString(LargestInt value); +std::string JSON_API valueToString(LargestUInt value); +std::string JSON_API valueToString(double value); +std::string JSON_API valueToString(bool value); +std::string JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API std::ostream& operator<<(std::ostream&, const Value& root); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + std::ostringstream oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +# define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ + { \ + std::ostringstream oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/ofdEditor/libs/jsoncpp/jsoncpp.cpp b/ofdEditor/libs/jsoncpp/jsoncpp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e61e84f0cea47f42a53e90950b0861ce4246ff8c --- /dev/null +++ b/ofdEditor/libs/jsoncpp/jsoncpp.cpp @@ -0,0 +1,4999 @@ +/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +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. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json/json.h" + +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { + +/// Converts a unicode code-point to UTF-8. +static inline std::string codePointToUTF8(unsigned int cp) { + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + +/* + if (cp <= 0x7f) + { + result.resize(1); + result[0] = static_cast(cp); + } + else if (cp <= 0x7FF) + { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } + else if (cp <= 0xFFFF) + { + if ( + (cp >= 0x4E00 && cp <= 0x9FA5) + || (cp >= 0xF900 && cp <= 0xFA2D) + || cp == 0x3002 + || cp == 0xFF1F + || cp == 0xFF01 + || cp == 0xFF0C + || cp == 0x3001 + || cp == 0xFF1B + || cp == 0xFF1A + || cp == 0x300C + || cp == 0x300D + || cp == 0x300E + || cp == 0x300F || cp == 0x2018 || cp == 0x2019 || cp == 0x201C + || cp == 0x201D || cp == 0xFF08 || cp == 0xFF09 || cp == 0x3014 + || cp == 0x3015 || cp == 0x3010 || cp == 0x3011 || cp == 0x2014 + || cp == 0x2026 || cp == 0x2013 || cp == 0xFF0E || cp == 0x300A + || cp == 0x300B || cp == 0x3008 || cp == 0x3009) + { + wchar_t src[2] = { 0 }; + char dest[5] = { 0 }; + src[0] = static_cast(cp); + std::string curLocale = setlocale(LC_ALL, NULL); + setlocale(LC_ALL, "chs"); + wcstombs_s(NULL, dest, 5, src, 2); + result = dest; + setlocale(LC_ALL, curLocale.c_str()); + } + else + { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + //result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + //result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); + result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); + } + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } */ + + return result; +} + +/// Returns true if ch is a control character (in range [1,31]). +static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned interger to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast(value % 10U + static_cast('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +static inline void fixNumericLocale(char* begin, char* end) { + while (begin < end) { + if (*begin == ',') { + *begin = '.'; + } + ++begin; + } +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#define snprintf std::snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +static int const stackLimit_g = 1000; +static int stackDepth_g = 0; // see readValue() + +namespace Json { + +#if __GNUC__ >= 6 +typedef std::scoped_ptr const CharReaderPtr; +#else +typedef std::auto_ptr CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false) +{} +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +static bool containsNewLine(Reader::Location begin, Reader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool +Reader::parse(const std::string& document, Value& root, bool collectComments) { + document_ = document; + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { + // std::istream_iterator begin(sin); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, (char)EOF); + return parse(doc, root, collectComments); +} + +bool Reader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + stackDepth_g = 0; // Yes, this is bad coding, but options are limited. + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // This is a non-reentrant way to support a stackLimit. Terrible! + // But this deprecated class has a security problem: Bad input can + // cause a seg-fault. This seems like a fair, binary-compatible way + // to prevent the problem. + if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_g; + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + break; + case tokenArrayBegin: + successful = readArray(token); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + } + break; + // Else, fall through... + default: + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_g; + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { + std::string normalized; + normalized.reserve(end - begin); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +Reader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const std::string& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char *p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } +} + +bool Reader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& /*tokenStart*/) { + Token tokenName; + std::string name; + Value init(objectValue); + currentValue().swapPayload(init); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool Reader::readArray(Token& /*tokenStart*/) { + Value init(arrayValue); + currentValue().swapPayload(init); + skipSpaces(); + if (*current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(c - '0'); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + std::string buffer(token.start_, token.end_); + std::istringstream is(buffer); + if (!(is >> value)) + return addError("'" + std::string(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + std::string decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + return true; +} + +bool Reader::decodeString(Token& token, std::string& decoded) { + decoded.reserve(token.end_ - token.start_ - 2); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + return true; +} + +bool +Reader::addError(const std::string& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + int errorCount = int(errors_.size()); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +std::string Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +std::string Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +std::string Reader::getFormattedErrorMessages() const { + std::string formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +// Reader +///////////////////////// + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + OurFeatures(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures::OurFeatures() + : allowComments_(true), strictRoot_(false) + , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) + , allowSingleQuotes_(false) + , failIfExtra_(false) + , allowSpecialFloats_(false) +{ +} + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + size_t offset_start; + size_t offset_limit; + std::string message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + std::string getFormattedErrorMessages() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, std::string& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const std::string& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + std::string getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + std::string commentsBefore_; + int stackDepth_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool OurReader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + stackDepth_ = 0; + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if (token.type_ != tokenError && token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_; + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + break; + case tokenArrayBegin: + successful = readArray(token); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + break; + } // else, fall through ... + default: + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_; + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else continue + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +void +OurReader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const std::string& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& /*tokenStart*/) { + Token tokenName; + std::string name; + Value init(objectValue); + currentValue().swapPayload(init); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + std::string msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover( + msg, tokenName, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool OurReader::readArray(Token& /*tokenStart*/) { + Value init(arrayValue); + currentValue().swapPayload(init); + skipSpaces(); + if (*current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(c - '0'); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + std::string buffer( token.start_, token.end_ ); + std::istringstream is(buffer); + if (!(is >> value)) + return addError("'" + std::string(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + std::string decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + return true; +} + +bool OurReader::decodeString(Token& token, std::string& decoded) { + decoded.reserve(token.end_ - token.start_ - 2); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + return true; +} + +bool +OurReader::addError(const std::string& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + int errorCount = int(errors_.size()); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +std::string OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +std::string OurReader::getFormattedErrorMessages() const { + std::string formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, std::string* errs) { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() +{ + setDefaults(&settings_); +} +CharReaderBuilder::~CharReaderBuilder() +{} +CharReader* CharReaderBuilder::newCharReader() const +{ + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + std::string const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](std::string key) +{ + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) +{ +//! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) +{ +//! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream( + CharReader::Factory const& fact, std::istream& sin, + Value* root, std::string* errs) +{ + std::ostringstream ssin; + ssin << sin.rdbuf(); + std::string doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +std::istream& operator>>(std::istream& sin, Value& root) { + CharReaderBuilder b; + std::string errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + + throwRuntimeError("reader error"); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - current_; +#else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +#endif +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +std::string ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return std::string(); + return std::string(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +#include +#endif +#include // size_t +#include // min() + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +// This exists for binary compatibility only. Use nullRef. +const Value Value::null; +#define ALIGNAS(byte_alignment) +#endif +static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +const unsigned char& kNullRef = kNull[0]; +const Value& Value::nullRef = reinterpret_cast(kNullRef); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template +static inline bool InRange(double d, T min, U max) { + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); +} + +template static inline double integerToDouble(T value) { + return static_cast(value); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, + size_t length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= (size_t)Value::maxInt) + length = Value::maxInt - 1; + + char* newString = static_cast(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; + char* newString = static_cast(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +static inline void releaseStringValue(char* value) { free(value); } + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(std::string const& msg) + : msg_(msg) +{} +Exception::~Exception() throw() +{} +char const* Exception::what() const throw() +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(std::string const& msg) + : Exception(msg) +{} +LogicError::LogicError(std::string const& msg) + : Exception(msg) +{} +JSONCPP_NORETURN void throwRuntimeError(std::string const& msg) +{ + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(std::string const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) {} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} + +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) +{ + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) + : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_) +{ + storage_.policy_ = (other.cstr_ + ? (static_cast(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast(other.storage_.policy_)); + storage_.length_ = other.storage_.length_; +} + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) + releaseStringValue(const_cast(cstr_)); +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(CZString other) { + swap(other); + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType vtype) { + initBasic(vtype); + switch (vtype) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); +} + +Value::Value(const char* beginValue, const char* endValue) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); +} + +Value::Value(const std::string& value) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(Value const& other) + : type_(other.type_), allocated_(false) + , + comments_(0) +{ + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + allocated_ = false; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } + if (other.comments_) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment( + otherComment.comment_, strlen(otherComment.comment_)); + } + } +} + +Value::~Value() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releaseStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + + if (comments_) + delete[] comments_; +} + +Value &Value::operator=(const Value &other) { + Value temp(other); + swap(temp); + return *this; +} + +void Value::swapPayload(Value& other) { + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap(value_, other.value_); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2 & 0x1; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); +} + +ValueType Value::type() const { return type_; } + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type_ - other.type_; + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type_) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + // if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if (type_ != temp) + return false; + switch (type_) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +bool Value::getString(char const** str, char const** cend) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *cend = *str + length; + return true; +} + +std::string Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return std::string(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString() == "") || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; +} + +bool Value::operator!() const { return isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + (*this)[newSize - 1]; + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + assert(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + CZString key(index); + ObjectValues::iterator it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullRef); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullRef; + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullRef; + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; + allocated_ = allocated; + comments_ = 0; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(strlen(key)), CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* cend) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(cend-key), CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullRef ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* key, char const* cend) const +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullRef; + return *found; +} +Value const& Value::operator[](std::string const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullRef; + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const std::string& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullRef; + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const +{ + Value const* found = find(key, cend); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(std::string const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); +} + + +bool Value::removeMember(const char* key, const char* cend, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + *removed = it->second; + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(std::string const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); +} +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullRef; + + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const std::string& key) +{ + return removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* key, char const* cend) const +{ + Value const* value = find(key, cend); + return NULL != value; +} +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(std::string const& key) const +{ + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(std::string((*it).first.data(), + (*it).first.length())); + } + return members; +} +// +//# ifdef JSON_USE_CPPTL +// EnumMemberNames +// Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: + return value_.int_ >= minInt && value_.int_ <= maxInt; + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); + case uintValue: + return value_.uint_ <= maxUInt; + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { +#if defined(JSON_HAS_INT64) + return isInt64() || isUInt64(); +#else + return isInt() || isUInt(); +#endif +} + +bool Value::isDouble() const { return type_ == realValue || isIntegral(); } + +bool Value::isNumeric() const { return isIntegral() || isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const std::string& comment, CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +std::string Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +std::string Value::toStyledString() const { + StyledWriter writer; + return writer.write(*this); +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const std::string& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const std::string& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const std::string& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *current++ != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(std::string(beginName, current)); + } + } +} + +void Path::addPathInArg(const std::string& /*path*/, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg); + } +} + +void Path::invalidPath(const std::string& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if (node == &Value::nullRef) { + // Error: unable to resolve path (object has no member named '' at + // position...) + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullRef) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#include +#define isfinite finite +#else +#include +#define isfinite std::isfinite +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#define snprintf std::snprintf +#endif + +#if defined(__BORLANDC__) +#include +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __GNUC__ >= 6 +typedef std::scoped_ptr const StreamWriterPtr; +#else +typedef std::auto_ptr StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +std::string valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +std::string valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +std::string valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +std::string valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[32]; + int len = -1; + + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + // For those, we do not need to call fixNumLoc, but it is fast. + } + assert(len >= 0); + fixNumericLocale(buffer, buffer + len); + return buffer; +} + +std::string valueToString(double value) { return valueToString(value, false, 17); } + +std::string valueToString(bool value) { return value ? "true" : "false"; } + +std::string valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && + !containsControlCharacter(value)) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + std::string::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c = value; *c != 0; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static std::string valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + std::string::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +std::string FastWriter::write(const Value& root) { + document_ = ""; + writeValue(root); + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast(end-str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + int size = value.size(); + for (int index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (Value::Members::iterator it = members.begin(); it != members.end(); + ++it) { + const std::string& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +std::string StyledWriter::write(const Value& root) { + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += "\n"; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const std::string& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultineArray(const Value& value) { + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = + isMultiLine || ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const std::string& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const std::string& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(int(indentString_.size()) >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += "\n"; + writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(std::string indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(std::ostream& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const std::string& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultineArray(const Value& value) { + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = + isMultiLine || ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const std::string& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const std::string& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + std::string const& indentation, + CommentStyle::Enum cs, + std::string const& colonSymbol, + std::string const& nullSymbol, + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + virtual int write(Value const& root, std::ostream* sout); +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(std::string const& value); + void writeIndent(); + void writeWithIndent(std::string const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + CommentStyle::Enum cs_; + std::string colonSymbol_; + std::string nullSymbol_; + std::string endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + std::string const& indentation, + CommentStyle::Enum cs, + std::string const& colonSymbol, + std::string const& nullSymbol, + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_ = ""; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + std::string const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ", "; + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = + isMultiLine || ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(std::string const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + std::string indentation = settings_["indentation"].asString(); + std::string cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + std::string colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + std::string nullSymbol = "null"; + if (dnp) { + nullSymbol = ""; + } + if (pre > 17) pre = 17; + std::string endingLineFeedSymbol = ""; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + std::string const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](std::string key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +std::string writeString(StreamWriter::Factory const& builder, Value const& root) { + std::ostringstream sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +std::ostream& operator<<(std::ostream& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// diff --git a/ofdEditor/model/Command/SetTextBlodCmd.h b/ofdEditor/model/Command/SetTextBlodCmd.h index 89f76b6c10ea0008991ceaf7268c0e542aac56a0..d53e31c8a193c1a1c220e7ed66454fb550daa3a3 100644 --- a/ofdEditor/model/Command/SetTextBlodCmd.h +++ b/ofdEditor/model/Command/SetTextBlodCmd.h @@ -10,7 +10,8 @@ class DocTextBlock; class DocPage; class DocLayer; -class SetTextBlodCmd:public QUndoCommand +class SetTextBlodCmd: + public QUndoCommand { public: SetTextBlodCmd(DocTextBlock *docTextBlock,QTextCursor &cursor,QUndoCommand *parent=0); diff --git a/ofdEditor/model/Convert/BuildTextBlock.cpp b/ofdEditor/model/Convert/BuildTextBlock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7308f14ff344af0a2cd35e440b9b4a2d0cdc699b --- /dev/null +++ b/ofdEditor/model/Convert/BuildTextBlock.cpp @@ -0,0 +1,585 @@ +#include "BuildTextBlock.h" +#include "DataTypes/page/CT_Layer.h" + +BuildTextBlock::BuildTextBlock() +{ + +} + +void BuildTextBlock::buildText( + DocTextBlock *textblock, + CT_Layer *layer, + ID_Table *table, + Doc_OFDConvertor *convertor) +{ + this->textBlock = textblock; + this->layer = layer; + this->table = table; + this->convertor = convertor; + + this->caculateLineHeight(); // 先计算行高 + caculateBlockLine(); //计算每块的行数 + caculateLineContentWidth(); + build(); +} + +/// +/// \brief BuildTextBlock::caculateLineHeight +/// +void BuildTextBlock::caculateLineHeight() +{ + int lineCount = 0; + this->textBlock->moveCursor(QTextCursor::Start); + QTextCursor cursor = this->textBlock->textCursor(); + + + // 一行一行的进行遍历-记录每行的开始位置和行数 + while(!cursor.atEnd()) + { + lineCount ++; + cursor.movePosition(QTextCursor::StartOfLine); // 移动到每行开始的位置 + this->start_of_line_Pos.push_back(cursor.position()); + +// cursor.select(QTextCursor::LineUnderCursor); +// this->every_line_text.push_back(cursor.selectedText()); +// cursor.movePosition(QTextCursor::NoMove); + + cursor.movePosition(QTextCursor::EndOfLine); // 移动到当前行尾,纪录位置 + this->end_of_line_pos.push_back(cursor.position()); // 将该行的结尾位置发出来 + + + cursor.movePosition(QTextCursor::Right); + + // 先用每块的字体初始化一下 lineHeight_Font + QTextCharFormat charFormat = cursor.charFormat(); + QFontMetrics fontMetrics(charFormat.font()); + + lineHeight_Font.push_back( + fontMetrics.ascent() + + fontMetrics.descent() + + fontMetrics.leading() + 1); + + } + cursor.movePosition(QTextCursor::Start); + while(!cursor.atEnd()) + { + cursor.select(QTextCursor::LineUnderCursor); + this->every_line_text.push_back(cursor.selectedText()); + cursor.movePosition(QTextCursor::Right); + } + + // 计算每行的行高---------------------------------------------- + QTextFrame::iterator it = textBlock->document()->rootFrame()->begin(); // 遍历rootFrame + while (!it.atEnd()) + { + // QTextBlock + QTextBlock block = it.currentBlock(); // 当前block + qDebug() << "block "<< block.text(); + + QTextBlock::iterator block_it = block.begin(); + while(!block_it.atEnd()) + { + // 遍历QTextFragment + QTextFragment fragment = block_it.fragment(); + start_of_fragment.push_back(fragment.position()); + + // 判断 fragment 影响哪几行的高度 + int lineHeight_fragment = 0; + QFontMetricsF fontMetrics(fragment.charFormat().font()); + lineHeight_fragment = fontMetrics.ascent() + fontMetrics.descent() + fontMetrics.leading() + 1; + + // 利用快的起点和重点,判断影响了哪几行 + int start_pos = fragment.position(); + int end_pos = fragment.position() + fragment.length() - 1; + int start_line = 0; + int end_line = 0; + + for(int line = 0; line < end_of_line_pos.size(); line ++) + { + if(start_pos > end_of_line_pos[line]) + { + start_line = line + 1; + } + + if(end_pos < end_of_line_pos[line]) + { + end_line = line; + break; + } + } + qDebug() << "fragment pos"< lineHeight_Font[line]) + { + lineHeight_Font[line] = lineHeight_fragment; + } + } + + block_it ++; + } // 遍历fragment + it ++; + } // 遍历block + + // 结合行高策略,计算每行的行高--------------------------------------------- + lineHeight_Real = lineHeight_Font; // 复制内容 + + // 遍历每行,根据行高规则计算行高 + for(int line = 0 ; line < end_of_line_pos.size(); line ++) + { + cursor.setPosition(end_of_line_pos[line]); + QTextBlockFormat blockFormat = cursor.blockFormat(); + + int lineHeightType = blockFormat.lineHeightType(); + int lineHeightValue = blockFormat.lineHeight(); + + switch (lineHeightType) + { + case QTextBlockFormat::SingleHeight: + // 单倍行距不用改 + break; + case QTextBlockFormat::MinimumHeight: + // 最小值 + if(lineHeight_Font[line] < lineHeightValue) + { + lineHeight_Real[line] = lineHeightValue; + } + else + { + lineHeight_Real[line] = lineHeight_Font[line]; + } + break; + case QTextBlockFormat::FixedHeight: + // 固定值 + lineHeight_Real[line] = lineHeightValue; + break; + case QTextBlockFormat::ProportionalHeight: + // 多倍行距 + lineHeight_Real[line] = (int)(1.0 * lineHeightValue / 100 * lineHeight_Font[line]); + break; + default: + break; + } + } + + qDebug() << "lineCount" << lineCount << endl + << "end of line" << end_of_line_pos << endl + << " start of fragements" << start_of_fragment << endl + << "line height font" << lineHeight_Font << endl + << "line height real" << lineHeight_Real << endl + << "every line text" << every_line_text << endl; + +} + +void BuildTextBlock::caculateBlockLine() +{ + QTextFrame::iterator iter = this->textBlock->document()->rootFrame()->begin(); // 开始的位置 + QTextCursor cursor = this->textBlock->textCursor(); + cursor.movePosition(QTextCursor::Start); + + int blockNum = 0; + while(!iter.atEnd()) + { + QTextBlock block = iter.currentBlock(); + cursor.setPosition(block.position()); + int startPos = cursor.position(); + int startLine = this->start_of_line_Pos.indexOf(startPos); + + cursor.movePosition(QTextCursor::EndOfBlock); + int endLine = this->end_of_line_pos.indexOf(cursor.position()); + + qDebug() << "block" << blockNum + << "startLine" << startLine + << "endLine" << endLine + << "blockNum" << blockNum + << "blockNumber" << block.blockNumber(); + + this->blockStartLineNum.push_back(startLine); + this->blockEndLineNum.push_back(endLine); + + blockNum ++; // 记录块数 + iter ++; + } + + // 计算每一个块开始的位置 + int startY = 0; + blockNum = 0; + double margin = 0; + iter = this->textBlock->document()->rootFrame()->begin(); + while(!iter.atEnd()) + { + // 两个block直接的距离 + if(iter.currentBlock() != this->textBlock->document()->firstBlock()) + { + // 比较Margin + double topMargin = iter.currentBlock().blockFormat().topMargin(); + if(topMargin > margin) + { + margin = topMargin; + } + startY += margin; + } + + this->blockStartY.push_back(startY); // 第一个块从0开始 + this->blockStartX.push_back( + iter.currentBlock().blockFormat().indent() * this->textBlock->document()->indentWidth()); + + double height = 0; + for(int i = this->blockStartLineNum[blockNum]; i <= this->blockEndLineNum[blockNum]; i++) + { + height += lineHeight_Real[i]; + } + + startY += height; // 将行的高度加入到 startY中 + + blockNum ++; + iter++; + } + + qDebug() << "block start Y" << blockStartY + << "block start X" << blockStartX; +} + +/// +/// \brief BuildTextBlock::caculateLineContentWidth +/// +void BuildTextBlock::caculateLineContentWidth() +{ + QTextFrame::iterator iter = this->textBlock->document()->rootFrame()->begin(); // 开始的位置 + int blockNum = 0; + // 循环每个块,循环处理每个语句,来生成这个行宽度的内容 + while(!iter.atEnd()) + { + int currentLine = blockStartLineNum[blockNum]; // 从这行开始 + QString lineContent; // 临时的行内容 + QString fragmentContent; // 临时的片段内容 + QTextBlock::iterator it_fragment = iter.currentBlock().begin(); + QTextFragment fragment = it_fragment.fragment(); + fragmentContent = fragment.text(); + + for(int i = currentLine; i <= blockEndLineNum[blockNum] && !it_fragment.atEnd(); i++) + { + lineContent = every_line_text[i]; + double width = 0; + while(fragmentContent.size() < lineContent.size()) + { + qDebug() << "fragmentContent " << fragmentContent; + + QFontMetricsF fontMetric(fragment.charFormat().font()); + width += fontMetric.boundingRect(fragmentContent).width(); + it_fragment ++; + lineContent.remove(0,fragmentContent.size()); + fragment = it_fragment.fragment(); + fragmentContent = fragment.text(); + + } + + qDebug() << "lineContent" << lineContent; + + QFontMetricsF fontMetirc(fragment.charFormat().font()); + width += fontMetirc.boundingRect(lineContent).width(); + lineWidth_content.push_back(width); + fragmentContent.remove(0,lineContent.size()); + } + + iter ++; + blockNum ++; + } + + qDebug() << "line Width" << lineWidth_content; +} + +/// +/// \brief BuildTextBlock::build +/// +void BuildTextBlock::build() +{ + QTextFrame::iterator iter = this->textBlock->document()->rootFrame()->begin(); // 开始的位置 + int blockNum = 0; + // 循环每个块,循环处理每个语句,来生成这个行宽度的内容 + while(!iter.atEnd()) + { + QTextBlock block = iter.currentBlock(); + QTextBlockFormat blockFormat = block.blockFormat(); + QTextBlock::iterator it_fragment = block.begin(); + QTextFragment fragment = it_fragment.fragment(); + QString lineContent; + QString fragmentContent; + double temp_x = 0; + double temp_y = 0; + int currentLine = blockStartLineNum[blockNum] - 1; + + while(currentLine <= blockEndLineNum[blockNum] + || !it_fragment.atEnd() + || fragmentContent.size() != 0) + { + if(lineContent.size() == 0) + { + // 如果当前行没内容了 + currentLine ++; + if(currentLine > blockEndLineNum[blockNum]) + { + // 放止因为fragment 而出现问题 + break; + } + + lineContent = every_line_text[currentLine]; + temp_y += lineHeight_Real[currentLine]; + if(currentLine == blockStartLineNum[blockNum]) + { + int indent = blockFormat.indent() * this->textBlock->document()->indentWidth() + + blockFormat.textIndent(); + + temp_x = calculateTemp_x(currentLine,blockFormat.alignment(),indent); + } + else + temp_x = calculateTemp_x(currentLine, blockFormat.alignment(), + blockFormat.indent() * this->textBlock->document()->indentWidth()); + continue; + } + if(fragmentContent.size() == 0) + { + // 如果当前处理的块内容用完了 + fragment = it_fragment.fragment(); + fragmentContent = fragment.text(); + it_fragment ++; + continue; + } + + QString editContent; + if(lineContent.size() <= fragmentContent.size()) + { + editContent = lineContent; + fragmentContent.remove(0,lineContent.size()); + lineContent = ""; + } + else + { + editContent = fragmentContent; + lineContent.remove(0,fragmentContent.size()); + fragmentContent = ""; + } + + qDebug() << "Line " << currentLine + << "Deal:" << editContent; + + double width =buildSmall_cttext( + editContent, + fragment.charFormat(), + this->textBlock->getBlock()->x() + temp_x, + this->textBlock->getBlock()->y() + blockStartY[blockNum] + temp_y, + currentLine, + blockFormat.alignment()); + + temp_x = temp_x + width; + } + + + iter++; + blockNum++; + } + + qDebug() << "line Width" << lineWidth_content; +} + +double BuildTextBlock::calculateTemp_x(int lineNum, int align, double indent) +{ + double contentWidth = lineWidth_content[lineNum]; + double blockwidth = this->textBlock->getBlock()->size().width(); + + switch (align) { + case Qt::AlignLeft: + // 左对齐的开始位置 + return indent; + break; + case Qt::AlignRight: + return blockwidth - contentWidth; + break; + case Qt::AlignHCenter: + return (blockwidth - contentWidth) / 2.0; + break; + case Qt::AlignJustify: + qDebug() <<"Justify"; + return indent; + break; + default: + break; + } +} + +/// +/// \brief BuildTextBlock::buildSmall_cttext +/// \param content +/// \param font +/// \param x +/// \param y +/// \param lineNum +/// \param align +/// \return +/// +double BuildTextBlock::buildSmall_cttext( + QString content, QTextCharFormat charFormat, double x, double y, int lineNum, Qt::Alignment align) +{ + QFont font = charFormat.font(); + + qDebug() <<"build small cttext " <setID(this->table->size() +1, this->table); + this->layer->getTextObject()->append(ct_text); + + CT_Font* ctfont = new CT_Font(); + ctfont->setFamilyName(font.family()); + ctfont->setFontName(font.family()); + int font_id = this->convertor->addFont(ctfont); + ct_text->setFont(font_id, this->table); + + // 设置字体 + if(font.italic()) + { + ct_text->setItalic(true); + qDebug() << "italic -------------------------------------"; + } + // 设置字重 + ct_text->setWeight(this->getWeight(font.weight())); + + // 设置颜色 + QColor color = charFormat.foreground().color(); // 获得颜色 + CT_ColorSpace *space = new CT_ColorSpace(); + space->setBitsPerComponent(8); + space->setType("RGB"); + int colorSpaceId = this->convertor->addColorSpace(space); + CT_Color* ct_color = new CT_Color(); + ct_color->setValue(QString::number(color.red()) + + " " + QString::number(color.green()) + + " " + QString::number(color.blue())); + ct_color->setColorSpace(colorSpaceId,this->table); + ct_text->setFillColor(ct_color); + + QFontMetricsF fontMetrics(font); + + // qDebug() << "font pointsize" + // << font.pointSizeF() + // << "font pixel Size" + // << font.pixelSize() << UnitTool::pixelToMM(font.pixelSize()) + // << "pixelToMM" << UnitTool::pixelToMM( + // fontMetrics.ascent() + fontMetrics.descent() + 1) + // << "test" << font.pointSizeF() * 0.35146; + if(font.pointSizeF() != -1) + { + ct_text->setSize( + UnitTool::pointSizeToMM(font.pointSizeF())); + } + else if(font.pixelSize() != -1) + { + ct_text->setSize( + UnitTool::pixelToMM(font.pixelSize())); + } + // ct_text->setSize( + // UnitTool::pixelToMM( + // fontMetrics.ascent() + fontMetrics.descent() + 1)); + + + double width = 0; + + + + if(align ==Qt::AlignLeft + || align == Qt::AlignRight + || align == Qt::AlignHCenter) + { + ct_text->setBoundary( + UnitTool::pixelToMM(x), + UnitTool::pixelToMM(y), + UnitTool::pixelToMM(fontMetrics.boundingRect(content).width() + 10), + UnitTool::pixelToMM(lineHeight_Real[lineNum] + 5)); + + TextCode *txtCode = new TextCode(); // 文字内容 + txtCode->setText(content); + txtCode->setX( + UnitTool::pixelToMM(0)); + txtCode->setY( + UnitTool::pixelToMM(lineHeight_Font[lineNum])); + if(content.size() > 1) + { + QString delta_x; + for(int delta = 0; delta setDeltaX(delta_x); + } + + width = fontMetrics.boundingRect(content).width(); + ct_text->getTextCode()->append(txtCode); + } + else if(align == Qt::AlignJustify) + { + double delta_delta_x = 1.0 * + (this->textBlock->getBlock()->size().width() - lineWidth_content[lineNum]) + /( every_line_text[lineNum].size() -1); + + ct_text->setBoundary( + UnitTool::pixelToMM(x), + UnitTool::pixelToMM(y), + UnitTool::pixelToMM(fontMetrics.boundingRect(content).width() + + content.length() * delta_delta_x), + UnitTool::pixelToMM(lineHeight_Real[lineNum] + 5)); + + TextCode *textCode = new TextCode(); // 文字内容 + textCode->setText(content); + textCode->setX( + UnitTool::pixelToMM(1)); + textCode->setY( + UnitTool::pixelToMM(lineHeight_Font[lineNum])); + + if(content.size() > 1) + { + QString delta_x; + for(int delta = 0; delta setDeltaX(delta_x); + } + ct_text->getTextCode()->append(textCode); + + width = fontMetrics.boundingRect(content).width() + delta_delta_x * content.size(); + } + + qDebug() <<"build small cttext " < +#include +#include +#include +#include +#include +#include + +class MODELSHARED_EXPORT BuildTextBlock +{ +public: + BuildTextBlock(); + + void buildText( + DocTextBlock* textblock, + CT_Layer *layer, + ID_Table *table, + Doc_OFDConvertor *convertor); + + void caculateLineHeight(); + void caculateBlockLine(); // 计算每个块开始于第几行,结束于第几行 + void caculateLineContentWidth(); // 计算每行文本所占的文字的宽度 + void build(); // 开始构建真正的内容 + double calculateTemp_x(int lineNum, int align, double indent); // 根据现有信息,计算出temp_x + double buildSmall_cttext(QString content, QTextCharFormat charFormat, double x, double y, int lineNum, Qt::Alignment align); + int getWeight(double width); // 将Qt中的字重转换为ofd的字重 + + DocTextBlock *textBlock; + CT_Layer *layer; + ID_Table *table; + Doc_OFDConvertor* convertor; + + QVector lineHeight_Font; // 每个字体的实际高度 + QVector lineHeight_Real; // 经过段落格式后的高度 + QVector end_of_line_pos; // 纪录每一行结尾的地方 + QVector start_of_line_Pos; // 记录每行开始的位置 + QVector start_of_fragment; // 每一个QTextFragment开始的位置 + QVector every_line_text; // 记录每行的文字的内容 + + QVector blockStartLineNum; // 块开始于第几行 + QVector blockEndLineNum; // 块结束于第几行 + + QVector blockStartY; // 每个块从哪个y值开始 + QVector blockStartX; // 每个块从哪个x值开始 + + QVector lineWidth_content; // 某行内容的宽度--通过QFontMetricsF 计算 +}; + +#endif // BUILDTEXTBLOCK_H diff --git a/ofdEditor/model/Convert/BuildTextTable.cpp b/ofdEditor/model/Convert/BuildTextTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc01e1c7d6bcaec54e93b8fef03767d747388305 --- /dev/null +++ b/ofdEditor/model/Convert/BuildTextTable.cpp @@ -0,0 +1,123 @@ +#include "BuildTextTable.h" + +#include "Doc_OFDConvertor.h" +#include "Doc/DocPassage.h" +#include "Doc/DocPage.h" +#include "Doc/DocBlock.h" +#include "Doc/DocTextBlock.h" +#include "Doc/DocLayer.h" +#include "Doc/DocImageBlock.h" +#include "Doc/DocTable.h" +#include "Convert/BuildTextBlock.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DataTypes/basic_datatype.h" +#include "DataTypes/document/ofd.h" +#include "DataTypes/document/Res.h" +#include "DataTypes/document/docbody.h" +#include "DataTypes/document/ct_docinfo.h" +#include "DataTypes/document/document.h" +#include "DataTypes/page/ct_pages.h" +#include "DataTypes/page/page.h" +#include "DataTypes/page/ct_layer.h" +#include "DataTypes/page/CT_PageArea.h" +#include "DataTypes/Color/CT_Color.h" +#include "DataTypes/Color/CT_ColorSpace.h" +#include "DataTypes/text/CT_Font.h" +#include "DataTypes/text/ct_text.h" +#include "DataTypes/text/textcode.h" +#include "DataTypes/basic_datatype.h" +#include "Tool/UnitTool.h" +#include "DataTypes/image/CT_Image.h" +#include "DataTypes/image/CT_MultiMedia.h" + +BuildTextTable::BuildTextTable() +{ + +} + +/// +/// \brief BuildTextTable::buildTable +/// \param table_block +/// \param layer +/// \param id_table +/// \param convertor +/// +void BuildTextTable::buildTable( + DocTable *table_block, CT_Layer *layer, ID_Table *id_table, Doc_OFDConvertor *convertor) +{ + this->table_block =table_block; + this->layer = layer; + this->id_table = id_table; + this->convertor = convertor; + + this->saveAsImage(); +} + +void BuildTextTable::saveAsImage() +{ + DocBlock *block = this->table_block->getBlock(); + + QString fileName; // 将要保存的图片的文件名 + QUuid uuid = QUuid::createUuid(); // 创建uuid + QString imageName = uuid.toString(); // 转换为字符串 + + // 去掉字符串的链接符号 {0142d46f-60b5-47cf-8310-50008cc7cb3a} + // 0142d46f60b547cf831050008cc7cb3a + imageName.remove(imageName.length()-1, 1); + imageName.remove(imageName.length() -13, 1); + imageName.remove(imageName.length() -17,1); + imageName.remove(imageName.length() -21, 1); + imageName.remove(imageName.length() - 25,1); + imageName.remove(0,1); + + fileName = imageName + ".jpg"; + + CT_Image *ctimage = new CT_Image(); + CT_MultiMedia *multiMedia = new CT_MultiMedia(); + + ctimage->setID(this->id_table->size() + 1 , this->id_table ); + multiMedia->setID(this->id_table->size() + 1, this->id_table ); + ctimage->setResourceID(multiMedia->getID().getID(), this->id_table); + + // 设置多媒体引用的标签 + multiMedia->Format = ""; + multiMedia->Type = "Image"; + multiMedia->MediaFile = fileName; + + QString filePath = convertor->passage->getTempSavePath() + + "/" + fileName; + + // 设置为背景透明 +// this->table_block->viewport()->setAttribute(Qt::WA_TranslucentBackground, false); +// QPixmap pixmap = QPixmap::grabWidget(this->table_block,0,0,block->size().width(),block->size().height()); +// pixmap.save(filePath,"JPEG",100); +// this->table_block->viewport()->setAttribute(Qt::WA_TranslucentBackground, true); + + QPixmap pixmap = QPixmap::grabWidget( + this->table_block->getPage(), + block->x(), + block->y(), + block->size().width()+4 , + block->size().height()+4); + + pixmap.save(filePath,"JPEG",100); + + ctimage->setBoundary( + UnitTool::pixelToMM(block->x()), + UnitTool::pixelToMM(block->y()), + UnitTool::pixelToMM(block->size().width()), + UnitTool::pixelToMM(block->size().height())); + + convertor->document_res->getMultiMedia()->push_back(multiMedia); + this->layer->image_object->push_back(ctimage); +} diff --git a/ofdEditor/model/Convert/BuildTextTable.h b/ofdEditor/model/Convert/BuildTextTable.h new file mode 100644 index 0000000000000000000000000000000000000000..89547a32f6a7117881fd577753546fd4e248384c --- /dev/null +++ b/ofdEditor/model/Convert/BuildTextTable.h @@ -0,0 +1,51 @@ +#ifndef BUILDTEXTTABLE_H +#define BUILDTEXTTABLE_H + +#include "Doc_OFDConvertor.h" +#include +#include "model_global.h" +#include + +class DocPassage; // 文章 +class DocPage; // 页 +class DocLayer; // 层 +class DocBlock; // 块 +class DocTextBlock; // 文本框 + +class OFD; // OFD文件模型 +class Res; // 资源描述 +class ID_Table; // id table表 +class CT_Font; // ct_font +class CT_ColorSpace; // 颜色空间 +class Page; +class Document; +class CT_Layer; +class DocImageBlock; +class DocTable; + + +/// +/// \brief The BuildTextTable class +/// 暂行方式,保存成图片 +/// + +class MODELSHARED_EXPORT BuildTextTable +{ +public: + BuildTextTable(); + + DocTable *table_block; + CT_Layer *layer; + ID_Table *id_table; + Doc_OFDConvertor *convertor; + + void buildTable( + DocTable *table_block, + CT_Layer *layer, + ID_Table *id_table, + Doc_OFDConvertor *convertor); + void saveAsImage(); + +}; + +#endif // BUILDTEXTTABLE_H diff --git a/ofdEditor/model/Convert/Doc_OFDConvertor.cpp b/ofdEditor/model/Convert/Doc_OFDConvertor.cpp index 0d46dc061a13f006b59ee864d8648b5d6e63dc9d..9c93cd028bc761b8bb81236cd501379c47984744 100644 --- a/ofdEditor/model/Convert/Doc_OFDConvertor.cpp +++ b/ofdEditor/model/Convert/Doc_OFDConvertor.cpp @@ -4,6 +4,9 @@ #include "Doc/DocBlock.h" #include "Doc/DocTextBlock.h" #include "Doc/DocLayer.h" +#include "Doc/DocImageBlock.h" +#include "Convert/BuildTextBlock.h" +#include "Convert/BuildTextTable.h" #include #include @@ -11,6 +14,7 @@ #include #include #include +#include #include "DataTypes/basic_datatype.h" #include "DataTypes/document/ofd.h" @@ -28,7 +32,9 @@ #include "DataTypes/text/ct_text.h" #include "DataTypes/text/textcode.h" #include "DataTypes/basic_datatype.h" - +#include "Tool/UnitTool.h" +#include "DataTypes/image/CT_Image.h" +#include "DataTypes/image/CT_MultiMedia.h" Doc_OFDConvertor::Doc_OFDConvertor(QObject *parent) : QObject(parent) @@ -52,7 +58,9 @@ OFD *Doc_OFDConvertor::doc_to_ofd(DocPassage *passage) this->buildDocBody(); // 构建DocBody this->buildDocument(); // docment + qDebug() << "doc to ofd finished"; + return this->ofdFile; } @@ -66,12 +74,15 @@ OFD *Doc_OFDConvertor::doc_to_ofd(DocPassage *passage) void Doc_OFDConvertor::buildDocBody() { qDebug() << "exec buildDocbody"; - QVector docbodys; // 新建docbodys新建带有……的docbodys + + // 新建DocBody DocBody* docbody = new DocBody(this->passage->getDocInfo()); // 加入docbody - docbodys.append(docbody); // 新建DocBody - docbody->setDocRoot(QString("Doc_0/Document.xml")); // 设置文档根目录 + docbody->setDocRoot("Doc_0/Document.xml"); // 设置文档根目录 + this->ofdFile->getDocBodies()->append(docbody); // 设置ofd的docbobys + this->ofdFile->setDocType(this->passage->getDocType()); // 文档类型 + this->ofdFile->setOfdVersion(this->passage->getVersion()); // 文档类型 - this->ofdFile->setDocBodies( &docbodys); // 设置ofd的docbobys + qDebug() << "build docbody finished"; } @@ -85,26 +96,39 @@ void Doc_OFDConvertor::buildDocBody() void Doc_OFDConvertor::buildDocument() { qDebug() << "exec buildDocument"; - QVector documents; // 新建Documents +// QVector *documents = new QVector(); // 新建Documents Document* document = new Document(); // 新建Document - documents.append(document); // 添加到文件中 +// documents->append(document); // 添加到文件中 // 设置ID_Table this->table = document->getIDTable(); // 获得IDTable - // 设置publicRes + // 设置publicRes\documentRes this->public_res = new Res(); - document->getPublicRes()->append(public_res); // 将公用资源加入到document - + this->public_res->setBaseLoc("Res"); + this->document_res = new Res(); + this->document_res->setBaseLoc("Res"); + document->getPublicRes()->append(this->public_res); // 将公用资源加入到document + document->document_res->append(this->document_res); // 设置common_data CT_CommonData * commonData = new CT_CommonData(); document->setCommonData(commonData); - // 设置指向资源文件的 - commonData->getPublicRes()->append(ST_Loc(QString("PublicRes.xml"), - QString("PublicRes.xml"), - QString("PublicRes.xml"))); + + // 设置指向资源文件的 + commonData->getPublicRes()->append(ST_Loc("PublicRes.xml", + "PublicRes.xml", + "PublicRes.xml")); + commonData->document_res->append(ST_Loc("DocumentRes.xml", + "DocumentRes.xml", + "DocumentRes.xml")); this->buildPages(document); // 解析每一页 + + // this->ofdFile->setDocument(documents); + commonData->setMaxUnitID(this->table->size()); // 设置最大单元 + this->ofdFile->getDocuments()->append(document); + + qDebug() << "build document finished"; } /** @@ -117,17 +141,18 @@ void Doc_OFDConvertor::buildDocument() void Doc_OFDConvertor::buildPages(Document* document) { qDebug() << "exec buildPages"; - QVector docPages = this->passage->getPages(); // 获得页面 - int pagesLength = docPages.size(); // 获得页面的数量 + QVector* docPages = this->passage->getPages(); // 获得页面 + int pagesLength = docPages->size(); // 获得页面的数量 - if(pagesLength > 1) + // 公共页大小,之后改成从DocPassage读取 + if(pagesLength >= 1) { // 设置公共页大小 CT_CommonData* commonData = document->getCommonData(); CT_PageArea *area = new CT_PageArea(); - DocPage* page = docPages[0]; + DocPage* page = docPages->operator [](0); area->setPhysicalBox(0,0, page->getWidth(),page->getHeight()); commonData->setPageArea(area); @@ -141,20 +166,22 @@ void Doc_OFDConvertor::buildPages(Document* document) // 遍历每个页面 for(int i=0; i< pagesLength;i++) { - DocPage* page = docPages.operator [](i); + DocPage* page = docPages->operator [](i); Page* ctPage = new Page(); ctPage->setID(this->table->size()+1,this->table); // 设置ID // 设置页的路径 - QString num; - num.setNum(i); - ctPage->setBaseLoc(QString("Pages/Page_") + num); + + ctPage->setBaseLoc(QString("Pages/Page_") + QString::number(i) + + "/Content.xml"); pages->append(ctPage); // 加入到OFD 文件中 this->buildPage(ctPage,page); // 单独处理每一页 } + qDebug() << "build Pages finished"; + } /** @@ -167,33 +194,50 @@ void Doc_OFDConvertor::buildPages(Document* document) */ void Doc_OFDConvertor::buildPage(Page *ctPage, DocPage *docPage) { - qDebug() << "exec buildPage"; + qDebug() << "exec buildPage:" << ctPage->getBaseLoc(); QVector *layers = ctPage->getContent(); + // pageArea + CT_PageArea *area = new CT_PageArea(); + area->setPhysicalBox(0,0, + docPage->getWidth(),docPage->getHeight()); + ctPage->setArea(area); + // 分成多个层,对每个层进行处理 DocLayer* foreground = docPage->getForegroundLayer(); // 获得前景层 - CT_Layer* foreLayer = new CT_Layer(); // 处理前景层 - foreLayer->setType("Foreground"); // 设置类型 - foreLayer->setID(this->table->size()+1,this->table); // 设置ID - layers->append(foreLayer); // 加入到Page中 - this->buildLayer(foreLayer,foreground); // 处理该层的信息 - + if(foreground->size() > 0) + { + CT_Layer* foreLayer = new CT_Layer(); // 处理前景层 + foreLayer->setType("Foreground"); // 设置类型 + foreLayer->setID(this->table->size()+1,this->table); // 设置ID + layers->append(foreLayer); // 加入到Page中 + this->buildLayer(foreLayer,foreground); // 处理该层的信息 + } // 处理正文层 DocLayer* body = docPage->getBodyLayer(); - CT_Layer* bodyLayer = new CT_Layer(); - bodyLayer->setType("Body"); - bodyLayer->setID(this->table->size()+1,this->table); - layers->append(bodyLayer); - this->buildLayer(bodyLayer,body); + if(body->size() > 0) + { + CT_Layer* bodyLayer = new CT_Layer(); + bodyLayer->setType("Body"); + bodyLayer->setID(this->table->size()+1,this->table); + layers->append(bodyLayer); + this->buildLayer(bodyLayer,body); + } + // 背景层 DocLayer* background = docPage->getBackgroundLayer(); - CT_Layer* backLayer = new CT_Layer(); - backLayer->setType("Background"); - backLayer->setID(this->table->size()+1,this->table); - layers->append(backLayer); - this->buildLayer(backLayer,background); + if(background->size() > 0) + { + CT_Layer* backLayer = new CT_Layer(); + backLayer->setType("Background"); + backLayer->setID(this->table->size()+1,this->table); + layers->append(backLayer); + this->buildLayer(backLayer,background); + } + + qDebug() << "build page Finished"; } @@ -207,7 +251,7 @@ void Doc_OFDConvertor::buildPage(Page *ctPage, DocPage *docPage) */ void Doc_OFDConvertor::buildLayer(CT_Layer* ctLayer,DocLayer *layer) { - qDebug() << "Exec buildLayer"; + qDebug() << "Exec buildLayer" << ctLayer->getType(); QVector *blocks = layer->getBlocks(); int blocks_length = blocks->size(); @@ -220,7 +264,33 @@ void Doc_OFDConvertor::buildLayer(CT_Layer* ctLayer,DocLayer *layer) if(block->isTextBlock()) { // 进入文字框处理模式 - this->buildText(ctLayer,block->getTextBlock()); +// this->buildText(ctLayer, block->getTextBlock()); +// this->buildTextBlock(ctLayer, block->getTextBlock()); + BuildTextBlock buildTextBlock; + buildTextBlock.buildText( + block->getTextBlock(), + ctLayer, + this->table, + this); + } + + // 如果是图片对象 + if(block->isImageBlock()) + { + // 将图片移动到资源文件夹,存下路径再结束 + this->buildImage(ctLayer, block->getImageBlock()); + } + + // 如果是表格 + if(block->isTableBlock()) + { + // 处理表格 + BuildTextTable buildTextTable; + buildTextTable.buildTable( + block->getTableBlock(), + ctLayer, + this->table, + this); } } @@ -246,42 +316,718 @@ void Doc_OFDConvertor::buildText(CT_Layer* ctLayer,DocTextBlock *textBlock) // 分析TextBlock textBlock->moveCursor(QTextCursor::Start); // 移动到块的开始 QTextCursor cursor = textBlock->textCursor(); - QTextDocument* document = cursor.document(); - int blockCount = document->blockCount(); // 获得Block的数量 - qDebug() << "This textBlock has " << blockCount << " QTextBlocks"; + QTextDocument* document = cursor.document(); // 获得文档 + + cursor.movePosition(QTextCursor::Start); // 移动到文章开头 - for(int i =0; iblockCount(); i++) { - // 遍历每一个QTextBlock - QTextBlock block = cursor.block(); - cursor.movePosition(QTextCursor::NextBlock, - QTextCursor::MoveAnchor); // 将鼠标移动到下一个块 - QTextCursor tempCursor = cursor; // 复制一个临时光标处理 - int lineCount = block.lineCount(); // 计算该块有多少行 - - qDebug() << "block " << i - << " has " << lineCount - << "lines"; - -// for(int lineValue = 0; lineValue = lineContent.length()) + { + // 当前行已完,但小块未完 + + // 删除重复的用来循环 + tempFragment.remove(0,lineContent.length()); + qDebug() << "use remaind lineContent: " << lineContent; + nextEditContent = lineContent; // 设置待处理字段 + lineContent.remove(0,lineContent.length()); // 清空 + } + + // 样式 + QTextCharFormat charFormat = fragment.charFormat(); // 字符格式 + QTextBlockFormat blockFormat = tempCursor.blockFormat();// 块格式 + QFont font = charFormat.font(); // 字体 + + + // 分析块的大小 + QFontMetricsF metrics(font); + + int pixelWidth = metrics.boundingRect(nextEditContent).width(); // 获得宽度 + int pixelHeight = metrics.boundingRect(nextEditContent).height(); // 获得高度 + + if(pixelContHeight < pixelHeight) + { + + // 如果小于最大行间距 + pixelLine = pixelLine + pixelHeight; // 纵向深度增加 + qDebug() << "pixelLine: "<< pixelLine + << " pixelHeight:" << pixelHeight; + } + + CT_Text* ct_text = new CT_Text(); // 新建文本块 + ct_text->setID(this->table->size() +1 ,this->table); // 设置ID + ctLayer->getTextObject()->append(ct_text); // 加入到layer + + // 设置颜色 + QBrush brush = charFormat.foreground(); // 获得画笔 + QColor color = brush.color(); // 获得颜色 + CT_ColorSpace *space = new CT_ColorSpace(); // 颜色空间 + space->setBitsPerComponent(8); + space->setType("RGB"); + int colorSpaceId = this->addColorSpace(space); + CT_Color* ct_color = new CT_Color(); + + ct_color->setValue(QString::number(color.red()) + " " + + QString::number(color.green()) + " " + + QString::number(color.blue())); + ct_color->setColorSpace(colorSpaceId,this->table); + + ct_text->setFillColor(ct_color); + + + // 加入字体 + CT_Font* ctfont = new CT_Font(); + ctfont->setFamilyName(font.family()); + ctfont->setFontName(font.family()); + int font_id = this->addFont(ctfont); // 添加字体ID + ct_text->setFont(font_id, this->table); // 设置字体引用 + + // 设置字体 + if(font.italic()) + { + // 如果斜体 + ct_text->setItalic( true); + } + if(font.weight() != 50) + { + // 字重 + ct_text->setWeight(font.weight() * 8); // 默认值400 + } + + // 设置字体大小 + // 这个只针对/通过 setPixelSize的才有效 +// double font_size = font.pixelSize(); // 获得字大小 +// qDebug() << "Font Size:" <setSize(UnitTool::pixelToMM(font_size)); +// int fontPixelSize = metrics.height(); // 获得像素高度 + ct_text->setSize(UnitTool::pixelToMM(pixelHeight)); + + qDebug() << "before setBoundary pixelLine: "<< pixelLine; + + // 边框 + ct_text->setBoundary(UnitTool::pixelToMM(textBlock->pos().rx() + + pixelContent), // 最左侧,向右偏移一定距离 + UnitTool::pixelToMM(textBlock->pos().ry() + + pixelLine), + UnitTool::pixelToMM(pixelWidth), + UnitTool::pixelToMM(pixelLine) + 5 + ); + + qDebug() << "After setBoundary pixelLine: "<< pixelLine; + + // 设置delta_x + TextCode* textCode = new TextCode(); // 文字内容 + textCode->setText(nextEditContent); // 设置文字内容 + textCode->setX(0); // 设置起始位置 + textCode->setY(UnitTool::pixelToMM(metrics.height())); + + if(nextEditContent.length()>1) + { + qDebug() << "font's wordSpacing:" << font.wordSpacing(); + QString delta_x_str; + // n个字符 n-1 个 delta_x + for(int delta_x = 0; delta_x < nextEditContent.length()-1; delta_x++) + { + + delta_x_str = delta_x_str + " " + + QString::number( + UnitTool::pixelToMM( + metrics.boundingRect( + nextEditContent.mid(delta_x,1)).width())); + } + textCode->setDeltaX(delta_x_str); + } + + ct_text->getTextCode()->append(textCode); // 加入到textCode中 + + pixelContent += pixelWidth; // 将当前使用长度加入,进入下一次循环 + } + + cursor.movePosition(QTextCursor::NextBlock); // + } + //// 将文本框按照 格式和行进行拆分 + +} + +/// +/// \brief Doc_OFDConvertor::buildTextBlock +/// \param CT_Layer +/// \param textBlock +/// 处理 DocTextBlock 实际相当于计算 QTextEdit中的文本的位置大小 +/// +void Doc_OFDConvertor::buildTextBlock(CT_Layer *CT_Layer, DocTextBlock *textBlock) +{ + DocBlock *block = textBlock->getBlock(); // 获得Block可以获得文本块的总大小 + double block_pos_x = block->x(); + double block_pos_y = block->y(); + double block_width = block->size().width(); + double block_height = block->size().height(); + + qDebug() << "block boundary" + << block_pos_x << block_pos_y << block_width << block_height; + + int lineCount = 0; // 用来计算共有多少行 + textBlock->moveCursor(QTextCursor::Start); // 将鼠标移动到文档开始 + QTextCursor cursor = textBlock->textCursor(); // 光标 + + // 计算每行的文字的最大高度 + QVector lineHeight_Font; // 每个字体的实际高度 + QVector lineHeight_Real; // 经过段落格式后的高度 + + QVector end_of_line_pos; // 纪录每一行结尾的地方 + QVector start_of_line_Pos; // 记录每行开始的位置 + QVector start_of_fragment; // 每一个QTextFragment开始的位置 + + // 一行一行的进行遍历-记录每行的开始位置和行数 + while(!cursor.atEnd()) + { + lineCount ++; + cursor.movePosition(QTextCursor::StartOfLine); // 移动到每行开始的位置 + start_of_line_Pos.push_back(cursor.position()); + + cursor.movePosition(QTextCursor::EndOfLine); // 移动到当前行尾,纪录位置 + end_of_line_pos.push_back(cursor.position()); // 将该行的结尾位置发出来 + + cursor.movePosition(QTextCursor::Right); + + // 先用每块的字体初始化一下 lineHeight_Font + QTextCharFormat charFormat = cursor.charFormat(); + QFontMetrics fontMetrics(charFormat.font()); + + lineHeight_Font.push_back( + fontMetrics.ascent() + + fontMetrics.descent() + + fontMetrics.leading() + 1); } + // 计算每行的行高---------------------------------------------- + QTextFrame::iterator it = textBlock->document()->rootFrame()->begin(); // 遍历rootFrame + while (!it.atEnd()) + { + // QTextBlock + QTextBlock block = it.currentBlock(); // 当前block + qDebug() << "block "<< block.text(); + + QTextBlock::iterator block_it = block.begin(); + while(!block_it.atEnd()) + { + // 遍历QTextFragment + QTextFragment fragment = block_it.fragment(); + start_of_fragment.push_back(fragment.position()); + + // 判断 fragment 影响哪几行的高度 + int lineHeight_fragment = 0; + QFontMetricsF fontMetrics(fragment.charFormat().font()); + lineHeight_fragment = fontMetrics.ascent() + fontMetrics.descent() + fontMetrics.leading() + 1; + + // 利用快的起点和重点,判断影响了哪几行 + int start_pos = fragment.position(); + int end_pos = fragment.position() + fragment.length(); + int start_line = 0; + int end_line = 0; + for(int line = 0; line < end_of_line_pos.size(); line ++) + { + if(start_pos > end_of_line_pos[line]) + { + start_line = line + 1; + } + if(end_pos < end_of_line_pos[line]) + { + end_line = line; + break; + } + } + qDebug() << "fragment pos"< lineHeight_Font[line]) + { + lineHeight_Font[line] = lineHeight_fragment; + } + } + + block_it ++; + } // 遍历fragment + it ++; + } // 遍历block + + // 结合行高策略,计算每行的行高--------------------------------------------- + lineHeight_Real = lineHeight_Font; // 复制内容 + + // 遍历每行,根据行高规则计算行高 + for(int line = 0 ; line < end_of_line_pos.size(); line ++) + { + cursor.setPosition(end_of_line_pos[line]); + QTextBlockFormat blockFormat = cursor.blockFormat(); + + int lineHeightType = blockFormat.lineHeightType(); + int lineHeightValue = blockFormat.lineHeight(); + + switch (lineHeightType) + { + case QTextBlockFormat::SingleHeight: + // 单倍行距不用改 + break; + case QTextBlockFormat::MinimumHeight: + // 最小值 + if(lineHeight_Font[line] < lineHeightValue) + { + lineHeight_Real[line] = lineHeightValue; + } + else + { + lineHeight_Real[line] = lineHeight_Font[line]; + } + break; + case QTextBlockFormat::FixedHeight: + // 固定值 + lineHeight_Real[line] = lineHeightValue; + break; + case QTextBlockFormat::ProportionalHeight: + // 多倍行距 + lineHeight_Real[line] = (int)(1.0 * lineHeightValue / 100 * lineHeight_Font[line]); + break; + default: + break; + } + } + + qDebug() << "lineCount" << lineCount << endl + << "end of line" << end_of_line_pos << endl + << " start of fragements" << start_of_fragment << endl + << "line height font" << lineHeight_Font << endl + << "line height real" << lineHeight_Real << endl; + + // 处理----------------------------------------------------------------------------------- + + double current_height = 0; // 当前左上角的位置 + int current_line = -1; // 用来标记当前处理到了第几行 + QTextFrame::iterator it_block = textBlock->document()->rootFrame()->begin(); // 遍历block + while(!it_block.atEnd()) + { + QTextBlock block = it_block.currentBlock(); // 遍历block + QTextBlockFormat blockFormat = block.blockFormat(); // 当前的blockFormat + + // 处理段前段后的问题 + if(block != textBlock->document()->firstBlock()) + { + // 如果不是第一个块,要加上上一个块的段前和这一个段的段后 + double last_bottom_margin = block.previous().blockFormat().bottomMargin()+0.5; + double this_top_margin = block.blockFormat().topMargin()+0.5; + current_height = current_height + last_bottom_margin + this_top_margin; + } + + if(block.text().size() ==0) + { + // 因为如果是空行的话,则没有QTextFragment + current_height = current_height + lineHeight_Real[current_line]; + current_line ++; // 行数 +1 + it_block ++; // 进入下一个块 + continue; + } + + // 计算每行的文本宽度 然后根据对齐的规则,可以获得每个字符的额外间距 + //-------------------------------------------------------- + QVector block_line_content_width; // 每行的不计算布局的纯文本的宽度 + QVectorblock_line_content_count; // 每行的文字的数量 + { + QString lineContent; // 行内容 + QString lineContent_backup; // 行内容备份 + QString tempFragment; + QTextFragment fragment; + QTextCursor tempCursor = textBlock->textCursor(); + + QTextBlock::iterator iter = block.begin(); + + while(!iter.atEnd() + || lineContent.size() != 0 + || tempFragment.size() != 0) + { + if(tempFragment.size() == 0 && !iter.atEnd()) + { + // 如果处理字段为空了 + fragment = iter.fragment(); // 获得新的字段 + tempFragment = fragment.text(); // 留存内容 + iter ++; + } + else if(tempFragment.size() == 0 && iter.atEnd()) + { + break; + } + + if(lineContent.size() == 0) + { + // 如果当前行处理完了 + tempCursor.select(QTextCursor::LineUnderCursor); // 选择当前行 + lineContent = tempCursor.selectedText(); + lineContent_backup = lineContent; + + block_line_content_width.push_back(0); + block_line_content_count.push_back(lineContent.size()); + + } + + QString nextEditContent; // 即将处理的字段 + + // 处理当前fragment + if(tempFragment.size() < lineContent.size()) + { + // 当前小块的长度没有达到行的长度 + lineContent.remove(0, tempFragment.length()); + qDebug() << " tempFragment "<< tempFragment ; + + nextEditContent = tempFragment; + tempFragment.remove(0,tempFragment.size()); + + } + else if(tempFragment.size() >= lineContent.size()) + { + // 当前块跨越了好几行 + tempFragment.remove(0,lineContent.size()); + qDebug() << "use remaind lineContent: "<< lineContent; + + nextEditContent = lineContent; + lineContent.remove(0,lineContent.size()); + + } + + QFontMetricsF fontMetrics(fragment.charFormat().font()); + double width = fontMetrics.boundingRect(nextEditContent).width(); + block_line_content_width[block_line_content_width.size() - 1 ] = + block_line_content_width[block_line_content_width.size() - 1 ] + width; + + } + + } + + qDebug() << "blockLine Width" << block_line_content_width; + QVector block_line_space = block_line_content_width; // 每行空白的位置 + QVector block_line_word_space = block_line_content_width; // 每行中空白位置除以每行中每个字的位置 + + for(int i = 0; i < block_line_space.size(); i++) + { + block_line_space[i] = block_width - block_line_content_width[i]; + block_line_word_space[i] = (block_width - block_line_content_width[i]) / (block_line_content_count[i] - 1); + } + + // 处理一般化的块的问题 + double block_indent = blockFormat.indent() * textBlock->document()->indentWidth(); // 整体缩进 + + // 解析文本内容 + //-------------------------------------------------------- + { + QString lineContent; // 行内容 + QString lineContent_backup; // 行内容备份 + int blockLineCount = -1; + QString tempFragment; + QTextFragment fragment; + QTextCursor tempCursor = textBlock->textCursor(); + QTextBlock::iterator iter = block.begin(); + bool blockFirstLine = true; + double current_x = 0; // 填充字符的x值 + current_x = blockFormat.textIndent(); // 初始化为首行缩进 + + while(!iter.atEnd() + || lineContent.size() != 0 + || tempFragment.size() != 0) + { + if(tempFragment.size() == 0 && !iter.atEnd()) + { + // 如果处理字段为空了 + fragment = iter.fragment(); // 获得新的字段 + tempFragment = fragment.text(); // 留存内容 + iter ++; + } + else if(tempFragment.size() == 0 && iter.atEnd()) + break; + + if(lineContent.size() == 0) + { + // 如果当前行处理完了 + tempCursor.select(QTextCursor::LineUnderCursor); // 选择当前行 + lineContent = tempCursor.selectedText(); + lineContent_backup = lineContent; + block_line_content_width.push_back(0); + + // 每到新的一行,设置开始文字位置 + switch(blockFormat.alignment()) + { + case Qt::AlignLeft: + current_x = block_indent; + break; + case Qt::AlignRight: + current_x = block_indent + block_line_space[blockLineCount]; + break; + case Qt::AlignHCenter: + current_x = block_indent + block_line_space[blockLineCount] / 2 ; + break; + case Qt::AlignJustify: + current_x = block_indent; + break; + } + + if(blockFirstLine) // 如果是本段落的第一行 + { + blockFirstLine = false; + current_x += blockFormat.textIndent(); + blockLineCount = 0; + } + if(current_line != 0) + { + current_height += lineHeight_Real[current_line -1]; + } + current_x = block_indent; + current_line ++; + blockLineCount ++; + } + + QString nextEditContent; // 即将处理的字段 + + // 处理当前fragment + if(tempFragment.size() < lineContent.size()) + { + // 当前小块的长度没有达到行的长度 + lineContent.remove(0, tempFragment.length()); + nextEditContent = tempFragment; + tempFragment.remove(0,tempFragment.size()); + + } + else if(tempFragment.size() >= lineContent.size()) + { + // 当前块跨越了好几行 + tempFragment.remove(0,lineContent.size()); + nextEditContent = lineContent; + lineContent.remove(0,lineContent.size()); + + } + + // 样式 + QTextCharFormat charFormat = fragment.charFormat(); // 字符格式 + QTextBlockFormat blockFormat = tempCursor.blockFormat();// 块格式 + QFont font = charFormat.font(); // 字体 + QFontMetrics fontMetics(font); + + // 新建 CT_Text + CT_Text* ct_text = new CT_Text(); // 新建文本块 + ct_text->setID(this->table->size() +1 ,this->table); // 设置ID + CT_Layer->getTextObject()->append(ct_text); // 加入到layer + + // 设置颜色 + QBrush brush = charFormat.foreground(); // 获得画笔 + QColor color = brush.color(); // 获得颜色 + CT_ColorSpace *space = new CT_ColorSpace(); // 颜色空间 + space->setBitsPerComponent(8); + space->setType("RGB"); + int colorSpaceId = this->addColorSpace(space); + CT_Color* ct_color = new CT_Color(); + + ct_color->setValue(QString::number(color.red()) + " " + + QString::number(color.green()) + " " + + QString::number(color.blue())); + ct_color->setColorSpace(colorSpaceId,this->table); + + ct_text->setFillColor(ct_color); + + + // 加入字体 + CT_Font* ctfont = new CT_Font(); + ctfont->setFamilyName(font.family()); + ctfont->setFontName(font.family()); + int font_id = this->addFont(ctfont); // 添加字体ID + ct_text->setFont(font_id, this->table); // 设置字体引用 + + // 设置字体 + if(font.italic()) + { + // 如果斜体 + ct_text->setItalic(true); + } + if(font.weight() != 50) + { + // 字重 + ct_text->setWeight(font.weight() * 8); // 默认值400 + } + + ct_text->setSize( + UnitTool::pixelToMM( + fontMetics.height())); // 设置字体大小 + + ct_text->setBoundary( + UnitTool::pixelToMM(block_pos_x + current_x), + UnitTool::pixelToMM(block_pos_y + current_height), + UnitTool::pixelToMM(block_width), + UnitTool::pixelToMM(lineHeight_Real[lineCount])); + + // 设置delta_x + TextCode* textCode = new TextCode(); // 文字内容 + textCode->setText(nextEditContent); // 设置文字内容 + textCode->setX(0); // 设置起始位置 + textCode->setY(UnitTool::pixelToMM(lineHeight_Font[lineCount])); + + if(nextEditContent.length()>1) + { + QString delta_x_str; + // n个字符 n-1 个 delta_x + for(int delta_x = 0; delta_x < nextEditContent.length()-1; delta_x++) + { + + if(blockFormat.alignment() == Qt::AlignJustify) + { + delta_x_str = delta_x_str + " " + + QString::number( + UnitTool::pixelToMM( + fontMetics.boundingRect( + nextEditContent.mid(delta_x,1)).width() + + block_line_word_space[blockLineCount])); + } + else + { + delta_x_str = delta_x_str + " " + + QString::number( + UnitTool::pixelToMM( + fontMetics.boundingRect( + nextEditContent.mid(delta_x,1)).width())); + } + + } + textCode->setDeltaX(delta_x_str); + } + + ct_text->getTextCode()->append(textCode); // 加入到textCode中 + + + } + + } + + it_block ++; + } + + + +} + +/// +/// \brief Doc_OFDConvertor::buildQTextBlock +/// \param ctlayer +/// \param textBlock +/// \param pos_x +/// \param pos_y +/// \param width +/// \param height +/// 使用提供的大小做为QTextBlock的大小进行处理文本 +/// +void Doc_OFDConvertor::buildQTextBlock( + CT_Layer *ctlayer, + QTextBlock *textBlock, + double pos_x, + double pos_y, + double width, + double height) +{ } +/// +/// \brief Doc_OFDConvertor::buildImage +/// \param ctLayer +/// \param imageBlock +/// +void Doc_OFDConvertor::buildImage(CT_Layer *ctLayer, DocImageBlock *imageBlock) +{ + // 新建所需的对象,设置ID + CT_Image *ctimage = new CT_Image(); // iamgeobject + CT_MultiMedia *multiMedia = new CT_MultiMedia(); // 多媒体 + ctimage->setID(this->table->size() + 1, + this->table); + multiMedia->setID(this->table->size() + 1, + this->table); + ctimage->setResourceID(multiMedia->getID().getID(), this->table); + + // 设置多媒体引用的标签 + multiMedia->Format = ""; + multiMedia->Type = "Image"; + multiMedia->MediaFile = imageBlock->getFileName(); + + // 将图片存储到临时文件夹去 + QString fileName = this->passage->getTempSavePath() + + "/" + multiMedia->MediaFile; + imageBlock->saveImage(fileName); + + DocBlock* block = imageBlock->getBlock(); + + // 设置边界 + ctimage->setBoundary( + UnitTool::pixelToMM(block->x()), + UnitTool::pixelToMM(block->y()), + UnitTool::pixelToMM(block->size().width()), + UnitTool::pixelToMM(block->size().height())); + + + this->document_res->getMultiMedia()->push_back(multiMedia); // 追加到资源文件内 + ctLayer->image_object->push_back(ctimage); +} + /** * @Author Chaoqun * @brief 加入字体 @@ -377,3 +1123,4 @@ int Doc_OFDConvertor::checkColorSpace(CT_ColorSpace *colorSpace) return -1; // 不存在已有的 } + diff --git a/ofdEditor/model/Convert/Doc_OFDConvertor.h b/ofdEditor/model/Convert/Doc_OFDConvertor.h index ccf6da4e5206ca1d23a4ffc9fe90889bfd315f93..f07e22530b7068f59a7c1a08ae348d11756484ee 100644 --- a/ofdEditor/model/Convert/Doc_OFDConvertor.h +++ b/ofdEditor/model/Convert/Doc_OFDConvertor.h @@ -3,6 +3,7 @@ #include #include "model_global.h" +#include class DocPassage; // 文章 class DocPage; // 页 @@ -18,6 +19,7 @@ class CT_ColorSpace; // 颜色空间 class Page; class Document; class CT_Layer; +class DocImageBlock; /** @@ -28,11 +30,19 @@ class CT_Layer; class MODELSHARED_EXPORT Doc_OFDConvertor : public QObject { + + Q_OBJECT public: explicit Doc_OFDConvertor(QObject *parent = 0); OFD *doc_to_ofd(DocPassage* passage); // 执行程序入口 + + int addFont(CT_Font* font); // 添加字体类型到资源 + int addColorSpace(CT_ColorSpace* colorSpace); // 添加颜色空间 + + + signals: public slots: @@ -41,25 +51,36 @@ private: void buildDocBody(); // 生成DocBody void buildDocument(); // 生成Document - void buildPages(Document *document); // 处理页面S + void buildPages(Document *document); // 处理页面S void buildPage(Page* ctPage, - DocPage* docPage); // 处理其中某一页 + DocPage* docPage); // 处理其中某一页 void buildLayer(CT_Layer* ctLayer, - DocLayer* layer); // 将一层中的信息存储出来 - void buildText(CT_Layer* ctLayer,DocTextBlock* textBlock); // 将DocTextBlock中的信息转换处理 + DocLayer* layer); // 将一层中的信息存储出来 + void buildText(CT_Layer* ctLayer, DocTextBlock* textBlock); // 将DocTextBlock中的信息转换处理 + void buildTextBlock(CT_Layer *CT_Layer, DocTextBlock *textBlock); // 处理文本块,方案二 + void buildQTextBlock( + CT_Layer *ctlayer, + QTextBlock *textBlock, + double pos_x, + double pos_y, + double width, + double height); // 处理一个 QTextBlock + void buildImage(CT_Layer* ctLayer, DocImageBlock *imageBlock); // 处理图片 + + - int addFont(CT_Font* font); // 添加字体类型到资源 - int addColorSpace(CT_ColorSpace* colorSpace); // 添加颜色空间 int checkFont(CT_Font* font); // 检查publicRes中是否存在该字体 int checkColorSpace(CT_ColorSpace* colorSpace); // 检查是否存在该颜色空间 -private: + +public: DocPassage* passage; // 文章 OFD* ofdFile; // OFD 对象 Res* public_res; // Res 公共资源文件 + Res* document_res; // 放图片等多媒体资源的res ID_Table* table; // ID table diff --git a/ofdEditor/model/Convert/OFD_DocConvertor.cpp b/ofdEditor/model/Convert/OFD_DocConvertor.cpp index 1b75e1065605a381ffe0223cdf6594f4ee5c4657..9aaf703a0643e88a17678a4c4fa22a072227a19f 100644 --- a/ofdEditor/model/Convert/OFD_DocConvertor.cpp +++ b/ofdEditor/model/Convert/OFD_DocConvertor.cpp @@ -10,6 +10,7 @@ #include "DataTypes/page/page.h" #include "Doc/DocTextBlock.h" #include "Doc/DocBlock.h" +#include "Doc/DocImageBlock.h" #include "Tool/UnitTool.h" #include "DataTypes/text/TextCode.h" #include "DataTypes/text/CT_Text.h" @@ -18,6 +19,8 @@ #include "Convert/Objects/MinTextUnit.h" #include "DataTypes/page/CT_PageArea.h" #include "DataTypes/document/ct_commondata.h" +#include "DataTypes/image/CT_Image.h" +#include "DataTypes/image/CT_MultiMedia.h" OFD_DocConvertor::OFD_DocConvertor() { @@ -61,6 +64,7 @@ DocPassage *OFD_DocConvertor::ofd_to_doc(OFD *ofd) { // 生成每一页 + qDebug() << "build Page" << i; DocPage * newPage = this->buildDocPage(passage, (*pages)[i]); newPage->setVisible(true); } @@ -101,15 +105,16 @@ DocPage *OFD_DocConvertor::buildDocPage(DocPassage *passage, Page *ct_page) page = new DocPage(); } - passage->addPage(page); // 加入到文章中来 page->setVisible(false); // 先隐藏显示 + passage->addPage(page); // 加入到文章中来 + // 将每一层加入到页中 QVector* layers = ct_page->getContent(); // 获得文章中的层信息 for(int i = 0; i < layers->size(); i++) { CT_Layer* layer = (*layers)[i]; -// qDebug() << "excute insertLayer: " << i; + qDebug() << "excute insertLayer: " << i; this->insertLayer(page,layer); // 将该层的内容加入到页面中 } @@ -187,6 +192,14 @@ void OFD_DocConvertor::insertPageBlock(DocPage *page, // 处理 CT_Path // 处理 CT_Image + QVector *images = pageBlock->getImageObject(); + for(int i = 0; i < images->size(); i++) + { + this->insertCT_Image( + page, + doctype, + images->operator [](i)); + } } @@ -225,14 +238,14 @@ void OFD_DocConvertor::insertCT_Text(DocPage *page, DocPage::Layer layer, CT_Tex // 处理每一个textCode QVector* textCodes = text->getTextCode(); // 获得文字内容 int length = textCodes->size(); // 数量 -// qDebug() << "textCodes' length:" << length; + qDebug() << "textCodes' length:" << length; for(int i = 0 ; i< length; i++) { TextCode* textCode = (*textCodes)[i]; // 当前处理的块 // qDebug() << "deal with current textcode:" << i; // 求出单个块的保卫面积 - double height = text->getSize(); // 高等于字体的高 + double height = text->getSize() + 5; // 高等于字体的高 double width = 0; // 所有deltax相加再加上一个字宽 double x = text->boundary.getX() + textCode->getX(); // 左上角 x坐标 double y = text->boundary.getY() + textCode->getY() - height; // 左上角y值 @@ -247,7 +260,7 @@ void OFD_DocConvertor::insertCT_Text(DocPage *page, DocPage::Layer layer, CT_Tex width += arrayDeltaX[j].toDouble(); // 计算宽度 } - width += height; // 假设为方块字吧 + width += height + 15; // 假设为方块字吧 // qDebug() << "has compute the boundary"; @@ -288,6 +301,17 @@ void OFD_DocConvertor::insertCT_Text(DocPage *page, DocPage::Layer layer, CT_Tex font.setPixelSize(UnitTool::mmToPixel(text->getSize())); // 字号 font.setFamily(textFont.family()); // 设置字体 + qDebug() << "italic ------------------------------------" << text->getItalic(); + // 倾斜 + if(text->getItalic()) + { + font.setItalic(true); + } + + // 加粗 + int weight = text->getWeight(); // 获得粗细 + font.setWeight(this->getWeight(weight)); + // 上下间距 blockFormat.setTopMargin(0); blockFormat.setBottomMargin(0); @@ -315,9 +339,41 @@ void OFD_DocConvertor::insertCT_Path(DocPage *page, CT_Layer *layer, CT_Path *pa } -void OFD_DocConvertor::insertCT_Image(DocPage *page, DocPage::Layer layer, CT_Image *image) +/// +/// \brief OFD_DocConvertor::insertCT_Image +/// \param page +/// \param layer +/// \param image +/// +void OFD_DocConvertor::insertCT_Image( + DocPage *page, + DocPage::Layer layer, + CT_Image *image) { + DocImageBlock *imageBlock = new DocImageBlock(); + // 获得多媒体资源 + CT_Base* base_media = + this->ofdFile->getDocuments()->operator [](0) + ->getIDTable()->getItem( + image->getResourceID()); + CT_MultiMedia* multMedia = (CT_MultiMedia *)base_media; + + qDebug() << multMedia->MediaFile; + imageBlock->setImage(multMedia->MediaFile); // 设置图片 + imageBlock->setWidthHeightRatioLocked(false); // 先不要锁定纵横比 + DocBlock * block = new DocBlock(); + + block->setWidget(imageBlock); + ST_Box box = image->boundary; // 获得位置大小 + block->resize( + UnitTool::mmToPixel(box.getDeltaX()), + UnitTool::mmToPixel(box.getDeltaY())); + block->setPos( + UnitTool::mmToPixel(box.getX()), + UnitTool::mmToPixel(box.getY())); + + page->addBlock(block, layer); // 加入到页面中 } /** @@ -331,6 +387,8 @@ QColor OFD_DocConvertor::ctColorToQColor(CT_Color *ct_color) { QColor defaultColor(Qt::black); // 设置默认颜色 + if(ct_color == NULL) + return defaultColor; Document* document = (*this->ofdFile->getDocuments())[0]; ID_Table* table = document->getIDTable(); @@ -404,3 +462,11 @@ QColor OFD_DocConvertor::ctColorToQColor(CT_Color *ct_color) } } + +int OFD_DocConvertor::getWeight(int weight) +{ + if(weight < 500) + return 50; + else + return 75; +} diff --git a/ofdEditor/model/Convert/OFD_DocConvertor.h b/ofdEditor/model/Convert/OFD_DocConvertor.h index f330308ba3370b3d947b157bec5534ce15d31df1..2ad1139d04980a1a18b0ae000f4a8debafc5da68 100644 --- a/ofdEditor/model/Convert/OFD_DocConvertor.h +++ b/ofdEditor/model/Convert/OFD_DocConvertor.h @@ -60,6 +60,8 @@ private: QColor ctColorToQColor(CT_Color* ct_color); // 颜色转换 + int getWeight(int weight); // ofd的weight 转化 QText的weight + }; #endif // OFD_DOCCONVERTOR_H diff --git a/ofdEditor/model/Core/GlobalSetting.cpp b/ofdEditor/model/Core/GlobalSetting.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12d3889da5dccb0577380dce5377e877a823cdc6 --- /dev/null +++ b/ofdEditor/model/Core/GlobalSetting.cpp @@ -0,0 +1,519 @@ +#include "GlobalSetting.h" + +#include +#include +#include +#include + +#include "json/json.h" +#include "json/json-forwards.h" +#include "jsoncpp.cpp" + +using std::string; +using Json::Reader; +using Json::Value; + +// 初始化静态成员变量 +GlobalSetting* GlobalSetting::m_instance = NULL; + +GlobalSetting::GlobalSetting(QObject *parent) + : QObject(parent) +{ + this->settingChanged = false; + this->filepath = "config.json"; + loadGlobalSetting(this->filepath); + +} + +/// +/// \brief GlobalSetting::loadGlobalSetting +/// 从给定的文件路径中读取系统的全局参数 +/// \param filePath 完整路径,以'/' 为分隔符 +/// \author chaoqun +/// \date 2017/08/04 +/// +void GlobalSetting::loadGlobalSetting(QString filePath) +{ + QFile qfile; + qfile.setFileName(filePath); // 设置文件路径 + + // 如果文件不存在,或者无法打开,使用默认配置 + if(!qfile.exists()) + { + qDebug() << "This global setting file is not exists," + << " program will use default setting"; + + this->setDefaultSetting(); // 使用默认配置 + this->SaveSetting(); // 保存配置 + return; + } + // 打开文件 + if(!qfile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qDebug() << "Program could not open this global setting file," + << " we will use default setting"; + + this->setDefaultSetting(); + this->SaveSetting(); // 保存配置 + return; + } + + QTextStream txtInput(&qfile); // 设置文件流 + QString qstr = txtInput.readAll(); // 读取文件的全部内容 + string str = qstr.toStdString(); // 读取出标准字符 + + Reader reader; // 解析器 + Value value; // 值 + + if(reader.parse(str,value)) + { + try + { + // 如果json 解析成功 + Value app = value["App"]; // App相关 + Value font = value["Font"]; // 字体相关 + Value page = value["Page"]; // 页面设置相关 + Value paragraph = value["Paragraph"]; // 段落设置相关 + + // App + string str_creator = app["Creator"].asString(); // 编辑器 + string str_creatorVersion = app["CreatorVersion"].asString(); // 软件版本 + string str_docType = app["DocType"].asString(); // 文档标准 + string str_docVersion = app["DocVersion"].asString(); // 文档标准版本 + string str_viewMode = app["ViewMode"].asString(); // 系统开启时默认的视图 + + this->creator= QString::fromStdString(str_creator); + this->creatorVersion = QString::fromStdString(str_creatorVersion); + this->docType = QString::fromStdString(str_docType); + this->docVersion = QString::fromStdString(str_docVersion); + this->viewMode = QString::fromStdString(str_viewMode); + this->undoSize = app["UndoSize"].asInt(); // 读取撤销恢复的最大数量 + + // Font + string str_fontFamily = font["FontFamily"].asString(); // 字体类型 + double double_fontSize = font["FontSize"].asDouble(); // 字号 + + this->fontFamily = QString::fromStdString(str_fontFamily); + this->fontSize = double_fontSize; + + // 页面设置相关 + double double_width = page["Width"].asDouble(); // 页面物理宽度 + double double_height = page["Height"].asDouble(); // 页面的物理高度 + double double_workWidth = page["WorkWidth"].asDouble(); // 页面的工作区宽度 + double double_workHeight = page["WorkHeight"].asDouble(); // 页面的工作区高度 + double double_workX = page["WorkX"].asDouble(); // x + double double_workY = page["WorkY"].asDouble(); // y + string str_pageType = page["PageType"].asString(); // 页面类型 + + this->physicalWidth = double_width; + this->physicalHeight = double_height; + this->contentWidth = double_workWidth; + this->contentHeight = double_workHeight; + this->contentX = double_workX; + this->contentY = double_workY; + this->pageType = QString::fromStdString(str_pageType); + + //段落相关 + string str_horizontal = paragraph["Horizontal"].asString(); // 水平对齐模式 + double double_paraIndent = paragraph["ParaIndent"].asDouble(); // 段落默认缩进 + double double_firstIndent = paragraph["FirstIndent"].asDouble(); // 段落首行缩进 + double double_spaceBefore = paragraph["SpaceBefore"].asDouble(); // 段前间距 + double double_spaceAfter = paragraph["SpaceAfter"].asDouble(); // 段后间距 + string str_lineHeight = paragraph["LineHeight"].asString(); // 行高类型 + double double_lineHeightValue = paragraph["LineHeightValue"].asDouble(); // 行高值 + + this->horizontal = QString::fromStdString(str_horizontal); + this->paraIndent = double_paraIndent; + this->firstIndent = double_firstIndent; + this->spaceBefore = double_spaceBefore; + this->spaceAfter = double_spaceAfter; + this->lineHeight = QString::fromStdString(str_lineHeight); + this->lineHeightValue = double_lineHeightValue; + + qDebug() << "The global setting file is explained successfully."; + + } + catch(...) + { + // 如果有抛出异常 + qDebug() << "Program explan this global setting file failed," + << "and program throws an exception," + << "we will use default setting."; + this->setDefaultSetting(); + this->SaveSetting(); // 保存配置 + } + + } + else + { + // 如果json解析失败 + qDebug() << "Program explan this global setting file failed," + << "we will use default setting."; + this->setDefaultSetting(); + this->SaveSetting(); // 保存配置 + } + + qfile.close(); // 关闭文件 +} + +/// +/// \brief GlobalSetting::exportGlobalSetting +/// 将当前系统的全局设置保存到指定文件 +/// \param filePath +/// \author chaoqun +/// \date 2017/08/04 +/// +void GlobalSetting::exportGlobalSetting(QString filePath) +{ + QFile qfile; + qfile.setFileName(filePath); + + if(!qfile.open(QIODevice::ReadWrite + | QIODevice::Text + | QIODevice::Truncate)) + { + qDebug() << "Program could not creat the global setting file"; + return; + } + + QTextStream txtOutput(&qfile); // 用来作为输出流 +// Json::StyledWriter swriter; // 用来将value转换为 string + + Value root; + Value app; // 应用程序 + Value font; // 字体 + Value page; // 页面 + Value paragraph; // 段落 + + // App + app["Creator"] = this->creator.toStdString(); + app["CreatorVersion"] = this->creatorVersion.toStdString(); + app["DocType"] = this->docType.toStdString(); + app["DocVersion"] = this->docVersion.toStdString(); + app["ViewMode"] = this->viewMode.toStdString(); + app["UndoSize"] = this->undoSize; + + // Font + font["FontFamily"] = this->fontFamily.toStdString(); + font["FontSize"] = this->fontSize; + + // Page + page["Width"] = this->physicalWidth; + page["Height"] = this->physicalHeight; + page["WorkWidth"] = this->contentWidth; + page["WorkHeight"] = this->contentHeight; + page["WorkX"] = this->contentX; + page["WorkY"] = this->contentY; + page["PageType"] = this->pageType.toStdString(); + + // Paragraph + paragraph["Horizontal"] = this->horizontal.toStdString(); + paragraph["ParaIndent"] = this->paraIndent; + paragraph["FirstIndent"] = this->firstIndent; + paragraph["SpaceBefore"] = this->spaceBefore; + paragraph["SpaceAfter"] = this->spaceAfter; + paragraph["LineHeight"] = this->lineHeight.toStdString(); + paragraph["LineHeightValue"] = this->lineHeightValue; + + root["App"] = app; + root["Font"] = font; + root["Page"] = page; + root["Paragraph"] = paragraph; + + txtOutput << QString::fromStdString(root.toStyledString()) <creator = QString::fromStdString("OFDEditor"); + this->creatorVersion = QString::fromStdString("1.0"); + this->docType = QString::fromStdString("OFD"); + this->docVersion = QString::fromStdString("1.0"); + this->viewMode = QString::fromStdString("Edit"); + this->undoSize = 10; + + // Font + this->fontFamily = tr("Test"); + this->fontSize = 12; + + // Page + this->physicalWidth = 210; + this->physicalHeight = 297; + this->contentWidth = 210; + this->contentHeight = 297; + this->contentX = 0; + this->contentY = 0; + this->pageType = QString::fromStdString("A4"); + + //Paragraph + this->horizontal = QString::fromStdString("AlignLeft"); + this->paraIndent = 0; + this->firstIndent = 0; + this->spaceBefore = 0; + this->spaceAfter = 0; + this->lineHeight = QString::fromStdString("SingleHeight"); + this->lineHeightValue = 0; + +} + +/// +/// \brief GlobalSetting::getInstance +/// 获得唯一的全局设置对象实例 +/// \return +/// \author chaoqun +/// \date 2017/08/03 +GlobalSetting *GlobalSetting::getInstance() +{ + if( m_instance != NULL ) + { + return m_instance; + } + + m_instance = new GlobalSetting(); // 新建实例 + return m_instance; +} + +/// +/// \brief GlobalSetting::DestoryInstance +/// 销毁实例-估计用不上 +/// \author chaoqun +/// \date 2017/08/04 +/// +void GlobalSetting::DestoryInstance() +{ + delete m_instance; + m_instance = NULL; +} + +/// +/// \brief GlobalSetting::SaveSetting +/// 将软件设置的更改保存到文件中去 +/// \author chaoqun +/// \date 2017/08/04 +/// +void GlobalSetting::SaveSetting() +{ + this->exportGlobalSetting(this->filepath); +} + +void GlobalSetting::setCreator(QString creator) +{ + if(this->creator != creator) + { + this->settingChanged = true; + this->creator = creator; + } + +} + +void GlobalSetting::setCreatorVersion(QString creatorVersion) +{ + if(this->creatorVersion != creatorVersion) + { + this->settingChanged = true; + this->creatorVersion = creatorVersion; + } + +} + +void GlobalSetting::setDocType(QString docType) +{ + if(this->docType != docType) + { + this->settingChanged = true; + this->docType = docType; + } +} + +void GlobalSetting::setDocVersion(QString docVersion) +{ + if(this->docVersion != docVersion) + { + this->settingChanged = true; + this->docVersion = docVersion; + } + +} + +void GlobalSetting::setViewMode(QString viewMode) +{ + if(this->viewMode != viewMode) + { + this->settingChanged = true; + this->viewMode = viewMode; + } + +} + +void GlobalSetting::setUndoSize(int undosize) +{ + if(this->undoSize != undosize) + { + this->settingChanged = true; + this->undoSize = undosize; + } +} + +void GlobalSetting::setFontFamily(QString fontFamily) +{ + if(this->fontFamily != fontFamily) + { + this->settingChanged = true; + this->fontFamily = fontFamily; + } + +} + +void GlobalSetting::setFontSize(double fontSize) +{ + if(this->fontSize != fontSize) + { + this->settingChanged = true; + this->fontSize = fontSize; + } + +} + +void GlobalSetting::setPhysicalWidth(double physicalWidth) +{ + if(this->physicalWidth != physicalWidth) + { + this->settingChanged = true; + this->physicalWidth = physicalWidth; + } + +} + +void GlobalSetting::setPhysicalHeight(double physicalHeight) +{ + if(this->physicalHeight != physicalHeight) + { + this->settingChanged = true; + this->physicalHeight = physicalHeight; + } + +} + +void GlobalSetting::setContentWidth(double contentWidth) +{ + if(this->contentWidth != contentWidth) + { + this->settingChanged = true; + this->contentWidth = contentWidth; + } + +} + +void GlobalSetting::setContentHeight(double contentHeight) +{ + if(this->contentX != contentHeight) + { + this->settingChanged = true; + this->contentHeight = contentHeight; + } +} + +void GlobalSetting::setContentX(double contentX) +{ + if(this->contentX != contentX) + { + this->settingChanged = true; + this->contentX = contentX; + } +} + +void GlobalSetting::setContentY(double contentY) +{ + if(this->contentY != contentY) + { + this->settingChanged = true; + this->contentY = contentY; + } +} + +void GlobalSetting::setPageType(QString pageType) +{ + if(this->pageType != pageType) + { + this->settingChanged = true; + this->pageType = pageType; + } +} + +void GlobalSetting::setHorizontal(QString horizontal) +{ + if(this->horizontal != horizontal) + { + this->settingChanged = true; + this->horizontal = horizontal; + } + +} + +void GlobalSetting::setParaIndent(double paraIndent) +{ + if(this->paraIndent != paraIndent) + { + this->settingChanged = true; + this->paraIndent = paraIndent; + } + +} + +void GlobalSetting::setFirstIndent(double firstIndent) +{ + if(this->firstIndent != firstIndent) + { + this->settingChanged = true; + this->firstIndent = firstIndent; + } +} + +void GlobalSetting::setSpaceBefore(double spaceBefore) +{ + if(this->spaceBefore != spaceBefore) + { + this->settingChanged = true; + this->spaceBefore = spaceBefore; + } +} + +void GlobalSetting::setSpaceAfter(double spaceAfter) +{ + if(this->spaceAfter != spaceAfter) + { + this->settingChanged = true; + this->spaceAfter = spaceAfter; + } +} + +void GlobalSetting::setLineHeight(QString lineHeight) +{ + if(this->lineHeight != lineHeight) + { + this->settingChanged = true; + this->lineHeight = lineHeight; + } +} + +void GlobalSetting::setLineHeightValue(double lineHeightValue) +{ + if(this->lineHeightValue != lineHeightValue) + { + this->settingChanged = true; + this->lineHeightValue = lineHeightValue; + } +} + +void GlobalSetting::setfilePath(QString path) +{ + this->filepath = path; +} diff --git a/ofdEditor/model/Core/GlobalSetting.h b/ofdEditor/model/Core/GlobalSetting.h new file mode 100644 index 0000000000000000000000000000000000000000..b91726d7f5b990eb7324330cc586ad5c03f7b89c --- /dev/null +++ b/ofdEditor/model/Core/GlobalSetting.h @@ -0,0 +1,146 @@ +#ifndef GLOBALSETTING_H +#define GLOBALSETTING_H + +#include +#include +#include +#include "model_global.h" + +/// +/// \brief The GlobalSetting class +/// 用来做系统的全局设置,没有设置多线程的锁结构,因此多线程慎用 +/// +class MODELSHARED_EXPORT GlobalSetting + : public QObject +{ + Q_OBJECT +private: + explicit GlobalSetting(QObject *parent = 0); + + static GlobalSetting* m_instance; + + + void loadGlobalSetting(QString filePath);// 从文件中读取设置信息 + + void exportGlobalSetting(QString filePath);// 将设置信息写回文件 + void setDefaultSetting(); // 在代码中纪录默认设置,防止设置文件丢失 + +public: + static GlobalSetting* getInstance(); // 获得单例 + static void DestoryInstance(); // 销毁单例 + + + QString getFilePath(){return this->filepath;} // 返回配置文件的存储路径 + bool isChanged(){return this->settingChanged;} // 设置内容是否发生过改变 + // 获得各种类型的全局变量 + + // 应用程序信息 + QString getCreator(){return this->creator;} + QString getCreatorVersion(){return this->creatorVersion;} + QString getDocType(){return this->docType;} + QString getDocVersion(){return this->docVersion;} + QString getViewMode(){return this->viewMode;} + int getUndoSize(){return this->undoSize;} + + // 字体 + QString getFontFamily(){return this->fontFamily;} + double getFontSize(){return this->fontSize;} + + // 纸张样式 + double getPhysicalWidth(){return this->physicalWidth;} + double getPhysicalHeight(){return this->physicalHeight;} + double getContentWidth(){return this->contentWidth;} + double getContentHeight(){return this->contentHeight;} + double getContentX(){return this->contentX;} + double getContentY(){return this->contentY;} + QString getPageType(){return this->pageType;} + + // 段落 + QString getHorizontal(){return this->horizontal;} + double getParaIndent(){return this->paraIndent;} + double getFirstIndent(){return this->firstIndent;} + double getSpaceBefore(){return this->spaceBefore;} + double getSpaceAfter(){return this->spaceAfter;} + QString getLineHeight(){return this->lineHeight;} + double getLineHeightValue(){return this->lineHeightValue;} + +public slots: + void setfilePath(QString path); // 设置文件路径 + void SaveSetting(); // 将设置保存回文件 + + // app + void setCreator(QString creator); + void setCreatorVersion(QString creatorVersion); + void setDocType(QString docType); + void setDocVersion(QString docVersion); + void setViewMode(QString viewMode); + void setUndoSize(int undosize); + + // font + void setFontFamily(QString fontFamily); + void setFontSize(double fontSize); + + // page + void setPhysicalWidth(double physicalWidth); + void setPhysicalHeight(double physicalHeight); + void setContentWidth(double contentWidth); + void setContentHeight(double contentHeight); + void setContentX(double contentX); + void setContentY(double contentY); + void setPageType(QString pageType); + + // paragraph + void setHorizontal(QString horizontal); + void setParaIndent(double paraIndent); + void setFirstIndent(double firstIndent); + void setSpaceBefore(double spaceBefore); + void setSpaceAfter(double spaceAfter); + void setLineHeight(QString lineHeight); + void setLineHeightValue(double lineHeightValue); + +private: + QString filepath; // 存放设置文件的路径 + QTextCharFormat charFormat; // 存放字体格式 + QTextBlockFormat blockFormat; // 段落格式 + + bool settingChanged; // 全局设置的内容是否发生改变 + + // App 信息 + QString creator; // 应用程序信息 + QString creatorVersion; // 应用程序版本 + QString docType; // 文档标准 + QString docVersion; // 文档标准版本 + QString viewMode; // 首次打开软件的阅读模式 + int undoSize; // 撤销恢复栈的最大容量 0 为不限容量 + + // Font + QString fontFamily; // 字体类型 + double fontSize; // 字体大小 + + //Page + double physicalWidth; // 页面物理宽度 + double physicalHeight; // 页面物理高度 + double contentWidth; // 内容宽度 + double contentHeight; // 内容高度 + double contentX; // 内容水平位置 + double contentY; // 内容竖直位置 + QString pageType; // 页面大小类型 + + // Paragraph + QString horizontal; // 水平对齐策略 + double paraIndent; // 段落缩进 + double firstIndent; // 首行缩进 + double spaceBefore; // 段前空白 + double spaceAfter; // 段后空白 + QString lineHeight; // 行高策略 + double lineHeightValue; // 行高值 + + +signals: + +public slots: + +}; + + +#endif // GLOBALSETTING_H diff --git a/ofdEditor/model/Doc/DocBlock.cpp b/ofdEditor/model/Doc/DocBlock.cpp index ad7f8f6db3fb473cced24aadebc5c8e8be260951..1bab6701e2c3c61bf4758898b1b5654abb897c6d 100644 --- a/ofdEditor/model/Doc/DocBlock.cpp +++ b/ofdEditor/model/Doc/DocBlock.cpp @@ -15,6 +15,8 @@ #include "Doc/DocPage.h" #include "Doc/DocPassage.h" #include "Doc/DocImageBlock.h" +#include "Doc/DocTable.h" +#include "Widget/BlockSizeAndPosSettingDialog.h" DocBlock::DocBlock(QGraphicsItem *parent , Qt::WindowFlags wFlags) :QGraphicsProxyWidget(parent,wFlags) @@ -24,14 +26,31 @@ DocBlock::DocBlock(QGraphicsItem *parent , Qt::WindowFlags wFlags) this->setZValue(200); this->isFocused = false; // 初始时设为false + this->blockIsResizing = false; this->rectAdjust = blockNone; // 一开始处于空状态 this->setFlag(QGraphicsProxyWidget::ItemIsSelectable, true); // 可选择 this->setFlag(QGraphicsProxyWidget::ItemIsFocusable, true); // 可关注 this->setAcceptHoverEvents(true); - textBlock = NULL; - imageBlock = NULL; + this->textBlock = NULL; + this->imageBlock = NULL; + this->_table = NULL; + this->isShowBox = false; + + this->initMenu(); +} + +/// +/// \brief DocBlock::Layer +/// \return +/// +DocPage::Layer DocBlock::Layer() +{ + if(this->layer != NULL) + return this->layer->getLayer(); + else + return DocPage::Body; } /** @@ -104,6 +123,8 @@ void DocBlock::resize(qreal w, qreal h) QGraphicsProxyWidget::resize(w,h); this->blockSize.setWidth(w); this->blockSize.setHeight(h); + + emit this->signal_resize(this->x(),this->y(),w,h); } /** @@ -118,6 +139,8 @@ void DocBlock::resize(const QSizeF &size) QGraphicsProxyWidget::resize(size); this->blockSize.setWidth(size.width()); this->blockSize.setHeight(size.height()); + emit this->signal_resize(this->x(),this->y(), + size.width(),size.height()); } /** @@ -159,6 +182,11 @@ void DocBlock::remove() QGraphicsScene *scene = this->scene(); // 查找到本块所在的场景 scene->removeItem(this); // 从场景中移除该组件 + if(this->layer) + { + this->layer->removeBlock(this); + } + emit this->signals_blockRemoved(this); // 发出信号 } @@ -181,6 +209,22 @@ void DocBlock::paint(QPainter *painter, this->paintHandle(*painter); // 画出调整框 } + if(this->isShowBox) + { + // 如果需要花边框的话,为什么要在这里画呢 + // 因为如果需要绘制边框,直接用系统的显示边框会影响block内的尺寸 + + painter->setPen(Qt::black); + + // resize line + qreal w = this->blockSize.width(); + qreal h = this->blockSize.height(); + + painter->drawRect(0,0, + w,h); + + } + } /** @@ -192,6 +236,9 @@ void DocBlock::paint(QPainter *painter, */ void DocBlock::focusInEvent(QFocusEvent *event) { + if(!this->getPage()->getEditable()) + return; + QGraphicsProxyWidget::focusInEvent(event); this->isFocused = true; @@ -209,6 +256,8 @@ void DocBlock::focusInEvent(QFocusEvent *event) */ void DocBlock::focusOutEvent(QFocusEvent *event) { + if(!this->getPage()->getEditable()) + return; QGraphicsProxyWidget::focusOutEvent(event); this->isFocused = false; QGraphicsProxyWidget::setZValue(this->realZValue); // 还原到真实的Z坐标 @@ -226,6 +275,7 @@ void DocBlock::focusOutEvent(QFocusEvent *event) void DocBlock::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { // qDebug() << "Hovering."; + if (this->rectAdjust == blockResize || (this->currentStatus(event->pos()) == blockResize && this->isFocused)) @@ -238,16 +288,27 @@ void DocBlock::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { this->setCursor(Qt::SizeAllCursor); // 设置为移动样式 } - else if(this->cursor().shape() != Qt::IBeamCursor) + else if(this->rectAdjust == blockNone) { -// this->unsetCursor(); // 取消设置鼠标-效果不好 -// qDebug() <<"Redo hoverEnterEvent"; - QGraphicsProxyWidget::hoverEnterEvent(event); // 执行重新进入,设置鼠标 + if(this->isTextBlock()) + { + // 如果是文本框 + this->setCursor(Qt::IBeamCursor); + } } + QGraphicsProxyWidget::hoverMoveEvent(event); // 调用父类的调整函数 } +void DocBlock::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + +// this->clearFocus(); +// this->setFocus(); + +} + /** * @Author Chaoqun * @brief 鼠标按下时处理函数 @@ -257,18 +318,6 @@ void DocBlock::hoverMoveEvent(QGraphicsSceneHoverEvent *event) */ void DocBlock::mousePressEvent(QGraphicsSceneMouseEvent *event) { -// qDebug() << "Pressed."; - QPointF pos = event->pos(); // 获取鼠标位置 -// qDebug()<<"DocBlock Mouse Postion" << pos.x() -// << ", "<button() == Qt::LeftButton ) - { - // 如果按下的是鼠标左键,检测是否是可以修改大小或位置的状态 - this->rectAdjust = this->currentStatus(event->pos()); -// qDebug() << (rectAdjust == DocBlock::blockResize); - } -//qDebug() << (rectAdjust == DocBlock::blockResize); QGraphicsProxyWidget::mousePressEvent(event); } @@ -312,27 +361,14 @@ void DocBlock::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void DocBlock::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - if (event->button() == Qt::LeftButton && - this->rectAdjust != blockNone) + if(event->button() == Qt::LeftButton) { - this->rectAdjust = blockNone; + this->rectAdjust = this->currentStatus(event->pos()); } QGraphicsProxyWidget::mouseReleaseEvent(event); } -/** - * @Author Chaoqun - * @brief 可以实现右键菜单 - * @param 参数 - * @return 返回值 - * @date 2017/06/20 - */ -void DocBlock::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) -{ - QGraphicsProxyWidget::contextMenuEvent(event); -} - /** * @Author Chaoqun * @brief 设置内容 @@ -355,15 +391,16 @@ void DocBlock::setWidget(QWidget *widget) void DocBlock::setWidget(DocTextBlock *textBlock) { // 建立connect - connect(textBlock,SIGNAL(signals_remove(DocTextBlock*)), - this,SLOT(remove())); // 和块做移除连接 - connect(textBlock,SIGNAL(signals_setZValue(qreal)), - this,SLOT(setZValue(qreal))); // 建立设置Z值的信号连接 +// connect(textBlock,SIGNAL(signals_remove(DocTextBlock*)), +// this,SLOT(remove())); // 和块做移除连接 +// connect(textBlock,SIGNAL(signals_setZValue(qreal)), +// this,SLOT(setZValue(qreal))); // 建立设置Z值的信号连接 textBlock->setBlock(this); // 给DocTextBlock设置引用 this->textBlock = textBlock; // 给DocBlock设置引用 QGraphicsProxyWidget::setWidget(textBlock); + qDebug() <<"set widget text"; } @@ -381,6 +418,40 @@ void DocBlock::setWidget(DocImageBlock * imageBlock) QGraphicsProxyWidget::setWidget(imageBlock); } +/// +/// \brief DocBlock::setWidget +/// 设置对象为表格 +/// \param table +/// +void DocBlock::setWidget(DocTable *table) +{ + table->setBlock(this); + this->_table = table; + QGraphicsProxyWidget::setWidget(table); + qDebug() << "set Widget table"; +} + +/// +/// \brief DocBlock::sizeAndPositionDialog +/// 大小位置调整窗口 +/// +void DocBlock::sizeAndPositionDialog() +{ + BlockSizeAndPosSettingDialog* dialog = BlockSizeAndPosSettingDialog::getInstance(); + dialog->init(this); + dialog->exec(); +} + +/// +/// \brief DocBlock::setShowBoundaryBox +/// 设置是否显示包围的边框 +/// \param flag +/// +void DocBlock::setShowBoundaryBox(bool flag) +{ + this->isShowBox = flag; +} + /** * @Author Chaoqun * @brief 检查鼠标是否在重置大小区域 @@ -394,6 +465,74 @@ bool DocBlock::isInResizeArea(const QPointF &pos) (this->size().height() - pos.y()); } + +void DocBlock::initMenu() +{ + // 移动到前景层 + this->action_foreground = new QAction(tr("Foreground"), NULL); + this->action_foreground->setCheckable(true); + this->connect(this->action_foreground, SIGNAL(triggered(bool)), + this, SLOT(moveToForeground())); + + // 移动到正文层 + this->action_body = new QAction(tr("Body"), NULL); + this->action_body->setCheckable(true); + this->connect(this->action_body, SIGNAL(triggered(bool)), + this, SLOT(moveToBody())); + + // 移动到背景层 + this->action_background = new QAction(tr("Background"), NULL); + this->action_background->setCheckable(true); + + this->connect(this->action_background, SIGNAL(triggered(bool)), + this, SLOT(moveToBackground())); + + // 删除 + this->action_delete = new QAction(tr("Delete"), NULL); + + this->connect(this->action_delete, SIGNAL(triggered(bool)), + this, SLOT(remove())); + + // 大小和位置调整 + this->action_geometry = new QAction(tr("size and position"), NULL); + + this->connect(this->action_geometry, SIGNAL(triggered(bool)), + this, SLOT(sizeAndPositionDialog())); +} + +/// +/// \brief DocBlock::moveToForeground +/// +void DocBlock::moveToForeground() +{ + if(this->Layer() != DocPage::Foreground) + { + this->getPage()->changeBlockLayer(this, DocPage::Foreground); + } +} + +/// +/// \brief DocBlock::moveToBody +/// +void DocBlock::moveToBody() +{ + if(this->Layer() != DocPage::Body) + { + this->getPage()->changeBlockLayer(this, DocPage::Body); + } +} + +/// +/// \brief DocBlock::moveToBackground +/// +void DocBlock::moveToBackground() +{ + if(this->Layer() != DocPage::Background) + { + this->getPage()->changeBlockLayer(this, DocPage::Background); + } +} + /** * @Author Chaoqun * @brief 检测当前状态是否可以移动块 @@ -401,33 +540,33 @@ bool DocBlock::isInResizeArea(const QPointF &pos) * @return RectAdjustStatus * @date 2017/05/19 */ -DocBlock::RectAdjustStatus DocBlock::currentStatus(const QPointF &pos) +DocBlock::RectAdjustStatus DocBlock::currentStatus( QPointF pos) { -// qDebug() << "get current status."; - if (isTextBlock()) + if (isTextBlock() || isTableBlock()) { if((pos.x() - this->size().width() + 15) > (this->size().height() - pos.y())) { - //qDebug() << "Mouse resizing."; return blockResize; } // 画出可以移动的边缘 - qreal moveMargin = 5; // 边缘多少像素内可以移动 - QRectF left(0,0, + qreal moveMargin = 10; // 边缘多少像素内可以移动 + QRectF left(-5,0, moveMargin,this->blockSize.height()); - QRectF right(this->blockSize.width()-moveMargin,0, + QRectF right(this->blockSize.width()-moveMargin+5,0, moveMargin,this->blockSize.height()); - QRectF top(0,0, + QRectF top(0,-5, this->blockSize.width(),moveMargin); - QRectF bottom(0,this->blockSize.height() - moveMargin, + QRectF bottom(0,this->blockSize.height() - moveMargin+5, this->blockSize.width(),moveMargin); if(left.contains(pos) || right.contains(pos) || top.contains(pos) || bottom.contains(pos)) + { return blockMove; + } // 如果未得出结果,则默认无操作 return blockNone; @@ -452,6 +591,76 @@ DocBlock::RectAdjustStatus DocBlock::currentStatus(const QPointF &pos) } } +/// +/// \brief DocBlock::getMenu +/// 获得菜单 +/// \return +/// +QMenu *DocBlock::getMenu() +{ + QMenu * menu = new QMenu(); // 新建菜单 + QMenu * menu_layer = new QMenu(tr("Layer")); // 子菜单-层 + menu_layer->addAction(this->action_foreground); + menu_layer->addAction(this->action_body); + menu_layer->addAction(this->action_background); + + // 设置提醒状态 + if(this->Layer() == DocPage::Foreground) + { + this->action_foreground->setChecked(true); + this->action_body->setChecked(false); + this->action_background->setChecked(false); + } + else if(this->Layer() == DocPage::Body) + { + this->action_foreground->setChecked(false); + this->action_body->setChecked(true); + this->action_background->setChecked(false); + } + else if(this->Layer() == DocPage::Background) + { + this->action_foreground->setChecked(false); + this->action_body->setChecked(false); + this->action_background->setChecked(true); + } + + if(this->isTextBlock()) + { + // 文本框 + menu = this->textBlock->getMenu(); + menu->setTitle(this->textBlock->getType()); + + menu->addSeparator(); + menu->addAction(this->action_geometry); + menu->addMenu(menu_layer); + menu->addAction(this->action_delete); + + } + else if(this->isTableBlock()) + { + // 这个是表格 + menu = this->_table->getMenu(); + menu->setTitle(this->_table->getType()); + + menu->addSeparator(); + menu->addAction(this->action_geometry); + menu->addMenu(menu_layer); + menu->addAction(this->action_delete); + } + else if(this->isImageBlock()) + { + // 如果是图片 + menu = this->imageBlock->getMenu(); + menu->setTitle(this->imageBlock->getType()); + + menu->addSeparator(); + menu->addMenu(menu_layer); + menu->addAction(this->action_delete); + } + + return menu; +} + /** * @Author Chaoqun * @brief 判断是其中装的是否是DocTextBlock @@ -482,6 +691,7 @@ DocTextBlock *DocBlock::getTextBlock() { if (isTextBlock()) return this->textBlock; + return NULL; } /** @@ -507,4 +717,17 @@ DocImageBlock * DocBlock::getImageBlock() { if (isImageBlock()) return imageBlock; + return NULL; +} + +bool DocBlock::isTableBlock() +{ + return this->_table != NULL; +} + +DocTable *DocBlock::getTableBlock() +{ + if(this->isTableBlock()) + return this->_table; + return NULL; } diff --git a/ofdEditor/model/Doc/DocBlock.h b/ofdEditor/model/Doc/DocBlock.h index eb126f99d53513df020184a8b7275ed19c826b4f..54aa0b6953eea4e352fb19c9d800fa2c3f0f7fbe 100644 --- a/ofdEditor/model/Doc/DocBlock.h +++ b/ofdEditor/model/Doc/DocBlock.h @@ -5,6 +5,9 @@ #include "Doc/DocBasicTypes.h" #include #include +#include +#include +#include "Doc/DocPage.h" class DocLayer; class QPainter; @@ -12,6 +15,7 @@ class DocTextBlock; class DocPage; class DocPassage; class DocImageBlock; +class DocTable; /** * @Author Chaoqun @@ -25,21 +29,45 @@ class MODELSHARED_EXPORT DocBlock { Q_OBJECT public: + enum { Type = UserType + 1 }; + int type() const + { + // Enable the use of qgraphicsitem_cast with this item. + return Type; + } + DocBlock(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); - enum RectAdjustStatus{blockNone , blockResize , blockMove}; // 对块的大小状态进行调整 + enum RectAdjustStatus + { + blockNone , + blockResize , + blockMove + }; // 对块的大小状态进行调整 + RectAdjustStatus rectAdjust; // 用来标识当前修改尺寸的状态 DocLayer * getLayer(){return this->layer;} // 获得所在的层 + DocPage::Layer Layer(); // 获得所在的层的名称 DocPage * getPage(); // 获得所在页 DocPassage *getPassage(); // 获得所在文章 void paintHandle(QPainter& painter); // 绘制负责变换的控制器 qreal getZValue(){return this->realZValue;} // 获得当前块所在的Z值 - RectAdjustStatus currentStatus(const QPointF& pos); // 鼠标所在位置可以进行什么调整 + RectAdjustStatus currentStatus(QPointF pos); // 鼠标所在位置可以进行什么调整 - bool isTextBlock(); // 判断是否DocBlock装的是否是DocTextBlock - DocTextBlock *getTextBlock(); // 获得DocTextBlock + QMenu *getMenu(); // 根据块和块内部的设置,增加设置窗口 + bool isTextBlock(); // 判断是否DocBlock装的是否是DocTextBlock + DocTextBlock *getTextBlock(); // 获得DocTextBlock bool isImageBlock(); DocImageBlock *getImageBlock(); //获得DocImageBlock + bool isTableBlock(); + DocTable *getTableBlock(); // 获得DocTable + + QAction *action_geometry; // 大小和位置 + QAction *action_delete; // 删除块 + + QAction *action_foreground; // 移动到前景 + QAction *action_body; // 移动到正文 + QAction *action_background; // 移动到背景 public slots: // 槽函数 void setLayer(DocLayer * layer){this->layer = layer;} @@ -49,10 +77,14 @@ public slots: // 槽函数 void setPos(qreal x, qreal y); // 设置位置 // 移动位置应该在所在的DocPage中吧…… void remove(); // 从场景中移除本框 + void setWidget(QWidget* widget); // 旧的函数 void setWidget(DocTextBlock *textBlock); // SetWidget void setWidget(DocImageBlock * imageBlock); + void setWidget(DocTable* table); + void sizeAndPositionDialog(); // 调整大小和位置窗口 + void setShowBoundaryBox(bool flag); // 设置是否显示边框 protected: void paint(QPainter *painter, @@ -63,27 +95,38 @@ protected: // 用来修改鼠标 void hoverMoveEvent (QGraphicsSceneHoverEvent *event); // 鼠标悬浮响应 + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); // 双击恢复正常 void mousePressEvent (QGraphicsSceneMouseEvent * event); void mouseMoveEvent (QGraphicsSceneMouseEvent *event); void mouseReleaseEvent (QGraphicsSceneMouseEvent * event); - void contextMenuEvent (QGraphicsSceneContextMenuEvent *event); // 邮件菜单吧 private: + DocBox boundary; // 该块的外包矩形 DocLayer * layer; // 该块在哪一个层之中 QSizeF blockSize; // 用来纪录大小 QPointF blockOldPos; // 用来记录旧的位置 - DocTextBlock * textBlock; // 存下引用 + DocTextBlock * textBlock; // 存下引用 DocImageBlock * imageBlock; //同上 + DocTable * _table; // 存下引用 + qreal realZValue; // 真实的z值 + bool isShowBox; // 是否显示边框 bool isFocused; // 是否被聚焦 bool blockIsResizing; // 是否正在改变大小 bool isInResizeArea(const QPointF& pos); // 检查鼠标是否在重置大小区域 - qreal realZValue; // 真实的z值 + + void initMenu(); // 初始化 signals: void signals_blockRemoved(DocBlock* block); // 当本块被移除时发出信号 + void signal_resize(qreal x, qreal y, qreal width, qreal height); // 发送block大小改变信号 + +private slots: + void moveToForeground(); // 移动到前景层 + void moveToBody(); // 移动到正文层 + void moveToBackground(); // 移动到背景层 }; diff --git a/ofdEditor/model/Doc/DocDrawParam.cpp b/ofdEditor/model/Doc/DocDrawParam.cpp deleted file mode 100644 index 374e0cc3e878044f10a0df480ea6d4f348d1ca1d..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocDrawParam.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "DocDrawParam.h" - -DocDrawParam::DocDrawParam() -{ - -} diff --git a/ofdEditor/model/Doc/DocDrawParam.h b/ofdEditor/model/Doc/DocDrawParam.h deleted file mode 100644 index 5f715d1de03163813738c208fa9737e527d6734c..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocDrawParam.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef DOCDRAWPARAN_H -#define DOCDRAWPARAN_H - -#include "model_global.h" - -/** - * @Author Chaoqun - * @brief 结合渲染,因此这里的绘画模式要更接近于Qt的 - * @date 2017/04/30 - */ -class MODELSHARED_EXPORT DocDrawParam -{ -public: - DocDrawParam(); -}; - -#endif // DOCDRAWPARAN_H diff --git a/ofdEditor/model/Doc/DocImageBlock.cpp b/ofdEditor/model/Doc/DocImageBlock.cpp index afb1befbf950e78330b4cb8f1d2a9c1164a6038d..48322c7201910acf28e48b000e90ac63de6930ba 100644 --- a/ofdEditor/model/Doc/DocImageBlock.cpp +++ b/ofdEditor/model/Doc/DocImageBlock.cpp @@ -4,6 +4,8 @@ #include #include #include "DocPage.h" +#include "Tool/UnitTool.h" +#include DocImageBlock::DocImageBlock(QWidget *parent) :QLabel(parent) @@ -15,25 +17,11 @@ DocImageBlock::DocImageBlock(QWidget *parent) this->setFocusPolicy(Qt::StrongFocus); //Initialization - this->context_menu = new QMenu(this); - change_image = new QAction(tr("Change Image"), NULL); - set_image_properties = new QAction(tr("Set Image Properties"), NULL); - properties_dialog = new ImagePropertiesDialog(this, parent); - width_height_ratio_locked = false; + width_height_ratio_locked = true; width_height_ratio = 0.0; - //signal-slots - this->connect(this->change_image, SIGNAL(triggered()), - this, SLOT(changeImage())); - this->connect(this->set_image_properties, SIGNAL(triggered()), - this, SLOT(setImageProperties())); - this->connect(properties_dialog, - SIGNAL(changeImageProperties(double,double, - double,double, - bool)), - this, SLOT(imagePropertiesChanged(double,double, - double,double, - bool))); + this->initMenu(); // 初始化右键菜单 + } /** @@ -45,6 +33,13 @@ DocImageBlock::DocImageBlock(QWidget *parent) */ void DocImageBlock::setImage(QPixmap & pixmap) { + + this->realWidth = UnitTool::pixelToMM( + pixmap.width()); // 保存实际宽度 + this->realHeight = UnitTool::pixelToMM( + pixmap.height()); // 保存实际高度 + this->width_height_ratio = this->realWidth / this->realHeight; + this->setPixmap(pixmap); } @@ -83,6 +78,117 @@ double DocImageBlock::getWidthHeightRatio() { if (isWidthHeightRatioLocked()) return width_height_ratio; + else return -1; +} + +DocPassage *DocImageBlock::getPassage() +{ + DocBlock *block = this->block; + if(block == NULL) + return NULL; + + return block->getPassage(); + +} + +/// +/// \brief DocImageBlock::getPage +/// 获得图片框所属的页 +/// \return +/// +DocPage *DocImageBlock::getPage() +{ + DocBlock *block = this->block; + if(block == NULL) + return NULL; + + return block->getPage(); +} + +/// +/// \brief DocImageBlock::getLayer +/// 获得图片框所属的层 +/// \return +/// +DocLayer *DocImageBlock::getLayer() +{ + DocBlock *block = this->block; + if(block == NULL) + return NULL; + + return block->getLayer(); +} + +/// +/// \brief DocImageBlock::getBlock +/// 获得图片框所属的块 +/// \return +/// +DocBlock *DocImageBlock::getBlock() +{ + return this->block; +} + +QString DocImageBlock::getType() +{ + return tr("DocImageBlock"); +} + +/// +/// \brief DocImageBlock::getMenu +/// 获得图片块的右键菜单 +/// \return +/// +QMenu *DocImageBlock::getMenu() +{ + this->context_menu->clear(); + this->context_menu->setTitle(this->getType()); + this->context_menu->addAction(this->change_image); + this->context_menu->addAction(this->set_image_properties); + + return this->context_menu; +} + +QString DocImageBlock::getFileName() +{ + if(this->fileName.size() == 0) + { + // 如果没有设置文件名,则随机生成文件名 + QUuid uuid = QUuid::createUuid(); // 创建uuid + QString imageName = uuid.toString(); // 转换为字符串 + + // 去掉字符串的链接符号 {0142d46f-60b5-47cf-8310-50008cc7cb3a} + // 0142d46f60b547cf831050008cc7cb3a + imageName.remove(imageName.length()-1, 1); + imageName.remove(imageName.length() -13, 1); + imageName.remove(imageName.length() -17,1); + imageName.remove(imageName.length() -21, 1); + imageName.remove(imageName.length() - 25,1); + imageName.remove(0,1); + + this->fileName = imageName + ".jpg"; + } + return this->fileName; +} + +/// +/// \brief DocImageBlock::saveImage +/// 将图片保存到指定路径 +/// \param filepath +/// +void DocImageBlock::saveImage(QString filepath) +{ + this->pixmap()->save(filepath, 0, 100); +} + +double DocImageBlock::getRealWidth() +{ + return this->realWidth; +} + +double DocImageBlock::getRealHeight() +{ + return this->realHeight; } /** @@ -96,7 +202,8 @@ void DocImageBlock::focusInEvent(QFocusEvent *e) { //qDebug() << "focus In Event"; emit signals_currrentImageBlock(this); - this->setFrameShape(QFrame::Box); +// this->setFrameShape(QFrame::Box); + this->block->setShowBoundaryBox(true); this->setLineWidth(1); QLabel::focusInEvent(e); } @@ -110,23 +217,32 @@ void DocImageBlock::focusInEvent(QFocusEvent *e) */ void DocImageBlock::focusOutEvent(QFocusEvent *e) { - this->setFrameStyle(QFrame::NoFrame); +// this->setFrameStyle(QFrame::NoFrame); + this->block->setShowBoundaryBox(false); QLabel::focusOutEvent(e); } -/** - * @Author Pan - * @brief 右键菜单 - * @param QContextMenuEvent *ev - * @return void - * @date 2017/06/24 - */ -void DocImageBlock::contextMenuEvent(QContextMenuEvent *ev) +/// +/// \brief DocImageBlock::initMenu +/// 初始化右键菜单 +/// +void DocImageBlock::initMenu() { - context_menu->addAction(this->change_image); - context_menu->addAction(this->set_image_properties); + this->context_menu = new QMenu(tr("DocImageBlock")); // 新建菜单 + + this->change_image = new QAction(tr("Change Image"), this); + this->set_image_properties = new QAction(tr("Property"), this); + + this->context_menu->addAction(this->change_image); + this->context_menu->addAction(this->set_image_properties); + + //signal-slots + this->connect(this->change_image, SIGNAL(triggered()), + this, SLOT(changeImage())); + + this->connect(this->set_image_properties, SIGNAL(triggered()), + this, SLOT(setImageProperties())); - context_menu->exec(ev->globalPos()); } /** @@ -139,15 +255,18 @@ void DocImageBlock::contextMenuEvent(QContextMenuEvent *ev) void DocImageBlock::changeImage() { QString fileName = QFileDialog::getOpenFileName(this, - tr("Open File"), QDir::currentPath()); - if (!fileName.isEmpty()) { + tr("Open File"), QDir::currentPath()); + if (!fileName.isEmpty()) + { QPixmap image(fileName); - if (image.isNull()) { + if (image.isNull()) + { QMessageBox::information(this, tr("OFD Editor"), tr("Cannot open file %1.").arg(fileName)); return; } - this->setPixmap(image); + this->setImage(image); + } } @@ -160,14 +279,9 @@ void DocImageBlock::changeImage() */ void DocImageBlock::setImageProperties() { - emit sendImageInfo(this->width(), - this->height(), - this->pos().x(), - this->pos().y(), - this->block->getPage()->width(), - this->block->getPage()->height(), - this->width_height_ratio_locked); - properties_dialog->exec(); + ImagePropertiesDialog* dialog = ImagePropertiesDialog::getInstance(); + dialog->init(this); + dialog->exec(); } /** @@ -177,14 +291,32 @@ void DocImageBlock::setImageProperties() * @return void * @date 2017/06/25 */ -void DocImageBlock::imagePropertiesChanged(double new_width, - double new_height, - double new_x, - double new_y, - bool ratio_locked) -{ - this->resize(new_width, new_height); - this->move(new_x, new_y); +void DocImageBlock::imagePropertiesChanged( + double new_width, + double new_height, + double new_x, + double new_y, + bool ratio_locked) +{ + this->block->resize(new_width, new_height); + this->block->setPos(new_x, new_y); this->width_height_ratio_locked = ratio_locked; this->width_height_ratio = new_width / new_height; } + +void DocImageBlock::setFileName(QString fileName) +{ + this->fileName = fileName; +} + +/// +/// \brief DocImageBlock::setImage +/// 直接用文件路径设置图片块 +/// \param filePath +/// +void DocImageBlock::setImage(QString filePath) +{ + QPixmap image(filePath); + this->fileName = filePath.section("/", -1); // 获取文件名部分 + this->setImage(image); +} diff --git a/ofdEditor/model/Doc/DocImageBlock.h b/ofdEditor/model/Doc/DocImageBlock.h index 8ac5f9e875ad4a8602bf40944b882883f44b867e..4bed26a235a20a8a6e8375d7a3e14120854a3a13 100644 --- a/ofdEditor/model/Doc/DocImageBlock.h +++ b/ofdEditor/model/Doc/DocImageBlock.h @@ -12,47 +12,66 @@ class DocBlock; class ImagePropertiesDialog; -class MODELSHARED_EXPORT DocImageBlock : public QLabel +class MODELSHARED_EXPORT DocImageBlock + : public QLabel { Q_OBJECT + public: + DocImageBlock(QWidget *parent = NULL); - void setImage(QPixmap & pixmap); - void setBlock(DocBlock * _block); + bool isWidthHeightRatioLocked(); double getWidthHeightRatio(); + DocPassage *getPassage(); // 获得文章 + DocPage *getPage(); // 获得页 + DocLayer *getLayer(); // 获得层 + DocBlock *getBlock(); //获取代理它的DocBlock + QString getType(); // 获得标识,来区分不同的块 + QMenu* getMenu(); // 获得图片块的菜单成分 + QString getFileName(); // 获得图片的文件名 + void saveImage( QString filepath ); // 保存文件 + + // 单位为 mm + double getRealWidth(); // 获得图片真实大小 + double getRealHeight(); // 获得图片真实大小 public slots: - void imagePropertiesChanged(double new_width, - double new_height, - double new_x, - double new_y, - bool ratio_locked); - void changeImage(); - void setImageProperties(); + void imagePropertiesChanged( + double new_width, + double new_height, + double new_x, + double new_y, + bool ratio_locked); // 修改图片属性 + void setFileName(QString fileName); // 设置图片文件名 + void setImage(QString filePath); // 直接使用路径设置图片 + void setImage(QPixmap & pixmap); // 设置图片 + void setBlock(DocBlock * _block); // 设置所属的块 + void changeImage(); // 修改图片 + void setImageProperties(); // 设置图片属性 + void setWidthHeightRatioLocked(bool flag){this->width_height_ratio_locked = flag;} protected: void focusInEvent(QFocusEvent *ev); void focusOutEvent(QFocusEvent *ev); - void contextMenuEvent(QContextMenuEvent *ev); private: DocBlock * block; //对代理它的DocBlock的引用 QMenu * context_menu; //右键菜单 QAction * change_image; //更改图片 QAction * set_image_properties; //更改图片的位置和尺寸 - ImagePropertiesDialog * properties_dialog; bool width_height_ratio_locked; double width_height_ratio; + QString fileName; // 图片的文件名 ---- uuid + 后缀名 + + void initMenu(); // 初始化右键菜单 + + double realWidth; // 图片实际宽度 + double realHeight; // 图片实际高度 + + signals: - void sendImageInfo(double image_width, - double image_height, - double image_x, - double image_y, - double page_width, - double page_height, - bool ratio_is_locked); void signals_currrentImageBlock(DocImageBlock * textBlock); //当前操作的imageBlock }; diff --git a/ofdEditor/model/Doc/DocLayer.cpp b/ofdEditor/model/Doc/DocLayer.cpp index 07da6603ff9f92799dc1ae9d93e39363f66c608e..aa8a3d72c15c08ad17e13fa376486094499ee665 100644 --- a/ofdEditor/model/Doc/DocLayer.cpp +++ b/ofdEditor/model/Doc/DocLayer.cpp @@ -1,7 +1,6 @@ #include "DocLayer.h" #include "Doc/DocBlock.h" // 块 #include "Doc/DocTable.h" // 表格 -#include "Doc/DocDrawParam.h" #include "Doc/DocPage.h" #include "Doc/DocPassage.h" @@ -32,27 +31,6 @@ DocLayer::~DocLayer() } this->blocks.clear(); - // 释放表格 - int tables_length = this->tables.size(); - for(int i = 0; i < tables_length; i++) - { - // 挨个释放表格的空间 - DocTable* temp = this->tables.at(i); - if(temp != NULL) - { - delete temp; - (this->tables)[i]=NULL; - } - } - this->tables.clear(); - - // 释放绘制模式 - if(this->drawParam != NULL) - { - delete this->drawParam; - this->drawParam = NULL; - } - } /** @@ -161,3 +139,14 @@ DocPassage *DocLayer::getPassage() return NULL; return page->getPassage(); } + +/// +/// \brief DocLayer::hasBlock +/// 检查块中是否包含此元素 +/// \param block +/// \return +/// +bool DocLayer::hasBlock(DocBlock *block) +{ + return this->blocks.contains(block); +} diff --git a/ofdEditor/model/Doc/DocLayer.h b/ofdEditor/model/Doc/DocLayer.h index d18bc3ed28848c8037368113aeea9e414259fb58..ff1062a7c2e49080c42a158e4aba249343e5aaba 100644 --- a/ofdEditor/model/Doc/DocLayer.h +++ b/ofdEditor/model/Doc/DocLayer.h @@ -8,7 +8,6 @@ class DocBlock; // 块 class DocTable; // 表格 -class DocDrawParam; // 默认绘画模式 class DocPassage; // 文章 /** @@ -30,6 +29,8 @@ public: DocPage::Layer getLayer(){return type;} DocPage* getPage(); // 找到层所在的Page DocPassage *getPassage(); // 找到文章 + bool hasBlock(DocBlock* block); // 判断是否包含这个块 + int size(){return this->blocks.size();} // 判断层中包含多少个块 public slots: @@ -39,12 +40,8 @@ void removeBlock(DocBlock* block); // 移除Block void setLayer(DocPage::Layer layer){this->type = layer;} void setPage(DocPage* page); // 设置page - private: QVector blocks; // 块 -文字块图形块的父类 - QVector tables; // 表格 - - DocDrawParam* drawParam; // 该层的默认绘画模式 DocPage::Layer type; // 共三层 DocPage* parent; // 表明此层是哪一个页面的 diff --git a/ofdEditor/model/Doc/DocPage.cpp b/ofdEditor/model/Doc/DocPage.cpp index 4b8bfc0a3b61dc803918676ffdaa14683f3bd36f..9a44f39f23ec1a4e3e14c5f9433275e2f6bf1812 100644 --- a/ofdEditor/model/Doc/DocPage.cpp +++ b/ofdEditor/model/Doc/DocPage.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -28,10 +29,11 @@ // #include "DataTypes/page/CT_PageArea.h" // 页面大小 + DocPage::DocPage(QWidget *parent) - :QGraphicsView(parent) + : QGraphicsView(parent) { - this->setSize(210,297); // 默认A4纸张大小 + //this->setSize(210,297); // 默认A4纸张大小 this->scaleFactor = 1.0; this->init(); @@ -106,6 +108,30 @@ QSize DocPage::getSize() UnitTool::mmToPixel(height_mm)); } +/// +/// \brief DocPage::hasBlock +/// 判断该页面中是否包含某个块 +/// \param block +/// \return +/// +bool DocPage::hasBlock(DocBlock *block) +{ + bool flag = false; + if(this->foregroundLayer->hasBlock(block)) + { + flag = true; + } + if(this->bodyLayer->hasBlock(block)) + { + flag = true; + } + if(this->backgroundLayer->hasBlock(block)) + { + flag = true; + } + return flag; +} + /** * @Author Chaoqun * @brief 获得前景层 @@ -142,6 +168,28 @@ DocLayer *DocPage::getBackgroundLayer() return this->backgroundLayer; } +/// +/// \brief DocPage::getLayer +/// 获得层 +/// \param layer +/// \return +/// +DocLayer *DocPage::getLayer(DocPage::Layer layer) +{ + if(layer == Foreground) + { + return this->foregroundLayer; + } + else if(layer == Body) + { + return this->bodyLayer; + } + else if(layer == Background) + { + return this->backgroundLayer; + } +} + /** * @Author Chaoqun * @brief 添加一个新的块到页面之中 @@ -165,13 +213,14 @@ void DocPage::addBlock(DocBlock *block, DocPage::Layer layer) emit this->signals_insertTextBlock(textBlock); // 发射信号 // 转发信号给passage - connect(textBlock,SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat&)), - passage,SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat&))); - connect(textBlock,SIGNAL(signals_currentCharFormatChanged(QTextCharFormat&)), - passage,SIGNAL(signals_currentCharFormatChanged(QTextCharFormat&))); + connect(textBlock,SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat)), + passage,SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat))); + connect(textBlock,SIGNAL(signals_currentCharFormatChanged(QTextCharFormat)), + passage,SIGNAL(signals_currentCharFormatChanged(QTextCharFormat))); connect(textBlock,SIGNAL(signals_currentTextBlock(DocTextBlock*)), passage,SIGNAL(signals_currentTextBlock(DocTextBlock*))); - } else if (block->isImageBlock()) + } + else if (block->isImageBlock()) { DocImageBlock * imageBlock = block->getImageBlock(); DocPassage * passage = this->getPassage(); @@ -181,6 +230,20 @@ void DocPage::addBlock(DocBlock *block, DocPage::Layer layer) this->connect(imageBlock, SIGNAL(signals_currrentImageBlock(DocImageBlock*)), passage, SIGNAL(signals_currentImageBlock(DocImageBlock*))); } + else if (block->isTableBlock()) + { + DocTable *table = block->getTableBlock(); + DocPassage *passage = this->getPassage(); + + // 之后可以做信号的转发 + connect(table, SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat)), + passage, SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat))); + connect(table, SIGNAL(signals_currentCharFormatChanged(QTextCharFormat)), + passage, SIGNAL(signals_currentCharFormatChanged(QTextCharFormat))); + connect(table ,SIGNAL(signals_currentTable(DocTable*)), + passage, SIGNAL(signals_currentTableBlock(DocTable*))); + + } // qDebug()<< "connect"; // 分到层 @@ -203,6 +266,34 @@ void DocPage::addBlock(DocBlock *block, DocPage::Layer layer) } +/// +/// \brief DocPage::changeBlockLayer +/// \param block +/// \param layer +/// +void DocPage::changeBlockLayer(DocBlock *block, DocPage::Layer layer) +{ + if(!this->hasBlock(block)) + { + // 如果本页中不包含此块 + qDebug() << "this page does not has this block."; + return; + } + + DocLayer *doclayer = block->getLayer(); // 获得层 + if(doclayer == NULL) + { + qDebug() << "This block has no layer"; + return; + } + + DocLayer* goalLayer = this->getLayer(layer); // 目标层 + + doclayer->removeBlock(block); // 从原有层中删除 + goalLayer->addBlock(block); // 加入到目标层中 + +} + /** * @Author Chaoqun * @brief 将item添加到scene中 @@ -236,7 +327,7 @@ QGraphicsProxyWidget *DocPage::addWidget(QWidget *widget, * @return void * @date 2017/05/16 */ -void DocPage::setInsertBlockType(InsertBlockInfo &blockInfo) +void DocPage::setInsertBlockType(InsertBlockInfo blockInfo) { if(this->insertBlockInfo == NULL) { @@ -246,7 +337,7 @@ void DocPage::setInsertBlockType(InsertBlockInfo &blockInfo) this->insertBlockInfo->layer = blockInfo.layer; // 层 this->insertBlockInfo->type = blockInfo.type; // 类型 - // qDebug()<<"Set InsertBlockInfo successfully!"; +// qDebug()<<"Set InsertBlockInfo successfully!"; } /** @@ -262,6 +353,96 @@ void DocPage::remove() passage->removePage(this); } +// 设置页面的显示大小 +void DocPage::setScale(double scale) +{ + // 设置纸张大小 + + this->setFixedSize(scale * this->width(), + scale * this->height()); + +// qDebug() << "Page Size after scale:" << this->width() +// << " " << this->height(); + + // 缩放 + this->scale(scale,scale); + this->viewport()->update(); + this->update(); +} + +/// +/// \brief DocPage::setWorkingArea +/// 设置工作区域 +/// \param isUsingWorkingArea +/// \param contentWidth +/// \param contentHeight +/// \param contentX +/// \param contentY +/// +void DocPage::setWorkingArea( + bool isUsingWorkingArea, + double contentWidth, + double contentHeight, + double contentX, + double contentY) +{ + this->has_working_area = isUsingWorkingArea; + this->working_area_width = contentWidth; + this->working_area_height = contentHeight; + this->working_area_x = contentX; + this->working_area_y = contentY; +} + +void DocPage::insertPageDialog() +{ + +} + +/// +/// \brief DocPage::insertPageBefore +/// 在本页之前插入页面 +/// +void DocPage::insertPageBefore() +{ + int index = this->passage->getLastedActivedPageIndex(); + this->passage->insertPage(NULL,index); +} + +/// +/// \brief DocPage::insertPageAfter +/// 在本页之后插入页面 +/// +void DocPage::insertPageAfter() +{ + int index = this->passage->getLastedActivedPageIndex(); + this->passage->insertPage(NULL,index + 1); +} + +/// +/// \brief DocPage::dialogPageSetting +/// 调用文章的页面设置窗口 +void DocPage::dialogPageSetting() +{ + this->getPassage()->activatePageDialog(); +} + +/// +/// \brief DocPage::setEditedAble +/// \param flag +/// +void DocPage::setEditedAble(bool flag) +{ + if(flag) + { + this->isEditable = flag; + } + else + { + this->isEditable = flag; + this->newBlockFlag = none; + } +} + /** * @Author Chaoqun @@ -280,7 +461,9 @@ void DocPage::paintEvent(QPaintEvent *event) QPainter painter(this->viewport()); // 坑,要画在viewport上 painter.setPen(Qt::blue); - QRectF rect = UnitTool::getBox(this->oldPos,this->newPos); + QRect rect = UnitTool::getBox( + mapFromScene(this->oldPos), + mapFromScene(this->newPos)); painter.drawRect(rect); painter.end(); // 结束 @@ -288,7 +471,30 @@ void DocPage::paintEvent(QPaintEvent *event) // qDebug()<<"Moving QPainter is Drawing"; } -// qDebug()<<"QPainter is Drawing"; + // qDebug()<<"QPainter is Drawing"; +} + +/// +/// \brief DocPage::contextMenuEvent +/// 实现右键菜单 +/// \param event +/// +void DocPage::contextMenuEvent(QContextMenuEvent *event) +{ + // event->globalPos() 是相对于屏幕的 + // event->pos() 相对于页面左上角 +// QMenu* menu = new QMenu(this->passage); // 让passage作为父亲 + + if(!this->isEditable) + return; + + QPoint pos = event->pos(); // 获得相对于页面的 + QList items = this->items(pos); // 获得某鼠标下的所有块 + QMenu *menu = this->getMenu(items); + this->oldPos = pos; // 记录鼠标位置 + + menu->exec(event->globalPos()); // 执行菜单 + } /** @@ -300,6 +506,8 @@ void DocPage::paintEvent(QPaintEvent *event) */ void DocPage::mouseDoubleClickEvent(QMouseEvent *event) { + if(!this->isEditable) + return; QGraphicsView::mouseDoubleClickEvent(event); } @@ -312,6 +520,10 @@ void DocPage::mouseDoubleClickEvent(QMouseEvent *event) */ void DocPage::mousePressEvent(QMouseEvent *event) { +// qDebug() << "mouse Press"; + + if(!this->isEditable) + return; // 如果是加入新块状态 if(this->newBlockFlag == draw) @@ -333,25 +545,17 @@ void DocPage::mousePressEvent(QMouseEvent *event) if( items.size()> 0) { QGraphicsItem* tempItem = items[0]; - - // 不清楚为什么,造型函数在这里编译出错,因此我采取了强制类型转换 -// DocBlock * block = qobject_cast(tempItem); - DocBlock * block = (DocBlock *)tempItem; - + DocBlock* block = qgraphicsitem_cast(tempItem); if(block != NULL) { this->activeBlock = block; // 存下 block QPointF tempPoint = this->mapToScene(this->oldPos.rx(), this->oldPos.ry()); -// qDebug() <<"temp Point"<currentStatus( - block->mapFromScene(tempPoint)) - == DocBlock::blockMove) + if(block->cursor().shape() == Qt::SizeAllCursor) { -// qDebug()<<" Accepted Signal is blockMove"; +// qDebug()<<" the cursor'shape is size all "; this->newBlockFlag = blockMove; } else if (block->currentStatus( @@ -378,8 +582,6 @@ void DocPage::mousePressEvent(QMouseEvent *event) // qDebug() << "items.size:" <isEditable) + return; + QGraphicsView::mouseMoveEvent(event); if(this->newBlockFlag == drawMove) @@ -416,6 +621,8 @@ void DocPage::mouseMoveEvent(QMouseEvent *event) } QPointF point = this->newPos - this->oldPos; +// qDebug() << "Move x:" << point.rx() +// << " y:" << point.ry(); this->activeBlock->moveBy(point.rx(),point.ry()); this->oldPos = this->mapToScene(event->pos()); @@ -430,12 +637,13 @@ void DocPage::mouseMoveEvent(QMouseEvent *event) this->newPos = this->mapToScene(event->pos()); QPointF point = this->newPos - this->oldPos; if (!image_block->isWidthHeightRatioLocked()) + // 如果纵横比未锁定 this->activeBlock->resize(point.rx(),point.ry()); else { + // 如果纵横比锁定 double ratio = image_block->getWidthHeightRatio(); - if(point.rx() < - point.ry() * ratio) + if(point.rx() < point.ry() * ratio) this->activeBlock->resize(point.rx(), point.rx() / ratio); else this->activeBlock->resize(point.ry() * ratio, point.ry()); @@ -452,6 +660,9 @@ void DocPage::mouseMoveEvent(QMouseEvent *event) */ void DocPage::mouseReleaseEvent(QMouseEvent *event) { + if(!this->isEditable) + return; + if(this->newBlockFlag == drawMove) { @@ -491,6 +702,27 @@ void DocPage::mouseReleaseEvent(QMouseEvent *event) QGraphicsView::mouseReleaseEvent(event); } +/// +/// \brief DocPage::focusInEvent +/// When this page been focused ,we will emit a message +/// \param event +/// +void DocPage::focusInEvent(QFocusEvent *event) +{ + if(this->isEditable) + { + QGraphicsView::focusInEvent(event); + } + + emit signals_page_actived(this); +} + +void DocPage::focusOutEvent(QFocusEvent *event) +{ + if(this->isEditable) + QGraphicsView::focusOutEvent(event); +} + /** * @Author Chaoqun @@ -499,6 +731,8 @@ void DocPage::mouseReleaseEvent(QMouseEvent *event) */ void DocPage::init() { + this->isEditable = true; // 是否可以编辑 + this->setWindowFlags(Qt::Widget); this->docScene = new DocPageScene(); // 新建 @@ -507,8 +741,6 @@ void DocPage::init() this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - // 新建三个层 this->foregroundLayer = new DocLayer(Foreground); this->foregroundLayer->setPage(this); @@ -525,14 +757,142 @@ void DocPage::init() // this->setBackgroundRole(QPalette::Dark); this->insertBlockInfo = NULL; this->activeBlock = NULL; + + has_working_area = false; + working_area_width = this->size().width(); + working_area_height = this->size().height(); + working_area_x = working_area_y = 0; + + this->initMenu(); // 初始化菜单 +} + +/// +/// \brief DocPage::initMenu +/// +void DocPage::initMenu() +{ + this->menu_main = new QMenu(tr("Main")); + this->menu_insert = new QMenu(tr("Insert")); + + // 插入文本框 + this->action_insertTextBlock = new QAction(tr("TextBlock"), this); + + // 插入图片 + this->action_insertImageBlock = new QAction(tr("ImageBlock"), this); + this->connect(action_insertImageBlock, SIGNAL(triggered(bool)), + this, SLOT(addImage())); + + // 插入表格 + this->action_insertTable = new QAction(tr("Table"), this); + this->connect(action_insertTable, SIGNAL(triggered(bool)), + this, SLOT(addTable())); + + // 插入页 + this->menu_insertPage = new QMenu(tr("Page")); + this->action_insertPage = new QAction(tr("Setting"), this); + this->action_insertPageBefore = new QAction(tr("Before"), this); + this->action_insertPageAfter = new QAction(tr("After"), this); + + this->menu_insertPage->addAction(this->action_insertPageAfter); + this->menu_insertPage->addAction(this->action_insertPageBefore); + this->menu_insertPage->addAction(this->action_insertPage); + + //删除本页 + this->action_deletePage = new QAction(tr("Delete This Page"), this); + + // 页面设置 + this->action_pageSetting = new QAction(tr("Page Setting"), this); + + this->menu_insert->addAction(this->action_insertTextBlock); + this->menu_insert->addAction(this->action_insertImageBlock); + this->menu_insert->addAction(this->action_insertTable); +// this->menu_insert->addAction(this->action_insertPage); + this->menu_insert->addMenu(this->menu_insertPage); + + + // 在本页之前插入 + connect(this->action_insertPageBefore, SIGNAL(triggered(bool)), + this, SLOT(insertPageBefore())); + // 在本页之后插入 + connect(this->action_insertPageAfter, SIGNAL(triggered(bool)), + this, SLOT(insertPageAfter())); + // 删除本页 + connect(this->action_deletePage, SIGNAL(triggered(bool)), + this, SLOT(remove())); + // 页面设置 + connect(this->action_pageSetting, SIGNAL(triggered(bool)), + this, SLOT(dialogPageSetting())); + +} + +/// +/// \brief DocPage::getMenu +/// 根绝获得的物体生成菜单 +/// \param items +/// \return +/// +QMenu *DocPage::getMenu(QList &items) +{ + // 三种情况 + // 无元素、一个元素、多个元素 + int size = items.size(); // 鼠标下总共多少个元素 + QMenu *menu = this->menu_main; + menu->clear(); + + if(size == 0) + { + menu->addMenu(this->menu_insert); + menu->addAction(this->action_deletePage); + menu->addAction(this->action_pageSetting); + } + else if(size == 1) + { + + if(items[0]->type() == DocBlock::Type) + { + DocBlock* block = qgraphicsitem_cast(items[0]); + if(block != NULL) + { + menu = block->getMenu(); + } + } + + menu->addSeparator(); + menu->addMenu(this->menu_insert); + menu->addAction(this->action_deletePage); + menu->addAction(this->action_pageSetting); + } + else if(size > 1) + { + + for(int i = 0; i < items.size(); i++) + { + // 将qgraphicsItem造型成为DocBlock + if(items[i]->type() == DocBlock::Type) + { + // 向下造型 + DocBlock* block = qgraphicsitem_cast(items[i]); + QMenu* tempMenu = block->getMenu(); + menu->addMenu(tempMenu); + } + } + + menu->addSeparator(); + menu->addMenu(this->menu_insert); + menu->addAction(this->action_deletePage); + menu->addAction(this->action_pageSetting); + } + + return menu; + } void DocPage::addImage() { - //qDebug() << "???"; +// qDebug() << "Open a QDialog and load an img"; //打开对话框,选取一个图片文件 QString fileName = QFileDialog::getOpenFileName(this, - tr("Open File"), QDir::currentPath()); + tr("Open File"), QDir::homePath()); if (!fileName.isEmpty()) { QPixmap image(fileName); if (image.isNull()) { @@ -540,28 +900,62 @@ void DocPage::addImage() tr("Cannot open file %1.").arg(fileName)); return; } + //新建一个DocBlock DocBlock * newBlock = new DocBlock(); //新建一个图片框 DocImageBlock * new_image_block = new DocImageBlock(); newBlock->setWidget(new_image_block); - new_image_block->setImage(image); + new_image_block->setImage(image); // 设置图片 double page_width = this->width(), page_height = this->height(); -// qDebug() << "Page Width: " << this->width(); -// qDebug() << "Page Height: " << this->height(); -// qDebug() << "Image Width: " << image.width(); -// qDebug() << "Image Height: " << image.height(); + double ratio; if (image.width() > page_width || image.height() > page_height) { - ratio = std::min(page_width / image.width(), page_height / image.height()); + ratio = std::min( + page_width / image.width(), + page_height / image.height()); ratio *= 0.8; } else ratio = 1.0; - qDebug() << "Ratio = " << ratio; - newBlock->setPos((page_width - image.width() * ratio) / 2, (page_height - image.height() * ratio) / 2); - newBlock->resize(image.width() * ratio,image.height() * ratio); + +// qDebug() << "Ratio = " << ratio; + newBlock->setPos( + (page_width - image.width() * ratio) / 2, + (page_height - image.height() * ratio) / 2); + + newBlock->resize( + image.width() * ratio, + image.height() * ratio); this->addBlock(newBlock,this->insertBlockInfo->layer); } } + +/// +/// \brief DocPage::addTable +/// 在屏幕中央,插入一个由对话框大小的表格 +/// +void DocPage::addTable() +{ + qDebug() << "insert Table"; + // 暂时做测试,新建默认大小的表格 + DocTable * _table = new DocTable(); + DocBlock * newBlock = new DocBlock(); + newBlock->setWidget(_table); + + double page_width = this->width(), page_height = this->height(); + + double ratio = 1; + double table_width = page_width * 0.8; + double table_height = table_width; + + newBlock->setPos( + (page_width - table_width)/2, + (page_height - table_height)/2 ); + newBlock->resize( + table_width * ratio, + table_height * ratio); + + this->addBlock(newBlock, this->insertBlockInfo->layer); +} diff --git a/ofdEditor/model/Doc/DocPage.h b/ofdEditor/model/Doc/DocPage.h index 2b219e9779018b0a4859570fb1c5ef4ec3d0a4f8..00f80ddf421cf7cbd63ade9c5b1c36bf2702fc20 100644 --- a/ofdEditor/model/Doc/DocPage.h +++ b/ofdEditor/model/Doc/DocPage.h @@ -8,6 +8,7 @@ #include #include #include +#include // 类声明 class DocLayer; @@ -28,10 +29,10 @@ class MODELSHARED_EXPORT DocPage { Q_OBJECT public: + enum Layer{Body,Foreground,Background}; // 分为三层 - enum BlockFlag{none,draw,drawMove,blockMove, blockResize}; // 插入时的绘制状态 + enum BlockFlag{none,draw,drawMove,blockMove, blockResize}; // 插入时的绘制状态 enum BlockType{text,image,table}; // 插入时的类型 - explicit DocPage(QWidget * parent = 0); DocPage(double width, double height, double scaleFactor,QWidget * parent = 0); @@ -43,38 +44,64 @@ public: double getHeight(){return height_mm;} // 返回毫米单位高度 BlockFlag getBlockFlag(){return this->newBlockFlag;} + bool hasBlock(DocBlock* block); // 页面中是否有某个块 DocLayer *getForegroundLayer(); // 获得前景层 DocLayer* getBodyLayer(); // 获得正文层 - DocLayer* getBackgroundLayer(); // 获得背景层 + DocLayer* getBackgroundLayer(); // 获得背景层 + DocLayer *getLayer(DocPage::Layer layer); // 获得层 + bool getEditable(){return this->isEditable;} + - //Pan - void addImage(); + bool isUsingWorkArea(){return this->has_working_area;} + double getContentWidth(){return this->working_area_width;} + double getContentHeight(){return this->working_area_height;} + double getContentX(){return this->working_area_x;} + double getContentY(){return this->working_area_y;} public slots: - void setSize(double width, double height); // 设置页面大小 - void setPassage(DocPassage * passage); // 设置文章 - void addBlock(DocBlock* block, DocPage::Layer layer); // 为页面添加一个新元素 -// void addBlock(DocTextBlock* textBlock, DocPage::Layer layer); // 为页面添加一个新元素 + void setSize(double width, double height); // 设置页面大小 + void setPassage(DocPassage * passage); // 设置文章 + void addBlock(DocBlock* block, DocPage::Layer layer); // 为页面添加一个新元素 + void addImage(); //添加图片 + void addTable(); // 用对话框来设置插入表格的大小 + void changeBlockLayer(DocBlock* block, DocPage::Layer layer); // 更换block的层 void addItem(QGraphicsItem *item); // 拓展接口 QGraphicsProxyWidget *addWidget(QWidget *widget, Qt::WindowFlags wFlags = Qt::WindowFlags()); void setBlockFlag(BlockFlag flag){this->newBlockFlag = flag;} - void setInsertBlockType(InsertBlockInfo& blockInfo); // 设置下一个要插入的block的信息 - void remove(); // 移除本页 + void setInsertBlockType(InsertBlockInfo blockInfo); // 设置下一个要插入的block的信息 + void remove(); // 移除本页 + void setScale(double scale); // 设置页面的显示大小 + void setWorkingArea( + bool isUsingWorkingArea, + double contentWidth, + double contentHeight, + double contentX, + double contentY); // 设置工作区域 + void insertPageDialog(); // 插入页面 + void insertPageBefore(); // 在本页之前插入页面 + void insertPageAfter(); // 在本页之后插入页面 + void dialogPageSetting(); // 页面设置窗口 + void setEditedAble(bool flag); // 设置是否可以编辑 + protected: void paintEvent(QPaintEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event) ; - void mousePressEvent(QMouseEvent *event) ; - void mouseMoveEvent(QMouseEvent *event) ; - void mouseReleaseEvent(QMouseEvent *event) ; + void contextMenuEvent(QContextMenuEvent *event); // 右键菜单 + void mouseDoubleClickEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void focusInEvent(QFocusEvent *event); + void focusOutEvent(QFocusEvent *event); private: void init(); // 初始化UI + void initMenu(); // 初始化一些自有的菜单 DocPassage * passage; // 页所属文章 DocPageScene* docScene; // 场景数据 @@ -83,6 +110,7 @@ private: DocLayer* backgroundLayer; // 背景层 InsertBlockInfo * insertBlockInfo; // 下一个插入的Block的类型 + QMenu *getMenu(QList& items); // 根据获得的物体生成菜单 // 还应该有模板页 //CT_PageArea* area; // 页面大小描述 @@ -97,11 +125,40 @@ private: BlockFlag newBlockFlag; // 是否画块 DocBlock * activeBlock; // 正在活跃的那个DocBlock + // QActions + QMenu *menu_main; // 菜单 + QMenu *menu_insert; // 菜单 + QMenu *menu_insertPage; // 插入页 + + QAction *action_insertTextBlock; // 插入文本框 + QAction *action_insertImageBlock; // 插入图片框 + QAction *action_insertTable; // 插入表格 + QAction *action_insertPage; // 插入页 + QAction *action_insertPageBefore; // 在本页之前插入页面 + QAction *action_insertPageAfter; // 在本页之后插入页面 + + QAction *action_deletePage; // 删除本页 + QAction *action_pageSetting; // 页面设置 + + // 是否可以编辑 + bool isEditable; + + + // 页面设置 + bool has_working_area; + double working_area_width; + double working_area_height; + double working_area_x; + double working_area_y; + + signals: // 信号 void signals_insertTextBlock(DocTextBlock* textBlock ); // 插入文本框信号 void signals_removeTextBlock(DocTextBlock* textBlock ); // 移除文本框信号 - + void has_focused_page(); + void has_no_focused_page(); + void signals_page_actived(DocPage* page); // 本页面被激活信号 }; diff --git a/ofdEditor/model/Doc/DocParaStyle.cpp b/ofdEditor/model/Doc/DocParaStyle.cpp deleted file mode 100644 index c1638e4f190de2ac65282e16a140ebb68a841671..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocParaStyle.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "DocParaStyle.h" -#include "Doc/DocImageBlock.h" - - -DocParaStyle::DocParaStyle() -{ - -} - -DocParaStyle::~DocParaStyle() -{ - -} diff --git a/ofdEditor/model/Doc/DocParaStyle.h b/ofdEditor/model/Doc/DocParaStyle.h deleted file mode 100644 index 8b63fa94c10ece7629fc01678ec6e7d9508d7822..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocParaStyle.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef DOCPARASTYLE_H -#define DOCPARASTYLE_H - -class DocImage; - - -class DocParaStyle -{ -public: - DocParaStyle(); - ~DocParaStyle(); -private: - double spaceAbove; // 段前间距 - double spaceBelow; // 段后间距 - - double indentFirstLine; // 首行缩进多少字符 - - double deltaLineSpace; // 行距 -- 和字体有关是一行高度的比例 - double fixedLineSpace; // 固定行距 -- 和字体无关,用毫米表示 - int LineSpaceType; // 0-deltaLineSpace - // 1-fixedlineSpace - - DocImage *background; // 段落可能需要背景颜色花纹等 - - // 大纲级别 -- 用来做大纲 - - enum ParaAlign{Left,Centered,Right,Fullness}; - // 段落缩进,居左,居中,居右,撑满 - ParaAlign alignment; - -}; - -#endif // DOCPARASTYLE_H diff --git a/ofdEditor/model/Doc/DocParagraph.cpp b/ofdEditor/model/Doc/DocParagraph.cpp deleted file mode 100644 index b35cdc975a4eb790c8b07fb3290b58987e75506f..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocParagraph.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "DocParagraph.h" - -DocParagraph::DocParagraph() -{ - -} diff --git a/ofdEditor/model/Doc/DocParagraph.h b/ofdEditor/model/Doc/DocParagraph.h deleted file mode 100644 index 4dd38fcd2d46dd6905ceb8f4387790df1a54b731..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocParagraph.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef PARAGRAPH_H -#define PARAGRAPH_H - -#include "model_global.h" -#include - -class DocText; // 文字小段 - -class DocParaStyle; // 段落的样式 - -class MODELSHARED_EXPORT DocParagraph -{ -public: - DocParagraph(); -private: - DocParaStyle* paraStyle; // 段落的样式 - QVector texts; // 段落中的字体一致的几个文字 - -}; - -#endif // PARAGRAPH_H diff --git a/ofdEditor/model/Doc/DocPassage.cpp b/ofdEditor/model/Doc/DocPassage.cpp index 66e39e58bfefb6b3460770157d2eef12c8837bf6..ed750ed1ad5de0a5717072c6273158cc372a41b1 100644 --- a/ofdEditor/model/Doc/DocPassage.cpp +++ b/ofdEditor/model/Doc/DocPassage.cpp @@ -3,14 +3,43 @@ #include "DocPage.h" #include "DataTypes/document/CT_DocInfo.h" #include "DataTypes/document/ct_commondata.h" - +#include "Widget/PageDialog.h" +#include "Core/GlobalSetting.h" #include +#include #include #include #include #include #include #include +#include +#include "Doc/DocTable.h" +#include "Doc/DocTextBlock.h" +#include "Doc/DocImageBlock.h" + +/// +/// \brief DocPassage::createNewPassage +/// 创建一个新的文章 +/// \return 新的文章 +/// +DocPassage *DocPassage::createNewPassage() +{ + DocPassage* passage = new DocPassage(0); + return passage; +} + +/// +/// \brief DocPassage::createEmptyPassage +/// 创建一个新的文章,空的,用来进行读取已有文章 +/// \return +/// +DocPassage *DocPassage::createEmptyPassage() +{ + DocPassage* passage = new DocPassage(); + return passage; +} + /** * @Author Chaoqun @@ -18,64 +47,36 @@ * @date 2017/04/30 */ DocPassage::DocPassage(QWidget *parent) - :docType("OFD"),version("1.0"),QScrollArea(parent) + :QScrollArea(parent) { - undoStack=new QUndoStack(this); - this->scaleFactor = 1.0; // 缩放100% - this->docInfo = new CT_DocInfo(); // 文档元信息 -// this->commonData = new CT_CommonData(); - this->init(); // 初始化界面 + this->undoStack=new QUndoStack(this); // 用来来存储操作队列 + this->docInfo = new CT_DocInfo(); // 文档元信息 + this->initUI(); // 初始化界面 + this->initDocInfo(); // 初始化文章信息 // this->addPage(new DocPage()); // 添加一个空白页面 setAttribute(Qt::WA_DeleteOnClose); - + // qDebug() << "DocPassage Constructor Finished."; + this->isEdited = false; } -/** - * @Author Chaoqun - * @brief 含参构造函数 - * @date 2017/05/01 - */ -DocPassage::DocPassage(QWidget *parent, - QString version, QString docType, double scaleFactor) - :QScrollArea(parent) +/// +/// \brief DocPassage::DocPassage +/// 空的构造函数,用来创建空的文章 +DocPassage::DocPassage() + :QScrollArea(0) { - undoStack=new QUndoStack(this); - this->version = version; - this->docType = docType; - this->scaleFactor = scaleFactor; + this->undoStack = new QUndoStack(this); // 撤销恢复队列 + this->docInfo = new CT_DocInfo(); // 新建文章信息 + this->initUI(); // 初始化界面 + this->initDocInfo(); + this->isEdited = false; + } DocPassage::~DocPassage() { - // 释放根节点内容 -// if(this->docInfo != NULL) -// { -// delete this->docInfo; -// this->docInfo = NULL; -// } - - // 释放公共数据 -// if(this->commonData != NULL) -// { -// delete this->commonData; -// this->commonData = NULL; -// } - -// 释放this->pages -// int pages_length = this->pages.size(); -// for(int i = 0; i < pages_length; i++) -// { -// // 需要挨个释放内存空间 -// DocPage* temp = this->pages.at(i); -// if(temp != NULL) -// { -// delete temp; -// (this->pages)[i] = NULL; -// } -// } -// this->pages.clear(); } @@ -90,22 +91,40 @@ void DocPassage::addPage(DocPage *page) { if(page == NULL) { - qDebug() << "DocPassage::addPage(DocPage* page) " - << "You have add a NULL pointer"; +// qDebug() << "DocPassage::addPage(DocPage* page) " +// << "You have add a NULL pointer"; return; } // 先添加到 vector + page->setSize(default_width, default_height); +// qDebug() << "!!Page width in pixel = " << page->size().width() +// << "!!Page height in pixel = " << page->size().height(); + page->setWorkingArea( + default_using_working_area, + default_working_width, + default_working_height, + default_working_x, + default_working_y); + this->pages.append(page); // 添加到ScrollArea - this->adjustWidgetSize(); // 调整大小 this->layout->addWidget(page,0,Qt::AlignCenter); - // 向layout中增加一页,并居中显示 + // 向layout中增加一页,并居中显示 + + // 接收当前操作页面的更新 + this->connect(page, SIGNAL(signals_page_actived(DocPage*)), + this, SLOT(setCurrentActivedPage(DocPage*))); + + this->connect(this, SIGNAL(signals_setEditable(bool)), + page, SLOT(setEditedAble(bool))); + this->layout->update(); // 更新 page->setPassage(this); // 设置页所属的文章 + page->setScale(this->scaleFactor); + this->adjustWidgetSize(); // 调整大小 - - qDebug() << "You have added an new page"; +// qDebug() << "You have added an new page"; } @@ -139,6 +158,72 @@ void DocPassage::appendNewPage(DocPage *page) this->addPage(page); // 此处调用addPage } +/// +/// \brief DocPassage::insertPage +/// \param page 页面 +/// \param index 插入的位置 +/// +void DocPassage::insertPage(DocPage *page, int index) +{ + if(page == NULL) + { + qDebug() << "page is null"; + page = new DocPage(); + } + + page->setSize(default_width, default_height); + page->setWorkingArea( + default_using_working_area, + default_working_width, + default_working_height, + default_working_x, + default_working_y); + int pos = -1; + + // 插入位置 + if(index >= this->pages.size()) + { + // 插入到最后一位 + pos = this->layout->indexOf( + this->pages.operator [](this->pages.size()-1)); + pos ++; + + this->pages.append(page); + + } + else if(index < 0) + { + // 插入到第一位 + pos = this->layout->indexOf( + this->pages.operator [](0)); + + this->pages.insert(0, page); + + } + else + { + pos = this->layout->indexOf( + this->pages.operator [](index)); + + this->pages.insert(index, page); + } + + this->layout->insertWidget(pos, page, 0, Qt::AlignCenter); + + this->connect(page, SIGNAL(signals_page_actived(DocPage*)), + this, SLOT(setCurrentActivedPage(DocPage*))); + + this->connect(this, SIGNAL(signals_setEditable(bool)), + page, SLOT(setEditedAble(bool))); + + this->layout->update(); + page->setPassage(this); + + page->setScale(this->scaleFactor); // 调整到合适的缩放比例 + this->adjustWidgetSize(); + +} + /** * @Author Chaoqun * @brief 移除指定的页 @@ -166,7 +251,7 @@ void DocPassage::removePage(DocPage *page) // qDebug()<<"pages size" << this->pages.size(); this->layout->removeWidget(page); // 从场景中移除页面 - page->deleteLater(); // 移除页面 +// page->deleteLater(); // 移除页面 this->pages.remove(index); // 从数据中移除页面 // qDebug()<<"pages size" << this->pages.size(); @@ -176,6 +261,18 @@ void DocPassage::removePage(DocPage *page) } +/** + * @Author Chaoqun + * @brief 设置文件路径 + * @param QString filePath + * @return void + * @date 2017/06/26 + */ +void DocPassage::setFilePath(QString filePath) +{ + this->filePath = filePath; +} + /** * @Author Chaoqun * @brief 设置文档原信息 @@ -186,6 +283,7 @@ void DocPassage::removePage(DocPage *page) void DocPassage::setDocInfo(CT_DocInfo &docInfo) { this->docInfo->copy(docInfo); + this->setWindowTitle(this->docInfo->getTitle()); // 设置小窗口标题 } /** @@ -197,7 +295,7 @@ void DocPassage::setDocInfo(CT_DocInfo &docInfo) */ void DocPassage::testMessage() { - qDebug()<<"passage success"; + qDebug()<<"passage success "; } /** @@ -212,6 +310,57 @@ CT_DocInfo *DocPassage::getDocInfo() return this->docInfo; } +/** + * @Author Chaoqun + * @brief 获得文章的uuid + * @param void + * @return QString& + * @date 2017/06/xx + */ +QString DocPassage::getUUID() +{ + return this->docInfo->getDocID(); +} + +/** + * @Author Chaoqun + * @brief 获得用来存储文档时的临时路径 + * @param void + * @return QString + * @date 2017/06/26 + */ +QString DocPassage::getTempSavePath() +{ + QString temp = QDir::tempPath() + "/"; // 获得系统临时路径 + QString uuid = this->getUUID(); // 获得uuid + QString end = "_source"; + + QDir dir(temp + uuid + end); + if(!dir.exists()) + { + dir.mkpath(temp + uuid + end); + } + + return temp + uuid + end; // 获得临时存放路径 +} + +/** + * @Author Chaoqun + * @brief 临时存储路劲 + * @param void + * @return QString + * @date 2017/06/26 + */ +QString DocPassage::getTempStorePath() +{ + QString temp = QDir::tempPath() + "/"; // 获得系统临时路径 + QString uuid = this->getUUID(); // 获得uuid + QString end = "_file"; + + + return temp + uuid + end; // 获得临时存放路径 +} + /** * @Author Chaoqun * @brief 获得文档中所有的页面 @@ -219,9 +368,9 @@ CT_DocInfo *DocPassage::getDocInfo() * @return 返回值 * @date 2017/06/20 */ -QVector &DocPassage::getPages() +QVector *DocPassage::getPages() { - return this->pages; + return &this->pages; } /** @@ -236,6 +385,49 @@ DocPage *DocPassage::getPage(int index) return this->pages[index]; } +/** + * @Author Chaoqun + * @brief 摘要 + * @param 参数 + * @return 返回值 + * @date 2017/06/26 + */ +QString DocPassage::getFilePath() +{ + // 获得文件路径 + return this->filePath; +} + +/// +/// \brief DocPassage::getLastedActivedPage +/// 获得最近更新的页面 +/// \return +/// +DocPage *DocPassage::getLastedActivedPage() +{ + return _lastActivedPage; +} + +/// +/// \brief DocPassage::getLastedActivedPageIndex +/// \return +/// +int DocPassage::getLastedActivedPageIndex() +{ + return this->pages.indexOf(this->_lastActivedPage); +} + +/// +/// \brief DocPassage::getPageIndex +/// \param page +/// \return +/// +int DocPassage::getPageIndex(DocPage *page) +{ + int index = this->pages.indexOf(page); // 查找页的序号 + return index; +} + /** * @Author Chaoqun * @brief 设置CommonData,深拷贝 @@ -280,7 +472,7 @@ void DocPassage::resetDocId() docId.remove(docId.length() -21, 1); docId.remove(docId.length() - 25,1); docId.remove(0,1); - qDebug() << "uuid : " << docId; +// qDebug() << "uuid : " << docId; this->docInfo->setDocID(docId); } @@ -295,7 +487,8 @@ void DocPassage::resetDocId() void DocPassage::resizeEvent(QResizeEvent *event) { this->adjustWidgetSize(); // 调整整体大小 - qDebug() << "DocPassage::resizeEvent Runs"; + QScrollArea::resizeEvent(event); +// qDebug() << "DocPassage::resizeEvent Runs"; } /** @@ -308,38 +501,78 @@ void DocPassage::resizeEvent(QResizeEvent *event) void DocPassage::closeEvent(QCloseEvent *event) { QScrollArea::closeEvent(event); + qDebug() << "passage close request"; } -void DocPassage::init() +/// +/// \brief DocPassage::initUI +/// 与界面有关的初始化 +/// +void DocPassage::initUI() { - this->docInfo = new CT_DocInfo(); // 新建文档 元信息 - this->resetDocId(); // 设置UUID - this->layout = new QVBoxLayout; // 新建布局 + + this->marginWhite = 50; // 边缘留下50像素的留白 + this->spacingWhite = 50; // 纸张之间留下的留白 + + this->layout = new QVBoxLayout; // 新建布局 + this->layout->setMargin(this->marginWhite); // 边缘留至少50的空白 + this->layout->setSpacing(this->spacingWhite); // 纸张之间留下50像素的留白 + this->layout->setAlignment(Qt::AlignHCenter); // 纸张自动居中排列 // 新增widget - this->widget = new QWidget(this); + this->widget = new QWidget(); // 中间文档显示区域 this->widget->setLayout(this->layout); this->widget->setVisible(true); - this->widget->setBackgroundRole(QPalette::Dark); // 背景 + this->widget->setBackgroundRole(QPalette::Dark); // widget 背景 this->widget->setAutoFillBackground(true); - + this->setWidgetResizable(true); // 设置ScrollArea 可以影响到内部纸张 this->setWidget(this->widget); // 设置内置widget - this->setBackgroundRole(QPalette::Dark); // 背景 + this->setBackgroundRole(QPalette::Dark); // ScrollArea 的背景 + this->setAlignment(Qt::AlignHCenter); // ScrollArea 设置位置水平居中 - this->horizontalWhite = 100; // 文章两侧黑边 - this->verticalWhite = 50; // 文章之间黑边 - this->setAlignment(Qt::AlignHCenter); // 设置位置水平居中 + this->scaleFactor = 1.0; // 放大缩小比例 // 设置滚动条策略 this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); this->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - adjustScrollBarRange(); // 调整进度条长度 + adjustScrollBarRange(); // 调整进度条长度 // 设置滚动条位置 adjustScrollBar(this->horizontalScrollBar(), 1); adjustScrollBar(this->verticalScrollBar(),1); +// qDebug() << "Finished Initializing DocPassage..."; + GlobalSetting* global = GlobalSetting::getInstance(); + default_width = global->getPhysicalWidth(); //默认宽度 + default_height = global->getPhysicalHeight(); //默认高度 + default_using_working_area = false; + default_working_width = global->getContentWidth(); + default_working_height = global->getContentHeight(); + default_working_x = global->getContentX(); + default_working_y = global->getContentY(); + +} + +/// +/// \brief DocPassage::initDocInfo +/// 用来初始化文档相关的信息 +/// +void DocPassage::initDocInfo() +{ + this->docInfo = new CT_DocInfo(); // 新建文档 元信息 + this->resetDocId(); // 设置UUID + + GlobalSetting* globalSetting = GlobalSetting::getInstance(); + this->docInfo->setCreator(globalSetting->getCreator()); + this->docInfo->setCreatorVersion(globalSetting->getCreatorVersion()); + + this->docType = globalSetting->getDocType(); + this->version = globalSetting->getDocVersion(); + + QDateTime time = QDateTime::currentDateTime(); // 获得系统当前时间 + this->docInfo->setCreationDate( time.toString("yyyy-MM-dd")); + } /** @@ -355,6 +588,7 @@ void DocPassage::adjustScrollBar(QScrollBar *scrollBar, double factor) // 设置滚动条位置 scrollBar->setValue(int(factor * scrollBar->value() + ((factor -1) * scrollBar->pageStep()/2)) + 1); + scrollBar->update(); } void DocPassage::adjustScrollBarRange() @@ -362,7 +596,6 @@ void DocPassage::adjustScrollBarRange() QSize areaSize = this->viewport()->size(); // 视窗大小 QSize widgetSize = this->widget->size(); // 面板大小 - this->horizontalScrollBar()->setPageStep(areaSize.width()); this->horizontalScrollBar()->setRange(0,widgetSize.width() - areaSize.width()); @@ -371,6 +604,8 @@ void DocPassage::adjustScrollBarRange() this->verticalScrollBar()->setRange(0,widgetSize.height() - areaSize.height()); + this->horizontalScrollBar()->update(); + this->verticalScrollBar()->update(); } @@ -382,40 +617,192 @@ void DocPassage::adjustScrollBarRange() */ void DocPassage::adjustWidgetSize() { - // 计算页面大小 - int width = 0; - int height = 0; - int length = this->pages.size(); - for(int i = 0; i update(); + this->viewport()->update(); + this->QScrollArea::update(); + + adjustScrollBarRange(); // 调整进度条长度 + + // 调整滚动条位置 + adjustScrollBar(this->horizontalScrollBar(), this->scaleFactor); + adjustScrollBar(this->verticalScrollBar(), this->scaleFactor); + +} + +void DocPassage::setDefaultPageSize(double default_width, double default_height) +{ + this->default_width = default_width; + this->default_height = default_height; +} + +void DocPassage::activatePageDialog() +{ + + if( this->_lastActivedPage!= NULL) { - if(width < this->pages[i]->getSize().width()) - { - width = this->pages[i]->getSize().width(); - } - height += verticalWhite + this->pages[i]->getSize().height(); + PageDialog* page_dialog = PageDialog::getInstance(); + + page_dialog->init( + this, + this->_lastActivedPage, + default_width, + default_height, + default_using_working_area, + default_working_width, + default_working_height, + default_working_x, + default_working_y); + + page_dialog->exec(); + } + else + { + qDebug() << "You should have clicked at least one page"; } - height += verticalWhite; - width += 2*horizontalWhite; +} -// this->widget->setMinimumSize(width, height); // 设置内容大小 - this->widget->resize(width,height); +/// +/// \brief DocPassage::modifyPageSize +/// 修改指定页面的尺寸 +/// \param choosed_pages +/// \param _width +/// \param _height +/// \param isUsingWorkingArea +/// \param contentWidth +/// \param contentHeight +/// \param contentX +/// \param contentY +/// +void DocPassage::modifyPageSize( + QVector *ch_pages, + double _width, + double _height, + bool isUsingWorkingArea, + double contentWidth, + double contentHeight, + double contentX, + double contentY) +{ - // 保存计算结果 - this->widgetWidth = width; - this->widgetHeight = height; - this->QScrollArea::update(); + qDebug() << "modifyPageSize"; + DocPage * temp_page; // 临时变量使用的页面 + for (int i = 0; i < ch_pages->size(); i++) { + temp_page = this->pages[ch_pages->operator [](i) - 1]; + temp_page->setSize(_width, _height); + temp_page->setWorkingArea(isUsingWorkingArea, + contentWidth, + contentHeight, + contentX, + contentY); + } - adjustScrollBarRange(); // 调整进度条长度 + this->adjustWidgetSize(); // 更新尺寸 +} - // 调整滚动条位置 - adjustScrollBar(this->horizontalScrollBar(), this->scaleFactor); - adjustScrollBar(this->verticalScrollBar(), this->scaleFactor); +/// +/// \brief DocPassage::modifyDefaultPageSize +/// 修改默认新增加页面时的尺寸 +/// \param default_width +/// \param default_height +/// \param default_isUsingWorkingArea +/// \param default_contentWidth +/// \param default_contentHeight +/// \param default_contentX +/// \param default_contentY +/// +void DocPassage::modifyDefaultPageSize( + double default_width, + double default_height, + bool default_isUsingWorkingArea, + double default_contentWidth, + double default_contentHeight, + double default_contentX, + double default_contentY) +{ + this->default_width = default_width; + this->default_height = default_height; + this->default_using_working_area = default_isUsingWorkingArea; + this->default_working_width = default_contentWidth; + this->default_working_height = default_contentHeight; + this->default_working_x = default_contentX; + this->default_working_y = default_contentY; +} +/** + * @Author Chaoqun + * @brief 放大页面 + * @param 参数 + * @return 返回值 + * @date 2017/06/27 + */ +void DocPassage::zoomIn() +{ + this->setScale(this->scaleFactor * 1.25); +} + +/** + * @Author Chaoqun + * @brief 缩小 + * @param 参数 + * @return 返回值 + * @date 2017/06/27 + */ +void DocPassage::zoomOut() +{ + this->setScale(this->scaleFactor * 0.8); +} - qDebug() <<"widget's Size"<widget->size(); - qDebug() << "ScrollArea's Size" << this->size(); +/** + * @Author Chaoqun + * @brief 设置文章的缩放 + * @param double scale + * @return void + * @date 2017/06/27 + */ +void DocPassage::setScale(double scale) +{ + // 重置DocPage的尺寸 + double scale_temp = scale / this->scaleFactor; // 获得需要缩小的增量 + + // 对每一页进行缩放 + int page_length = this->pages.size(); + + for(int i =0 ; i< page_length; i++) + { + pages[i]->setScale(scale_temp); // 进行缩放 + } + + // 调整页面的尺寸 + adjustWidgetSize(); + + this->scaleFactor = scale; + +} + +/// +/// \brief DocPassage::updateEditTime +/// 更新修改文件的设置 +/// +void DocPassage::updateEditTime() +{ + QDateTime date = QDateTime::currentDateTime(); + QString str = date.toString("yyyy-MM-dd"); + + this->docInfo->setModDate(str); +} + +/// +/// \brief DocPassage::setCurrentActivedPage +/// 设置当前活跃的页面 +/// 因为假设调用此函数的均为此文档下的页面,因此未作检测 +/// 通过信号槽调用 +/// \param page +/// +void DocPassage::setCurrentActivedPage(DocPage *page) +{ + this->_lastActivedPage = page; } diff --git a/ofdEditor/model/Doc/DocPassage.h b/ofdEditor/model/Doc/DocPassage.h index 2246bd1c2a12bcfbabfb0fc8d69d23272bbe97e3..96bd91d75dd7fb579a2d64d94ee8a0f38eadc2f5 100644 --- a/ofdEditor/model/Doc/DocPassage.h +++ b/ofdEditor/model/Doc/DocPassage.h @@ -23,6 +23,8 @@ class CT_CommonData; class DocBlock; class DocTextBlock; class DocImageBlock; +class DocTable; +//class PageDialog; /** * @Author Chaoqun @@ -34,25 +36,42 @@ class MODELSHARED_EXPORT DocPassage { Q_OBJECT public: - explicit DocPassage(QWidget* parent = 0); - DocPassage(QWidget *parent, QString version, - QString docType,double scaleFactor); + + static DocPassage *createNewPassage(); // 创建新的文章 + static DocPassage *createEmptyPassage(); // 创建空的文章 + + explicit DocPassage(QWidget* parent); + DocPassage(); // 空构造函数 ~DocPassage(); CT_DocInfo* getDocInfo(); // 获取CT_DocInfo数据 + QString getUUID(); // 获得文章的uuid + QString getTempSavePath(); // 获得文章保存前的临时路径 + QString getTempStorePath(); // 获得暂存资源的临时路径 + QString getFilePath(); // 获得文档路径 QString getVersion( ){return this->version;} QString getDocType( ){return this->docType;} - QVector& getPages(); // 获得文档中包含的所有页面 + QVector* getPages(); // 获得文档中包含的所有页面 DocPage *getPage(int index); // 获得文档中的某一页 + + DocPage* getLastedActivedPage(); // Get last actived page + int getLastedActivedPageIndex(); // Get the id of last actived page + int getPageIndex(DocPage* page); // 获得页面的序号 + int pageCount(){return this->pages.size();} // 共有多少页面 + + bool isNeedSave(){return this->isEdited;} // 文档是否被修改,需要保存吗 + QUndoStack *undoStack; // 撤销队列 public slots: void addPage(DocPage *page); // 添加一个新页面 void addPassage(QVector& passage); // 添加很多界面 void appendNewPage(DocPage *page = NULL); // 如果为空,则代表假如空白页 + void insertPage(DocPage* page, int index); // 在指定位置插入页面 void removePage(int index); // 移除某一页 void removePage(DocPage* page); // 移除某一页 + void setFilePath(QString filePath); // 设置文件路径 // DocInfo void setDocInfo( CT_DocInfo & docInfo ); @@ -70,9 +89,46 @@ public slots: // docId void resetDocId(); // 重新设置DocId - void testMessage(); // 测试信号是否走通 + void testMessage(); // 测试信号是否走通 + + void adjustWidgetSize();// 根据页数来自动调整widget大小 + + void setDefaultPageSize( + double default_width, + double default_height); //设置默认的页面尺寸 + + void activatePageDialog(); // 调出设置页面尺寸窗口 - void adjustWidgetSize(); // 根据页数来自动调整widget大小 + // 更改指定页面的页面尺寸 + void modifyPageSize( + QVector * ch_pages, + double _width, + double _height, + bool isUsingWorkingArea, + double contentWidth, + double contentHeight, + double contentX, + double contentY); + + // 修改文章的默认尺寸 + void modifyDefaultPageSize( + double default_width, + double default_height, + bool default_isUsingWorkingArea, + double default_contentWidth, + double default_contentHeight, + double default_contentX, + double default_contentY + ); + + void zoomIn(); // 缩小 + void zoomOut(); // 放大 + + void setScale(double scale); // 设置缩放 + void updateEditTime(); // 更新修改文件日期 + + // Set the current actived page + void setCurrentActivedPage(DocPage* page); protected: void resizeEvent(QResizeEvent* event); @@ -84,8 +140,10 @@ private: QString docType; // 类型默认是 OFD CT_DocInfo* docInfo; // 文档元数据结构 ofd/CT_DocInfo CT_CommonData* commonData; // 文档公用文档数据 - QVector pages; // 既作为数据,也作为渲染 + DocPage* _lastActivedPage; // 用来纪录最后操作过的页面 + bool isEdited; // 是否修改过 + // 文件信息 QString filePath; @@ -98,28 +156,46 @@ private: QWidget * widget; // 用widget做缓冲 double scaleFactor; // 表示缩放倍数 - double widgetWidth; // 内容的宽度 + double widgetWidth; // 文章内部的宽度 double widgetHeight; // 内容的高度 - int horizontalWhite; // 白色页面左右两边的灰色区域 - int verticalWhite; // 白色页面上下的灰色区域 - - void init(); // 初始化 - void adjustScrollBar(QScrollBar *scrollBar, - double factor); // 调整滑动条 + int marginWhite; // 边缘留白 + int spacingWhite; // 纸张之间的留白 + + // 默认的大小 + double default_width; //默认宽度 + double default_height; //默认高度 + bool default_using_working_area; + double default_working_width; + double default_working_height; + double default_working_x; + double default_working_y; + + void initUI(); // 初始化文章界面相关的 + void initDocInfo(); // 初始化文档信息 + void adjustScrollBar( + QScrollBar *scrollBar, + double factor); // 调整滑动条 void adjustScrollBarRange(); //调整滑动条范围 signals: - void signals_insertTextBlock(DocTextBlock* textBlock); // 用来转发信号 - void signals_removeTextBlock(DocTextBlock* textBlock); // 用来转发信号 + void signals_insertTextBlock( + DocTextBlock* textBlock); // 用来转发信号 + void signals_removeTextBlock( + DocTextBlock* textBlock); // 用来转发信号 void signals_currentCharFormatChanged( - QTextCharFormat& fmt); // 当前选择的charFormat发生了变化 + QTextCharFormat fmt); // 当前选择的charFormat发生了变化 void signals_currentBlockFormatChanged( - QTextBlockFormat& fmt); // 当前选择的block格式发生了变化 - void signals_currentTextBlock(DocTextBlock* textBlock); // 当前操作的textBlock - void signals_currentImageBlock(DocImageBlock* imageBlock); //当前操作的imageBlock + QTextBlockFormat fmt); // 当前选择的block格式发生了变化 + void signals_currentTextBlock( + DocTextBlock* textBlock); // 当前操作的textBlock + void signals_currentImageBlock( + DocImageBlock* imageBlock); //当前操作的imageBlock + void signals_currentTableBlock( + DocTable* tableBlock); + void signals_setEditable(bool flag); // 通知自己页面是否可以编辑 }; diff --git a/ofdEditor/model/Doc/DocTable.cpp b/ofdEditor/model/Doc/DocTable.cpp index cbf53d540c51dca4d6411a39ec0a59325c920835..ea3cc94d91f933afa48a38167d6245a29e856a70 100644 --- a/ofdEditor/model/Doc/DocTable.cpp +++ b/ofdEditor/model/Doc/DocTable.cpp @@ -1,14 +1,615 @@ #include "DocTable.h" +#include +#include "Doc/DocBlock.h" +#include "Doc/DocLayer.h" +#include "Doc/DocPage.h" +#include "Doc/DocPassage.h" +#include +#include +#include +#include +#include +#include "Widget/TableSettingDialog.h" +DocTable::DocTable(QWidget *parent) + :DocTextBlock(1.0) +{ + QTextCursor cursor = this->textCursor(); // 获得光标 + this->_table = cursor.insertTable(3,4); // 插入一个表格 + this->init(); -DocTable::DocTable(QWidget *parent) - :QTextEdit(parent) + +} + +/// +/// \brief DocTable::DocTable +/// 固定的行列数初始化表格 +/// \param rows +/// \param columns +/// +DocTable::DocTable(int rows, int columns) + :DocTextBlock(1.0) { + QTextCursor cursor = this->textCursor(); // 获得光标 + this->_table = cursor.insertTable(rows, columns); // 插入一个表格 + this->init(); } + DocTable::~DocTable() { } + +/// +/// \brief DocTable::getType +/// \return +/// +QString DocTable::getType() +{ + return tr("DocTable"); +} + +/// +/// \brief DocTable::getMenu +/// 关于表格操作的菜单 +/// \return +/// +QMenu *DocTable::getMenu() +{ + this->ContextMenu->clear(); //清空菜单 + this->ContextMenu->setTitle(this->getType()); + + this->ContextMenu->addAction(this->actionCut); + this->ContextMenu->addAction(this->actionCopy); + this->ContextMenu->addAction(this->actionPaste); + this->ContextMenu->addAction(this->actionSelectAll); + + this->ContextMenu->addSeparator(); // 增加分界线 + this->ContextMenu->addAction(this->actionBold); // 加粗 + this->ContextMenu->addAction(this->actionItalic); // 斜体 + this->ContextMenu->addAction(this->actionColor); // 颜色 + + this->ContextMenu->addSeparator(); // 分界线 + this->ContextMenu->addAction(this->actionFontSetTest); // 字体 + this->ContextMenu->addAction(this->actionParagraph); // 段落设置 + + // 检验粘贴键的状态 + QClipboard *board = QApplication::clipboard(); + if(board->text().length() <= 0) + { + this->actionPaste->setEnabled(false); + } + else + { + this->actionPaste->setEnabled(true); + } + + // 选择表格的状态 + QTextCursor cursor = this->textCursor(); // 文本光标 + this->selectedCells(cursor); + +// qDebug() << "firstRow, numRows, firstColumn, numColumns" +// << this->firstRow +// << this->rows +// << this->firstColumn +// << this->columns; + + this->ContextMenu->addSeparator(); // ------------------ + this->ContextMenu->addAction(this->actionTableSetting); // 表格设置 + this->ContextMenu->addMenu(this->menu_insertRowOrCol); // 插入行或列 + + if(this->rows > 1 || this->columns > 1) + { + this->ContextMenu->addAction(this->actionMergeCells); // 合并单元格 + this->ContextMenu->addAction(this->actionSplitCells); // 拆分单元格 + } + + this->ContextMenu->addAction(this->actionDeleteRow); // 删除该行 + this->ContextMenu->addAction(this->actionDeleteColumn); // 删除该列 + + return this->ContextMenu; +} + +/// +/// \brief DocTable::getTableColor +/// 获得表格线条的颜色 +/// \return +/// +QColor DocTable::getTableColor() +{ + QTextTableFormat format = this->_table->format(); + QBrush brush = format.borderBrush(); + return brush.color(); +} + +QVector DocTable::getColumnWidth() +{ + QTextTableFormat format = this->_table->format(); + QVector vector = format.columnWidthConstraints(); + return vector; +} + +/// +/// \brief DocTable::setTable +/// 设置表格行数列数 +/// \param rows +/// \param columns +/// +void DocTable::setTable(int rows, int columns) +{ + this->_table->resize(rows,columns); +} + +/// +/// \brief DocTable::setDefaultStyle +/// 将表格设置为默认的样式 +/// +void DocTable::setDefaultStyle() +{ + int length = this->_table->columns(); + QVector colWidth; + + for(int i = 0; i < length; i++) + { + QTextLength l(QTextLength::PercentageLength, 1.0 / length * 100); + colWidth.append(l); + } + QTextTableFormat format = this->_table->format(); + format.setColumnWidthConstraints(colWidth); + + // 设置为单线 + QBrush blackBrush(Qt::SolidPattern); + format.setBorderBrush(blackBrush); + format.setBorder(1); + format.setBorderStyle(QTextFrameFormat::BorderStyle_Solid); + format.setCellSpacing(0); +// format.setCellPadding(0); +// format.setCellPadding(5); + + this->_table->setFormat(format); +} + +void DocTable::setDefaultStyle(bool flag) +{ + this->isDefaultStyle = flag; + if(flag == true) + updateStyle(); +} + +/// +/// \brief DocTable::setColumnWidth +/// 设置每列的宽度 +/// \param vector +/// +void DocTable::setColumnWidth(QVector &vector) +{ + this->colWidth.clear(); + this->colWidth = vector; + this->updateStyle(); +} + +/// +/// \brief DocTable::setBlock +/// \param block +/// +void DocTable::setBlock(DocBlock *block) +{ + this->block = block; + this->connect(block, SIGNAL(signal_resize(qreal,qreal,qreal,qreal)), + this, SLOT(blockSizeChanged())); + // qDebug() << "set block success table"; +} + +/// +/// \brief DocTable::setCellPadding +/// 设置单元格留白 +/// \param cellpadding +/// +void DocTable::setCellPadding(double cellpadding) +{ + QTextTableFormat format = this->_table->format(); + format.setCellPadding(cellpadding); + this->_table->setFormat(format); +} + +void DocTable::setTableColor(QColor color) +{ + QTextTableFormat format = this->_table->format(); + format.setBorderBrush(color); + this->_table->setFormat(format); +} + +/// +/// \brief DocTable::setTableWidth +/// 设置表格总体宽度 +/// \param width +/// +void DocTable::setTableWidth(double width) +{ + this->block->resize(width,this->block->size().rheight()); +} + +/// +/// \brief DocTable::insertRowBefore +/// 在之前插入行 +/// +void DocTable::insertRowBefore() +{ + QTextCursor cursor = this->textCursor(); + this->insertRow(cursor, -1); +} + +/// +/// \brief DocTable::insertRow +/// 插入行 +/// \param cursor +/// \param flag +/// +void DocTable::insertRow(QTextCursor cursor, int flag) +{ + this->selectedCells(cursor); + + // 插入行 + if(flag == -1) + { + // 在选择区域上方插入一行 + this->_table->insertRows(this->firstRow,1); + } + else if(flag == 1) + { + this->_table->insertRows(this->firstRow + 1, 1); + } + +} + +/// +/// \brief DocTable::insertRowAfter +/// +void DocTable::insertRowAfter() +{ + QTextCursor cursor = this->textCursor(); + this->insertRow(cursor, 1); +} + +void DocTable::insertColBefore() +{ + QTextCursor cursor = this->textCursor(); + this->insertCol(cursor, -1); +} + +void DocTable::insertColAfter() +{ + QTextCursor cursor = this->textCursor(); + this->insertCol(cursor, 1); +} + +void DocTable::insertCol(QTextCursor cursor, int flag) +{ + this->selectedCells(cursor); + + // 插入行 + if(flag == -1) + { + // 在选择区域前 + this->_table->insertColumns(this->firstColumn,1); + } + else if(flag == 1) + { + this->_table->insertColumns(this->firstColumn + 1, 1); + } + + if(!this->isDefaultStyle) + { + // 如果是自定义列宽 + double width = this->colWidth[this->firstColumn].rawValue(); + this->colWidth.remove(this->firstColumn); + this->colWidth.insert( + this->firstColumn, + QTextLength( + QTextLength::PercentageLength, + width / 2)); + this->colWidth.insert( + this->firstColumn, + QTextLength( + QTextLength::PercentageLength, + width / 2)); + } + this->updateStyle(); +} + +void DocTable::mergeCells() +{ + QTextCursor cursor = this->textCursor(); + this->_table->mergeCells(cursor); +} + +/// +/// \brief DocTable::splitCells +/// 将已经合并的项给分离开来 +/// +void DocTable::splitCells() +{ + QTextCursor cursor = this->textCursor(); + this->selectedCells(cursor); + + this->_table->splitCell( + this->firstRow, + this->firstColumn, + 1, + 1); +// qDebug() <<"split cells"; +} + +/// +/// \brief DocTable::delRow +/// 删除当前行 +/// +void DocTable::delRow() +{ + QTextCursor cursor = this->textCursor(); + this->selectedCells(cursor); + + this->_table->removeRows(this->firstRow, 1); +} + +/// +/// \brief DocTable::delCol +/// 删除当前列 +/// +void DocTable::delCol() +{ + QTextCursor cursor = this->textCursor(); + this->selectedCells(cursor); + + this->_table->removeColumns(this->firstColumn, 1); + this->updateStyle(); +} + +/// +/// \brief DocTable::tableSetting +/// 给出表格设置窗口,然后设置表格 +/// +void DocTable::tableSetting() +{ + TableSettingDialog* dialog = TableSettingDialog::getInstance(); + dialog->init(this); + + dialog->exec(); +} + +void DocTable::updateStyle() +{ + + if(this->isDefaultStyle) + { + this->setDefaultStyle(); + } + else + { + // 按照设置的比例调节 + QTextTableFormat format = this->_table->format(); + if(format.columnWidthConstraints().size() == this->getColumns()) + { + format.setColumnWidthConstraints(this->colWidth); + this->_table->setFormat(format); + } + + } +} + +void DocTable::focusInEvent(QFocusEvent *e) +{ + emitFormatSignals(); + QTextEdit::focusInEvent(e); +} + +void DocTable::focusOutEvent(QFocusEvent *e) +{ + QTextEdit::focusOutEvent(e); +} + +void DocTable::emitFormatSignals() +{ + QTextCursor cursor = this->textCursor(); // 光标 + this->_currentBlockFormat = cursor.blockFormat(); // 获得块格式 + this->_currentCharFormat = cursor.charFormat(); // 获得字符格式 + + // 发射三个信号 + emit this->signals_currentBlockFormatChanged(this->_currentBlockFormat); + emit this->signals_currentCharFormatChanged(this->_currentCharFormat); + emit this->signals_currentTable(this); +} + +void DocTable::selectedCells(QTextCursor &cursor) +{ + // 这里可以检测是否复选单元格 + cursor.selectedTableCells( + &this->firstRow, + &this->rows, + &this->firstColumn, + &this->columns); + + if( + this->firstRow == -1 + && this->rows == -1 + && this->firstColumn == -1 + && this->columns == -1) + { + QTextTableCell cell = this->_table->cellAt(cursor); + this->firstRow = cell.row(); + this->rows = cell.rowSpan(); + this->firstColumn = cell.column(); + this->columns = cell.columnSpan(); + } + +} + +/// +/// \brief DocTable::checkCursorInTable +/// 与光标改变事件相关联,如果光标出现在了表格外部, +/// 则将它重新移动回到表格内部 +/// +void DocTable::checkCursorInTable() +{ + QTextCursor cursor = this->textCursor(); + int cursorPosition = cursor.position(); // 光标位置 + + if(!(cursorPosition >= this->_table->firstPosition() + && cursorPosition <= this->_table->lastPosition())) + { + // 如果光标离开了表格的范围 + this->setTextCursor(this->_table->firstCursorPosition()); + } + +} + +void DocTable::init() +{ +// this->setFrameStyle(QFrame::NoFrame); + this->setMinimumSize(50,10); + + this->firstRow = 0; + this->firstColumn = 0; + this->rows = 1; + this->columns = 1; + + this->isDefaultStyle = true; + this->updateStyle(); // 更新样式 + this->setCellPadding(5); + + this->initAction(); + this->initMenu(); + this->initConnection(); + +// this->setCellPadding(5); + +} + +/// +/// \brief DocTable::initAction +/// 初始化QAction +void DocTable::initAction() +{ + // 插入 + this->actionInsertColAfter = new QAction(tr("insert Col After"), this); + this->actionInsertColBefore = new QAction(tr("insert Col Before"), this); + this->actionInsertRowAfter = new QAction(tr("insert row after"), this); + this->actionInsertRowBefore = new QAction(tr("insert row before"), this); + + this->actionMergeCells = new QAction(tr("Merge Cells"), this); // 合并单元格 + this->actionSplitCells = new QAction(tr("Split Cells"), this); // 拆分单元格 + + this->actionDeleteColumn = new QAction(tr("delete column"), this); // 删除列 + this->actionDeleteRow = new QAction(tr("delete row"), this); // 删除整行 + this->actionTableSetting = new QAction(tr("table setting"), this); // 表格设置 + +} + +void DocTable::initMenu() +{ + this->ContextMenu = new QMenu(tr("DocTable")); + + // 基本功能 + this->ContextMenu->addAction(this->actionCut); + this->ContextMenu->addAction(this->actionCopy); + this->ContextMenu->addAction(this->actionPaste); + this->ContextMenu->addAction(this->actionSelectAll); + + this->ContextMenu->addSeparator(); // 增加分界线 + this->ContextMenu->addAction(this->actionBold); // 加粗 + this->ContextMenu->addAction(this->actionItalic); // 斜体 + this->ContextMenu->addAction(this->actionColor); // 颜色 + + this->ContextMenu->addSeparator(); // 分界线 + this->ContextMenu->addAction(this->actionFontSetTest); // 字体 + this->ContextMenu->addAction(this->actionParagraph); // 段落设置 + + this->ContextMenu->addSeparator(); // ------------- + this->ContextMenu->addAction(this->actionTableSetting); // 表格设置 + + this->menu_insertRowOrCol = new QMenu(tr("Insert Row or Col")); // 插入行或列 + this->menu_insertRowOrCol->addAction(this->actionInsertRowBefore); + this->menu_insertRowOrCol->addAction(this->actionInsertRowAfter); + this->menu_insertRowOrCol->addAction(this->actionInsertColBefore); + this->menu_insertRowOrCol->addAction(this->actionInsertColAfter); + + this->ContextMenu->addMenu(this->menu_insertRowOrCol); + this->ContextMenu->addAction(this->actionMergeCells); // 合并单元格 + this->ContextMenu->addAction(this->actionSplitCells); // 拆分单元格 + this->ContextMenu->addAction(this->actionDeleteRow); // 删除该行 + this->ContextMenu->addAction(this->actionDeleteColumn); // 删除该列 + +} + +void DocTable::initConnection() +{ + + // 在当前单元格之前插入列 + this->connect(this->actionInsertColBefore, SIGNAL(triggered(bool)), + this, SLOT(insertColBefore())); + + // 在当前单元格之后插入列 + this->connect(this->actionInsertColAfter, SIGNAL(triggered(bool)), + this, SLOT(insertColAfter())); + + // 在当前单元格之前插入行 + this->connect(this->actionInsertRowBefore, SIGNAL(triggered(bool)), + this, SLOT(insertRowBefore())); + + // 在当前单元格之后插入 + this->connect(this->actionInsertRowAfter, SIGNAL(triggered(bool)), + this, SLOT(insertRowAfter())); + + // 合并单元格 + this->connect(this->actionMergeCells, SIGNAL(triggered(bool)), + this, SLOT(mergeCells())); + + // 拆分单元格-------我觉得拆分单元格要慎重-就只把原本合并的单元格分开就好了? + this->connect(this->actionSplitCells, SIGNAL(triggered(bool)), + this, SLOT(splitCells())); + + // 删除整行 + this->connect(this->actionDeleteRow, SIGNAL(triggered(bool)), + this, SLOT(delRow())); + + // 删除整列 + this->connect(this->actionDeleteColumn, SIGNAL(triggered(bool)), + this, SLOT(delCol())); + + // 表格设置 + this->connect(this->actionTableSetting, SIGNAL(triggered(bool)), + this, SLOT(tableSetting())); + + // 自动调整大小 + this->connect(this, SIGNAL(textChanged()), + this, SLOT(blockSizeChanged())); + + // 防止光标移动到表格以外 + this->connect(this, SIGNAL(cursorPositionChanged()), + this, SLOT(checkCursorInTable())); +} + +/// +/// \brief DocTable::blockSizeChanged +/// +void DocTable::blockSizeChanged() +{ +// qDebug() << "block resize"; + + QTextDocument* doc = this->document(); // 获得文档 + int newHeight = doc->size().height(); + + int oldWidth = (int)(this->block->size().width() + 0.5); + int oldHeight = (int)(this->block->size().height() + 0.5); + + if(oldHeight - newHeight > 5 + || oldHeight - newHeight < -5) + { + // 如果需要调整大小 + this->block->resize(oldWidth, newHeight); + } + +} diff --git a/ofdEditor/model/Doc/DocTable.h b/ofdEditor/model/Doc/DocTable.h index 27a150023cfe3949a261bc725d8e0ad7c3143f15..9cdd904fc95ce80816a7fd52010d0e27c8e747b0 100644 --- a/ofdEditor/model/Doc/DocTable.h +++ b/ofdEditor/model/Doc/DocTable.h @@ -6,19 +6,130 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Doc/DocTextBlock.h" +class DocBlock; +class DocPassage; +class DocPage; +class DocLayer; -// 这个类专门用来表示表格 +/// +/// \brief The DocTable class +/// 这个类专门表示表格 +/// 为一个QTextEdit、但内部内容仅有一个QTextTable +/// class MODELSHARED_EXPORT DocTable - :public QTextEdit + :public DocTextBlock { Q_OBJECT public: DocTable(QWidget *parent = NULL); - ~DocTable(); + DocTable(int rows, int columns); + + ~DocTable(); + + QString getType(); // 获得类型 + QMenu *getMenu(); + bool isDefaultWidth(){return this->isDefaultStyle;} // 是否是均分宽度 + double cellPadding(){return this->_table->format().cellPadding();} + QColor getTableColor(); + QVector getColumnWidth(); // 获得行列宽度 + int getColumns(){return this->_table->columns();} + int getRows(){return this->_table->rows();} + QTextTable* getTable(); // 获得QTextTable表格的指针 + +public slots: + void setTable(int rows, int columns); // 设置表格长和宽 + void setDefaultStyle(); // 设置默认样式 + void setDefaultStyle(bool flag); // 设置是否为默认样式 + void setColumnWidth(QVector& vector); // 设置每列的宽度 + void setBlock(DocBlock* block); // 设置块 + void setCellPadding(double cellpadding); // 设置单元格留白 + void setTableColor(QColor color); // 设置表格颜色 + void setTableWidth(double width); // 设置表格整体宽度 + + // 插入行或列 + void insertRowBefore(); + void insertRow( + QTextCursor cursor, + int flag); + void insertRowAfter(); + void insertColBefore(); + void insertColAfter(); + void insertCol( + QTextCursor cursor, + int flag); + + // 合并单元格 + void mergeCells(); + + // 拆分单元格 + void splitCells(); + + // 删除 + void delRow(); + void delCol(); + + // 单元格设置 + void tableSetting(); + void updateStyle(); // 更新表格的样式 + +protected: + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + +protected slots: + void emitFormatSignals(); + +private slots: + void selectedCells(QTextCursor& cursor); + void checkCursorInTable(); // 确保光标永远在表格内部 private: - // tableCell的内容估计使用QTextBlock + int rowCount; // 行数 + int colCount; // 列数 + QTextTable* _table; // 该表格 + QVector colWidth; // 列宽设置 + bool isDefaultStyle; + + // 选择的结果 + int firstRow; + int firstColumn; + int rows; + int columns; + + void init(); // 通用的初始化部分 + void initAction(); // 初始化Action + void initMenu(); // 初始化菜单 + void initConnection(); // 初始化信号槽链接 + + QMenu *menu_insertRowOrCol; // 插入行或列 + QAction *actionInsertRowBefore; // 在当前单元格之前插入行 + QAction *actionInsertRowAfter; // 在当前单元格之后插入行 + QAction *actionInsertColBefore; // 在当前单元格之前插入列 + QAction *actionInsertColAfter; // 在当前单元格之后插入列 + + QAction *actionMergeCells; // 合并单元格 + QAction *actionSplitCells; // 拆分单元格 + + QAction *actionDeleteRow; // 删除该行 + QAction *actionDeleteColumn; // 删除该列 + QAction *actionTableSetting; // 表格设置-对话框解决 + +private slots: + void blockSizeChanged(); // 根据文字内容自动调整块的大小 +signals: + void signals_currentTable(DocTable *table); // 当前操作的表格 }; #endif // TABLE_H diff --git a/ofdEditor/model/Doc/DocTableRow.cpp b/ofdEditor/model/Doc/DocTableRow.cpp deleted file mode 100644 index 80b83549b0b490e8bcb2b2ad488ac854b7d738cc..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocTableRow.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "DocTableRow.h" - -DocTableRow::DocTableRow() -{ - -} diff --git a/ofdEditor/model/Doc/DocTableRow.h b/ofdEditor/model/Doc/DocTableRow.h deleted file mode 100644 index 90fe403d9f964f3a5d3481365ba04052ea215ebc..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocTableRow.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef DOCTABLEROW_H -#define DOCTABLEROW_H - -#include "model_global.h" // 导出lib使用 - - -class MODELSHARED_EXPORT DocTableRow -{ -public: - DocTableRow(); -}; - -#endif // DOCTABLEROW_H diff --git a/ofdEditor/model/Doc/DocTemplate.cpp b/ofdEditor/model/Doc/DocTemplate.cpp deleted file mode 100644 index 98ce4e9d255f1a23c1a29101fc9062251e85ab0a..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocTemplate.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "DocTemplate.h" -// #include "DataTypes/page/CT_PageArea.h" // 页面大小 - -DocTemplate::DocTemplate() -{ - -} - -DocTemplate::~DocTemplate() -{ - // area空间释放 - - // 层空间释放 - int layers_length = layers.size(); - for(int i = 0; i < layers_length; i++) - // 挨个释放空间 - { - DocLayer* temp = this->layers.at(i); - if(temp != NULL) - { - delete temp; - (this->layers)[i] = NULL; - } - } - this->layers.clear(); // 清空层 -} diff --git a/ofdEditor/model/Doc/DocTemplate.h b/ofdEditor/model/Doc/DocTemplate.h deleted file mode 100644 index feecb497eaa1377fc451d054dc6172c2b980b25a..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Doc/DocTemplate.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef DOCTEMPLATE_H -#define DOCTEMPLATE_H - -#include "model_global.h" // 导出lib使用 -#include - -// 类声明 -class DocLayer; -class CT_PageArea; - -class MODELSHARED_EXPORT DocTemplate -{ -public: - DocTemplate(); - ~DocTemplate(); -private: - QVector layers; // 模板的层 - - CT_PageArea* area; // 模板的页面大小 - - -}; - -#endif // DOCTEMPLATE_H diff --git a/ofdEditor/model/Doc/DocTextBlock.cpp b/ofdEditor/model/Doc/DocTextBlock.cpp index 6368d1dafff68359916d1e120701e5a306b9d441..13484a06478ec605af17cef47863572b7d31596f 100644 --- a/ofdEditor/model/Doc/DocTextBlock.cpp +++ b/ofdEditor/model/Doc/DocTextBlock.cpp @@ -1,5 +1,4 @@ #include "DocTextBlock.h" -#include "Doc/DocParagraph.h" #include "Widget/ParagraphFormatDialog.h" #include "Widget/FontSettingDialog.h" #include "Doc/DocPage.h" @@ -16,14 +15,21 @@ #include #include #include - - +#include +#include DocTextBlock::DocTextBlock(QWidget *parent) :QTextEdit(parent) { this->init(); // 调用初始化函数 + this->initNotUseInSun(); +} + +DocTextBlock::DocTextBlock(double i) + :QTextEdit(0) +{ + this->init(); } DocTextBlock::~DocTextBlock() @@ -112,7 +118,7 @@ DocBlock *DocTextBlock::getBlock() * @return QString & * @date 2017/06/25 */ -QString &DocTextBlock::getContent() +QString DocTextBlock::getContent() { QString content = this->document()->toPlainText(); // 获得纯文本 return content; @@ -131,6 +137,55 @@ int DocTextBlock::getContentLength() return content.length(); } +/// +/// \brief DocTextBlock::getType +/// \return +/// +QString DocTextBlock::getType() +{ + QString summary = this->document()->toPlainText().left(5); + return tr("DocTextBlock") + summary; +} + +/// +/// \brief DocTextBlock::getMenu +/// 将文本块中间所需的菜单返回出来 +/// \return +/// +QMenu *DocTextBlock::getMenu() +{ + // 重建菜单 + this->ContextMenu->clear(); //清空菜单 + this->ContextMenu->setTitle(this->getType()); + + this->ContextMenu->addAction(this->actionCut); + this->ContextMenu->addAction(this->actionCopy); + this->ContextMenu->addAction(this->actionPaste); + this->ContextMenu->addAction(this->actionSelectAll); + + this->ContextMenu->addSeparator(); // 增加分界线 + this->ContextMenu->addAction(this->actionBold); // 加粗 + this->ContextMenu->addAction(this->actionItalic); // 斜体 + this->ContextMenu->addAction(this->actionColor); // 颜色 + + this->ContextMenu->addSeparator(); // 分界线 + this->ContextMenu->addAction(this->actionFontSetTest); // 字体 + this->ContextMenu->addAction(this->actionParagraph); // 段落设置 + + // 检验粘贴键的状态 + QClipboard *board = QApplication::clipboard(); + if(board->text().length() <= 0) + { + this->actionPaste->setEnabled(false); + } + else + { + this->actionPaste->setEnabled(true); + } + + return this->ContextMenu; // 返回ContextMenu +} + /** * @Author Chaoqun * @brief 用来合并格式 @@ -167,7 +222,7 @@ void DocTextBlock::mergeFormatOnWordOrSelection( if(!cursor.hasSelection()) { // 如果没有选择文字段落 - cursor.select(QTextCursor::WordUnderCursor); +// cursor.select(QTextCursor::WordUnderCursor); qDebug() << "cursor has no selection!"; } cursor.mergeCharFormat(format); // 合并光标下的 QTextCharFormat @@ -185,10 +240,10 @@ void DocTextBlock::mergeBlockFormatOnBlock( QTextBlockFormat &blockFormat) { QTextCursor cursor = this->textCursor(); // 光标 - if(!cursor.hasSelection()) - { - cursor.select(QTextCursor::BlockUnderCursor); // 选择光标下的块 - } +// if(!cursor.hasSelection()) +// { +// cursor.select(QTextCursor::BlockUnderCursor); // 选择光标下的块 +// } cursor.mergeBlockFormat(blockFormat); } @@ -242,6 +297,16 @@ void DocTextBlock::setFont( mergeFormatOnWordOrSelection(cursor, currentFormat); // 合并给定光标下的字体样式 } +void DocTextBlock::setFont(QString fontName) +{ + QTextCursor cursor = this->textCursor(); + QTextCharFormat charformat = cursor.charFormat(); + QFont font = charformat.font(); + font.setFamily(fontName); + charformat.setFont(font); + mergeFormatOnWordOrSelection(cursor,charformat); +} + /** * @Author Chaoqun * @brief 设置block @@ -252,6 +317,8 @@ void DocTextBlock::setFont( void DocTextBlock::setBlock(DocBlock *block) { this->block = block; // 设置Block + this->connect(block, SIGNAL(signal_resize(qreal,qreal,qreal,qreal)), + this, SLOT(textBlockSizeChanged())); } /** @@ -275,14 +342,7 @@ void DocTextBlock::remove() */ void DocTextBlock::showBoundaryFrame(bool show) { - if(show) - { - this->setFrameStyle(QFrame::Box); // 显示边框 - } - else - { - this->setFrameStyle(QFrame::NoFrame); // 隐藏边框 - } + this->block->setShowBoundaryBox(show); } @@ -362,56 +422,6 @@ void DocTextBlock::textUnderline() mergeFormatOnWordOrSelection(fmt); // 合并格式 - -// /////test -// QTextCursor cursor = this->textCursor(); // 获取光标 -// cursor.movePosition(QTextCursor::Start); // 移动到文章开头 -// for(int i = 0 ; i < this->document()->blockCount(); i++) -// { -// QTextBlock block = cursor.block(); // 获得当前块 -// QTextCursor tempCursor = cursor; // 复制cursor - -// QTextBlock::Iterator iter = block.begin(); // 块的开始 -// QString lineContent; // 行内容 -// QString tempFragement; // 块 -// QTextFragment fragment; // 短句 - -// while(!iter.atEnd()) // 用来判断是否处理完了 -// { -// if(tempFragement == "") -// { -// // 如果处理字段为空 -// fragment = iter.fragment(); // 获得当前的 -// tempFragement = fragment.text(); // -// iter++; -// } -//// while(lineContent.length() < tempFragement.length()) -//// { -//// cursor.select(QTextCursor::LineUnderCursor); // 选择当前行 -//// QString currentLine = cursor.selectedText(); // 选中的文字 - -//// lineContent += currentLine; // 追加一行 -//// qDebug() << "Read Next Line: " << currentLine -//// << "LineContent: " << lineContent; -//// } -// if(lineContent == "") -// { -// cursor.select(QTextCursor::LineUnderCursor); // 选择当前行 -// QString currentLine = cursor.selectedText(); // 选中的文字 - -// lineContent += currentLine; // 追加一行 -// qDebug() << "Read Next Line: " << currentLine -// << "LineContent: " << lineContent; -// } - -// // 处理当前Fragment -//// if(fra) - - -// } - -// cursor.movePosition(QTextCursor::NextBlock); -// } } /** @@ -512,9 +522,13 @@ void DocTextBlock::textParagraph() QTextCursor cursor = this->textCursor(); QTextBlockFormat blockFormat = cursor.blockFormat(); - ParagraphFormatDialog * para = new ParagraphFormatDialog( - blockFormat,this); +// ParagraphFormatDialog * para = new ParagraphFormatDialog( +// blockFormat,this); +// para->exec(); + ParagraphFormatDialog* para = + ParagraphFormatDialog::getInstance(); // 获得实例 + para->init(blockFormat, this); para->exec(); } /** @@ -555,43 +569,15 @@ void DocTextBlock::setTextColor(QTextCursor& cursor,QColor color) mergeFormatOnWordOrSelection(cursor,fmt); } -/** - * @Author Chaoqun - * @brief 通过字体小窗口设置字体 - * @param void - * @return void - * @date 2017/05/21 - */ -void DocTextBlock::textFontDialog() -{ - bool btn_ok; // 确认按键 - QTextCursor cursor = this->textCursor(); - QTextCharFormat currentFormat = cursor.charFormat(); -// QTextCharFormat currentFormat = -// this->currentCharFormat(); // 当前选择文字的样式 - QFont oldFont = currentFormat.font(); // 获取之前的字体样式 - - QFont newFont = QFontDialog::getFont( - &btn_ok, oldFont,NULL,tr("Set the font") - ); // 选择字体框 - - if(btn_ok) - { - this->setFont(newFont); // 设置字体 - } - else - { - // 用户取消了操作,不做处理 - qDebug() << "Cancel select Font!"; - } - - -} - +/// +/// \brief DocTextBlock::customFontDialog +/// 自定义的字体设置窗口 +/// void DocTextBlock::customFontDialog() { - FontSettingDialog * font = new FontSettingDialog(this,0); + FontSettingDialog* font = FontSettingDialog::getInstance(); // 获取实例 + font->init(this); font->exec(); } @@ -609,12 +595,11 @@ void DocTextBlock::setTextBlockFormat(QTextBlockFormat &blockFormat) { // 如果没有选择文字段落 cursor.select(QTextCursor::WordUnderCursor); - qDebug() << "cursor has no selection!"; +// qDebug() << "cursor has no selection!"; } cursor.setBlockFormat(blockFormat); - // 发出信号 emit this->signals_currentBlockFormatChanged(blockFormat); @@ -636,7 +621,7 @@ void DocTextBlock::setTextBlockFormat( { // 如果没有选择文字段落 cursor.select(QTextCursor::WordUnderCursor); - qDebug() << "cursor has no selection!"; +// qDebug() << "cursor has no selection!"; } cursor.setBlockFormat(blockFormat); @@ -658,7 +643,7 @@ void DocTextBlock::setCharFormatOnWordOrSelection( { // 如果没有选择文字段落 cursor.select(QTextCursor::WordUnderCursor); - qDebug() << "cursor has no selection!"; +// qDebug() << "cursor has no selection!"; } cursor.setCharFormat(format); // 设置光标下的 QTextCharFormat this->setCurrentCharFormat(format); // 合并当前的 QTextCharFormat @@ -717,38 +702,6 @@ void DocTextBlock::serCharFormatOnSelection( cursor.setCharFormat(format); // 设置字符格式 } -/** - * @Author Chaoqun - * @brief 显示右键菜单 - * @param QContextMenuEvent *event - * @return void - * @date 2017/05/20 - */ -void DocTextBlock::contextMenuEvent(QContextMenuEvent *event) -{ - - this->ContextMenu = createStandardContextMenu(); // 拓展标准菜单 - this->ContextMenu->addAction(this->actionBold); // 加粗 - this->ContextMenu->addAction(this->actionItalic); // 斜体 - this->ContextMenu->addAction(this->actionUnderline); // 下划线 - this->ContextMenu->addAction(this->actionColor); // 颜色 - this->ContextMenu->addSeparator(); // 分界线 - this->ContextMenu->addAction(this->actionFontSet); // 字体设置 - this->ContextMenu->addAction(this->actionParagraph); // 段落设置 - this->ContextMenu->addAction(this->actionFontSetTest); // 字体 - this->ContextMenu->addAction(this->actionRemove); // 移除操作 - - connect(this->ContextMenu, SIGNAL(aboutToHide()), - this,SLOT(contextMenuAboutToHideEvent())); // 测试 - - this->tempZValue = this->getBlock()->getZValue(); - emit this->signals_setZValue(2000); - - // 展示菜单 - this->ContextMenu->exec(event->globalPos()); - -} - /** * @Author Chaoqun * @brief 焦点聚焦,显示边框 @@ -758,8 +711,11 @@ void DocTextBlock::contextMenuEvent(QContextMenuEvent *event) */ void DocTextBlock::focusInEvent(QFocusEvent *e) { - this->showBoundaryFrame(true); + if(!this->getPage()->getEditable()) + return; + + this->showBoundaryFrame(true); emitFormatSignals(); // 当鼠标移进时,必须发出信号 QTextEdit::focusInEvent(e); @@ -774,24 +730,13 @@ void DocTextBlock::focusInEvent(QFocusEvent *e) */ void DocTextBlock::focusOutEvent(QFocusEvent *e) { - this->showBoundaryFrame(false); + if(!this->getPage()->getEditable()) + return; + this->showBoundaryFrame(false); QTextEdit::focusOutEvent(e); } -/** - * @Author Chaoqun - * @brief 用来当右键菜单消失时,调整块的深度 - * @param 参数 - * @return 返回值 - * @date 2017/06/22 - */ -void DocTextBlock::contextMenuAboutToHideEvent() -{ - emit this->signals_setZValue(this->tempZValue); // 还原Z值 - this->focusInEvent(new QFocusEvent(QEvent::FocusIn)); // 关注它 -} - /** * @Author Chaoqun * @brief 用来检查当前的格式是否发生改变,并向外界发出信号 @@ -858,6 +803,35 @@ void DocTextBlock::emitFormatSignals() emit this->signals_currentTextBlock(this); } +/// +/// \brief DocTextBlock::textBlockSizeChanged +/// 当文字内容改变时,尝试调整文本框大小 +void DocTextBlock::textBlockSizeChanged() +{ + QTextDocument* doc = this->document(); // 获得文档 +// document()->adjustSize(); + +// qDebug() << "Document.size.width" +// << doc->size().width() +// << "Document.textWidth" +// << doc->textWidth(); + + int newHeight = doc->size().height() + 10; + + int oldWidth = (int)(this->block->size().width() + 0.5); + int oldHeight = (int)(this->block->size().height() + 0.5); + + if(oldHeight < newHeight) + { + // 如果需要调整大小 + this->block->resize(oldWidth, newHeight); +// qDebug() << "Automatically resize edit size" +// << oldWidth +// << "," +// << newHeight; + } +} + /** * @Author Chaoqun * @brief 初始化函数 @@ -867,6 +841,7 @@ void DocTextBlock::emitFormatSignals() */ void DocTextBlock::init() { + this->setMinimumSize(5,5); // 为了正确显示缩放标识 // 关闭滑动条 @@ -889,6 +864,7 @@ void DocTextBlock::init() this, SLOT(checkCurrentFormat())); this->initAcitons(); // 初始化QAction相关 + qDebug() << "text block init finished"; } /** @@ -900,8 +876,29 @@ void DocTextBlock::init() */ void DocTextBlock::initAcitons() { + + // 剪切 + this->actionCut = new QAction(tr("Cut"), this); + connect(this->actionCut, SIGNAL(triggered(bool)), + this, SLOT(cut())); + + // 复制 + this->actionCopy = new QAction(tr("Copy"), this); + connect(this->actionCopy, SIGNAL(triggered(bool)), + this, SLOT(copy())); + + // 粘贴 + this->actionPaste = new QAction(tr("Paste"), this); + connect(this->actionPaste, SIGNAL(triggered(bool)), + this, SLOT(paste())); + + // 全选 + this->actionSelectAll = new QAction(tr("Select All"), this); + connect(this->actionSelectAll, SIGNAL(triggered(bool)), + this, SLOT(selectAll())); + // 粗体 - this->actionBold = new QAction(tr("Bold"),NULL); + this->actionBold = new QAction(tr("Bold"), this); this->actionBold->setPriority(QAction::LowPriority); QFont bold; bold.setBold(true); @@ -911,7 +908,7 @@ void DocTextBlock::initAcitons() this,SLOT(textBold())); // 斜体 - this->actionItalic = new QAction(tr("Italic"),NULL); + this->actionItalic = new QAction(tr("Italic"), this); this->actionItalic->setPriority(QAction::LowPriority); QFont italic; italic.setItalic(true); @@ -921,7 +918,7 @@ void DocTextBlock::initAcitons() this,SLOT(textItalic())); // 下划线 - this->actionUnderline = new QAction(tr("Underline"),NULL); + this->actionUnderline = new QAction(tr("Underline"), this); this->actionUnderline->setPriority(QAction::LowPriority); QFont underline; underline.setUnderline(true); @@ -931,37 +928,34 @@ void DocTextBlock::initAcitons() this,SLOT(textUnderline())); // 设置字体颜色 - this->actionColor = new QAction(tr("Color"),NULL); + this->actionColor = new QAction(tr("Color"), this); this->actionColor->setPriority(QAction::LowPriority); this->connect(this->actionColor,SIGNAL(triggered()), this,SLOT(setTextColor())); - // 字体 - this->actionFontSet = new QAction(tr("Font"),NULL); - this->actionFontSet->setPriority(QAction::LowPriority); - - this->connect(this->actionFontSet,SIGNAL(triggered()), - this,SLOT(textFontDialog())); - // 段落 - this->actionParagraph = new QAction(tr("Paragraph"),NULL); + this->actionParagraph = new QAction(tr("Paragraph"), this); this->connect(this->actionParagraph,SIGNAL(triggered()), this,SLOT(textParagraph())); - // 移除文本框 - this->actionRemove = new QAction(tr("Remove"),NULL); - - this->connect(this->actionRemove,SIGNAL(triggered(bool)), - this,SLOT(remove())); // 链接信号,可以移除文本框 - // 字体窗口测试 - this->actionFontSetTest = new QAction(tr("FontDialogTest"),NULL); + this->actionFontSetTest = new QAction(tr("FontDialogTest"), this); this->connect(this->actionFontSetTest, SIGNAL(triggered()), this, SLOT(customFontDialog())); } +void DocTextBlock::initNotUseInSun() +{ + + this->initMenu(); // 初始化右键菜单 + + // 自动调整窗口大小 + this->connect(this, SIGNAL(textChanged()), + this, SLOT(textBlockSizeChanged())); +} + /** * @Author Chaoqun * @brief 初始化文字的样式 @@ -971,11 +965,36 @@ void DocTextBlock::initAcitons() */ void DocTextBlock::initFormat() { - QTextCursor cursor = this->textCursor(); // 获得当前光标 + this->document()->setDocumentMargin(0); // 清空文档的边界 + QTextFrameFormat frameFormat = this->document()->rootFrame()->frameFormat(); + frameFormat.setMargin(0); // 设置边缘 + frameFormat.setPadding(0); // 设置留白 + this->document()->rootFrame()->setFrameFormat(frameFormat); // 设置格式 + +} - QTextCharFormat charFormat = cursor.charFormat(); // 字符格式 - charFormat.setVerticalAlignment(QTextCharFormat::AlignMiddle); +/// +/// \brief DocTextBlock::initMenu +/// 初始化右键菜单 +/// +void DocTextBlock::initMenu() +{ + this->ContextMenu = new QMenu(tr("DocTextBlock")); - this->mergeCurrentCharFormat(charFormat); + // 基本功能 + this->ContextMenu->addAction(this->actionCut); + this->ContextMenu->addAction(this->actionCopy); + this->ContextMenu->addAction(this->actionPaste); + this->ContextMenu->addAction(this->actionSelectAll); + + this->ContextMenu->addSeparator(); // 增加分界线 + this->ContextMenu->addAction(this->actionBold); // 加粗 + this->ContextMenu->addAction(this->actionItalic); // 斜体 +// this->ContextMenu->addAction(this->actionUnderline); // 下划线 + this->ContextMenu->addAction(this->actionColor); // 颜色 + + this->ContextMenu->addSeparator(); // 分界线 + this->ContextMenu->addAction(this->actionFontSetTest); // 字体 + this->ContextMenu->addAction(this->actionParagraph); // 段落设置 } diff --git a/ofdEditor/model/Doc/DocTextBlock.h b/ofdEditor/model/Doc/DocTextBlock.h index 7e1a8d70eb43e37e434f20da0ae129c33846a5ce..4a953475377693ff25140b05330d46a46db1e169 100644 --- a/ofdEditor/model/Doc/DocTextBlock.h +++ b/ofdEditor/model/Doc/DocTextBlock.h @@ -26,15 +26,18 @@ class MODELSHARED_EXPORT DocTextBlock Q_OBJECT public: DocTextBlock(QWidget *parent = NULL); + DocTextBlock(double i); // 假的构造函数 ~DocTextBlock(); - void setContent(QString str); // 设置内容 + void setContent(QString str); // 设置内容 DocPassage* getPassage(); // 获得文章 DocPage* getPage(); // 获得页 DocLayer* getLayer(); // 获得层 DocBlock* getBlock(); // 获得Block - QString& getContent(); // 获得TextBlock中的所有文本 + QString getContent(); // 获得TextBlock中的所有文本 int getContentLength(); // 获得内部文字长度 + QString getType(); // 获得标识,来区分不同的块 + QMenu* getMenu(); // 获得该块的菜单成分 public slots: @@ -48,8 +51,6 @@ public slots: void setTextColor(QTextCursor& cursor,QColor color); // 设置颜色 void textParagraph(); // 设置段落 - - void textFontDialog(); // 通过字体小窗口设置字体 void customFontDialog(); // 自定义的字体窗口设置 void setTextBlockFormat( @@ -87,6 +88,7 @@ public slots: void setFont( QTextCursor& cursor, const QFont &font); // 设置给定光标下的字体格式 + void setFont(QString fontName); // 关于框的一些其他部分 void setBlock(DocBlock* block); // 设置Block @@ -94,49 +96,49 @@ public slots: void showBoundaryFrame(bool show); // 是否显示边界 protected: - - void contextMenuEvent(QContextMenuEvent *event); // 右键菜单重载 void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); -private slots: - void contextMenuAboutToHideEvent(); // 右键菜单隐藏绑定事件 - void checkCurrentFormat(); // 检查当前的格式是否发生改变 - void emitFormatSignals(); // 发射格式的信号 +protected slots: + void checkCurrentFormat(); // 检查当前的格式是否发生改变 + void emitFormatSignals(); // 发射格式的信号 + void textBlockSizeChanged(); // 当文字内容改变时自动调整文字大小 -private: +protected: QString content; // 文字内容 void init(); // 初始化 void initAcitons(); // 初始化事件 + void initNotUseInSun(); // 初始化函数,不应用在子类之中 void initFormat(); // 初始化文字样式 + void initMenu(); // 初始化右键菜单 // QActions + QAction * actionCut; // 剪贴 + QAction * actionCopy; // 复制 + QAction * actionPaste; // 粘贴 + QAction * actionSelectAll; // 全选 + QAction * actionBold; // 加粗 QAction * actionUnderline; // 下划线 QAction * actionItalic; // 斜体 QAction * actionColor; // 设置颜色 - QAction * actionFontSet; // 设置字体 QAction * actionParagraph; // 设置段落 - QAction * actionRemove; // 移除文本框 - - QAction * actionFontSetTest; // 新字体窗口测试 + QAction * actionFontSetTest;// 新字体窗口测试 QMenu * ContextMenu; // 右键菜单 DocBlock* block; // 本类型所在的block - qreal tempZValue; // 存储临时Z值 - QTextBlockFormat _currentBlockFormat; // 当前BlockFormat QTextCharFormat _currentCharFormat; // 当前 signals: void signals_remove(DocTextBlock* textBlock); // 移除文本框的信号。 - void signals_setZValue(qreal z); // 设置Z值的信号 + void signals_setZValue(qreal z); // 设置Z值的信号 void signals_currentCharFormatChanged( - QTextCharFormat& fmt); // 当前选择的charFormat发生了变化 + QTextCharFormat fmt); // 当前选择的charFormat发生了变化 void signals_currentBlockFormatChanged( - QTextBlockFormat& fmt); // 当前选择的block格式发生了变化、 + QTextBlockFormat fmt); // 当前选择的block格式发生了变化、 void signals_currentTextBlock(DocTextBlock* textBlock); // 当前操作的textBlock }; diff --git a/ofdEditor/model/Tool/UnitTool.cpp b/ofdEditor/model/Tool/UnitTool.cpp index 030175decdfa9dafe522723da17b51c0e7b4a424..2eb317b9db73a5ba4003af45caf0d4bf1e53261b 100644 --- a/ofdEditor/model/Tool/UnitTool.cpp +++ b/ofdEditor/model/Tool/UnitTool.cpp @@ -27,10 +27,10 @@ int UnitTool::mmToPixel(double mm) // QDesktopWidget *desktopWidget = QApplication::desktop(); // 获取桌面信息 double dotsPerInch = 96; // 暂时不知道如何获得屏幕具体信息 + int pixel = (int)(inch * dotsPerInch); - - return (int)(inch * dotsPerInch); // 返回像素大小 + return pixel; // 返回像素大小 } /** @@ -50,7 +50,8 @@ double UnitTool::pixelToMM(double pixel) double dotsPerInch = 96; double inch = pixel / dotsPerInch; // 获取像素单位对应的英寸单位 - return inch * 25.4; // 返回毫米单位 + double mm = inch * 25.4; + return mm; // 返回毫米单位 } /** @@ -96,6 +97,53 @@ QRectF UnitTool::getBox(QPointF &point1, QPointF &point2) return QRectF(x,y,w,h); } +/** + * @Author Chaoqun + * @brief 获得两个点组成的方形 + * @param 参数 + * @return 返回值 + * @date 2017/06/27 + */ +QRect UnitTool::getBox(QPoint point1, QPoint point2) +{ + int x1 = point1.x(); + int x2 = point2.x(); + + int y1 = point1.y(); + int y2 = point2.y(); + + int x,y,w,h; + + if(x1 < x2) + { + x = x1; + w = x2 - x1; + } + else + { + x = x2; + w = x1 - x2; + } + + if(y1 < y2) + { + y = y1; + h = y2 - y1; + } + else + { + y = y2; + h = y1 - y2; + } + + return QRect(x,y,w,h); +} + +double UnitTool::pointSizeToMM(double pointsize) +{ + return pointsize * 0.35146; +} + /** * @Author Chaoqun * @brief 判断两个数是否相等,因为公文的误差要求是 1mm, diff --git a/ofdEditor/model/Tool/UnitTool.h b/ofdEditor/model/Tool/UnitTool.h index 92b5552e7213477a54c725c1ba05802137a113d6..bf003061fd838b38eaf575809da7460ef21373db 100644 --- a/ofdEditor/model/Tool/UnitTool.h +++ b/ofdEditor/model/Tool/UnitTool.h @@ -3,7 +3,7 @@ #include #include - +#include "model_global.h" /** * @Author Chaoqun @@ -11,7 +11,7 @@ * 或者是一些常用的工具函数 * @date 2017/05/01 */ -class UnitTool +class MODELSHARED_EXPORT UnitTool { public: UnitTool(); @@ -20,6 +20,9 @@ public: static QRectF getBox(QPointF& point1, QPointF& point2); // 获得两个点组成的方形 + static QRect getBox(QPoint point1, + QPoint point2); // 获得两个点组成的方形 + static double pointSizeToMM(double pointsize); // 点大小转换为毫米单位 static bool equal(double a, double b); // 因为double的误差,用来判断两个数是否相等 }; diff --git a/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.cpp b/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82069192cf9237b43d9391796b4d1d28fe7661fd --- /dev/null +++ b/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.cpp @@ -0,0 +1,80 @@ +#include "BlockSizeAndPosSettingDialog.h" +#include "ui_BlockSizeAndPosSettingDialog.h" + +#include "Doc/DocBlock.h" +#include "Tool/UnitTool.h" + +BlockSizeAndPosSettingDialog *BlockSizeAndPosSettingDialog::m_instance = NULL; + +BlockSizeAndPosSettingDialog::BlockSizeAndPosSettingDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::BlockSizeAndPosSettingDialog) +{ + ui->setupUi(this); + + connect(this, SIGNAL(finished(int)), + this, SLOT(slot_finished(int))); +} + +void BlockSizeAndPosSettingDialog::setUI(int width, int height, int x, int y) +{ + ui->widthValue->setValue(width); + ui->heightValue->setValue(height); + ui->xValue->setValue(x); + ui->yValue->setValue(y); +} + +void BlockSizeAndPosSettingDialog::slot_finished(int value) +{ + if(value == QDialog::Accepted) + { + int height = ui->heightValue->value(); + int width = ui->widthValue->value(); + int x = ui->xValue->value(); + int y = ui->yValue->value(); + + this->_block->resize( + UnitTool::mmToPixel(width), + UnitTool::mmToPixel(height)); + + this->_block->setPos( + UnitTool::mmToPixel(x), + UnitTool::mmToPixel(y)); + } + else if(value == QDialog::Rejected) + { + + } +} + +BlockSizeAndPosSettingDialog *BlockSizeAndPosSettingDialog::getInstance() +{ + if(m_instance == NULL) + { + m_instance = new BlockSizeAndPosSettingDialog(); + } + + return m_instance; +} + +void BlockSizeAndPosSettingDialog::DestoryInsatance() +{ + m_instance = NULL; +} + +void BlockSizeAndPosSettingDialog::init(DocBlock *block) +{ + this->_block = block; // 记录操作的对象 + + this->setUI( + UnitTool::pixelToMM( block->size().width()), + UnitTool::pixelToMM( block->size().height()), + UnitTool::pixelToMM( block->x()), + UnitTool::pixelToMM( block->y())); + +} + +BlockSizeAndPosSettingDialog::~BlockSizeAndPosSettingDialog() +{ + delete ui; +} diff --git a/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.h b/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..455886ae2ae0233c4f326f485d73c5b020ab4f26 --- /dev/null +++ b/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.h @@ -0,0 +1,46 @@ +#ifndef BLOCKSIZEANDPOSSETTINGDIALOG_H +#define BLOCKSIZEANDPOSSETTINGDIALOG_H + +#include +#include "model_global.h" + + +class DocBlock; + +namespace Ui { +class BlockSizeAndPosSettingDialog; +} + +class MODELSHARED_EXPORT BlockSizeAndPosSettingDialog + : public QDialog +{ + Q_OBJECT + +public: + + static BlockSizeAndPosSettingDialog *getInstance(); // 获得单例 + static void DestoryInsatance(); // 销毁单例 + void init(DocBlock* block); + + + ~BlockSizeAndPosSettingDialog(); + +private: + explicit BlockSizeAndPosSettingDialog(QWidget *parent = 0); + Ui::BlockSizeAndPosSettingDialog *ui; + + static BlockSizeAndPosSettingDialog* m_instance; + DocBlock *_block; + + + void setUI( + int width, + int height, + int x, + int y); + +public slots: + void slot_finished(int value); +}; + +#endif // BLOCKSIZEANDPOSSETTINGDIALOG_H diff --git a/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.ui b/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..a8031fccb2927582bcb5ecaebc2f534ded7e458e --- /dev/null +++ b/ofdEditor/model/Widget/BlockSizeAndPosSettingDialog.ui @@ -0,0 +1,218 @@ + + + BlockSizeAndPosSettingDialog + + + + 0 + 0 + 282 + 328 + + + + 调整块的大小尺寸 + + + + + + 大小 + + + + + + + + + + + + + 1000.000000000000000 + + + + + + + mm + + + + + + + + + + + + + + 1000.000000000000000 + + + + + + + mm + + + + + + + + + + 位置 + + + + + + 距离左边 + + + + + + + 1000.000000000000000 + + + + + + + mm + + + + + + + 距离顶部 + + + + + + + 1000.000000000000000 + + + + + + + mm + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + buttonBox + accepted() + BlockSizeAndPosSettingDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + BlockSizeAndPosSettingDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ofdEditor/model/Widget/DocInfoDialog.cpp b/ofdEditor/model/Widget/DocInfoDialog.cpp index d9d8601dcc30ba28423e61b2f7149f6626d02a94..d2fc0001053a844c29219c853aea0ca04be65299 100644 --- a/ofdEditor/model/Widget/DocInfoDialog.cpp +++ b/ofdEditor/model/Widget/DocInfoDialog.cpp @@ -5,22 +5,65 @@ #include #include -DocInfoDialog::DocInfoDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::DocInfoDialog) +DocInfoDialog* DocInfoDialog::m_instance = NULL; // 初始化静态变量 + +/// +/// \brief DocInfoDialog::getInstance +/// 获取实例 +/// \return +/// +DocInfoDialog *DocInfoDialog::getInstance() { - ui->setupUi(this); + if(m_instance != NULL) + { + return m_instance; + } + + m_instance = new DocInfoDialog(); + return m_instance; } -DocInfoDialog::DocInfoDialog(CT_DocInfo *docInfo,QWidget *parent = 0): - QDialog(parent), ui(new Ui::DocInfoDialog) +/// +/// \brief DocInfoDialog::DestoryInstance +/// 销毁实例 +void DocInfoDialog::DestoryInstance() +{ + m_instance = NULL; +} + +/// +/// \brief DocInfoDialog::init +/// 每次调用出单例后进行调用,来调整显示的内容 +/// \param docInfo +/// +void DocInfoDialog::init(CT_DocInfo *docInfo) { - ui->setupUi(this); this->docInfo = docInfo; - this->init(); this->initUi(); } +/// +/// \brief DocInfoDialog::DocInfoDialog +/// 构造函数 +/// \param parent +/// +DocInfoDialog::DocInfoDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::DocInfoDialog) +{ + ui->setupUi(this); + this->init(); // 初始化链接信号槽 +} + +//DocInfoDialog::DocInfoDialog(CT_DocInfo *docInfo,QWidget *parent = 0): +// QDialog(parent), ui(new Ui::DocInfoDialog) +//{ +// ui->setupUi(this); +// this->docInfo = docInfo; +// this->init(); +// this->initUi(); +//} + DocInfoDialog::~DocInfoDialog() { delete ui; diff --git a/ofdEditor/model/Widget/DocInfoDialog.h b/ofdEditor/model/Widget/DocInfoDialog.h index 97af86e1192bab437dc5aab904aeaaed7c9f05b9..779001a13e941df0b5a127019bab6ba48c3e55b1 100644 --- a/ofdEditor/model/Widget/DocInfoDialog.h +++ b/ofdEditor/model/Widget/DocInfoDialog.h @@ -3,7 +3,7 @@ #include #include "model_global.h" -class CT_DocInfo; // ĵԪϢ +class CT_DocInfo; // 文档元信息 namespace Ui { class DocInfoDialog; @@ -14,26 +14,32 @@ class MODELSHARED_EXPORT DocInfoDialog : public QDialog Q_OBJECT public: - explicit DocInfoDialog(QWidget *parent = 0); - DocInfoDialog(CT_DocInfo* docInfo,QWidget *parent); + static DocInfoDialog* getInstance(); // 获得实例 + static void DestoryInstance(); // 销毁实例 + void init(CT_DocInfo* docInfo); // 初始化-每次调用窗口时使用 + +// DocInfoDialog(CT_DocInfo* docInfo,QWidget *parent); ~DocInfoDialog(); private: Ui::DocInfoDialog *ui; - CT_DocInfo* docInfo; // ĵԪϢ - void init(); // ʼ - void initUi(); // ʼui + static DocInfoDialog* m_instance; // 单例 + CT_DocInfo* docInfo; // 文档元信息 + + explicit DocInfoDialog(QWidget *parent = 0); + void init(); // 初始化 + void initUi(); // 初始化ui public slots: - void editTitle(const QString & text); // ޸ı - void editAuthor(const QString & text); // ޸ - void editSubject(const QString & text); // ޸ - void editAbstract(const QString & text); // ޸ժҪ - void editFileType(const QString & text); // ĵ - void editFileCover(const QString & text); // ĵ - void resetDocId(); // UUID + void editTitle(const QString & text); // 修改标题 + void editAuthor(const QString & text); // 修改作者 + void editSubject(const QString & text); // 修改主题 + void editAbstract(const QString & text); // 修改摘要 + void editFileType(const QString & text); // 文档类型 + void editFileCover(const QString & text); // 文档封面 + void resetDocId(); // 重置UUID }; diff --git a/ofdEditor/model/Widget/DocInfoDialog.ui b/ofdEditor/model/Widget/DocInfoDialog.ui index 87d36cfaeaa27cda8020fb26779af9ae83d888b1..7515fa5cfece86d15a425ac96c89f31f2d4ed138 100644 --- a/ofdEditor/model/Widget/DocInfoDialog.ui +++ b/ofdEditor/model/Widget/DocInfoDialog.ui @@ -6,240 +6,217 @@ 0 0 - 483 - 641 + 363 + 472 - Dialog + 文档信息 - - - - 70 - 590 - 341 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 20 - 461 - 361 - - - - 说明 - - - - - 21 - 21 - 411 - 301 - - - - - - - 文件: - - - - - - - 文档ID: - - - - - - - 更改 - - - - - - - 标题: - - - - - - - - - - 作者: - - - - - - - - - - 主题: - - - - - - - - - - 摘要: - - - - - - - - - - 关键字: - - - - - - - - - - 文档类型: - - - - - - - - - - 文档封面: - - - - - - - - - - 创建日期: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10 - 420 - 461 - 151 - - - - 高级 - - - - - 20 - 30 - 431 - 111 - - - - - - - 最近修改时间: - - - - - - - - - - - - - - 创建应用程序: - - - - - - - - - - - - - - 应用程序版本: - - - - - - - - - - - - - + + + + + 说明 + + + + + + + + + 主题: + + + + + + + 作者: + + + + + + + 文档类型: + + + + + + + 文件: + + + + + + + 文档ID: + + + + + + + 更改 + + + + + + + + + + + + + + + + + + + + + + + 摘要: + + + + + + + + + + 标题: + + + + + + + + + + + + + + 关键字: + + + + + + + + + + + + + + 创建日期: + + + + + + + + + + + + + 文档封面: + + + + + + + + + + 高级 + + + + + + + + + + + + + + + + + + + + 创建应用程序: + + + + + + + 最近修改时间: + + + + + + + + + + + + + + 应用程序版本: + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/ofdEditor/model/Widget/FindAndReplaceDock.cpp b/ofdEditor/model/Widget/FindAndReplaceDock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f35391200b77aa4272846d84fbfff749fefb06c0 --- /dev/null +++ b/ofdEditor/model/Widget/FindAndReplaceDock.cpp @@ -0,0 +1,430 @@ +#include "FindAndReplaceDock.h" +#include "ui_FindAndReplaceDock.h" +#include "../model/Doc/DocPassage.h" +#include "../model/Doc/DocPage.h" +#include "../model/Doc/DocLayer.h" +#include "../model/Doc/DocBlock.h" +#include "../model/DOc/DocTextBlock.h" +#include +#include +#include +#include + +FindAndReplaceDock* FindAndReplaceDock::m_instance = NULL; // 初始化静态变量 + +/// +/// \brief FindAndReplaceDock::getInstance +/// 获得实例 +/// \return +/// +FindAndReplaceDock *FindAndReplaceDock::getInstance() +{ + if(m_instance != NULL) + { + return m_instance; + } + + m_instance = new FindAndReplaceDock(); + return m_instance; +} + +/// +/// \brief FindAndReplaceDock::DestoryInstance +/// 销毁实例 - 暂时交由QT处理 +void FindAndReplaceDock::DestoryInstance() +{ + m_instance = NULL; +} + +/// +/// \brief FindAndReplaceDock::FindAndReplaceDock +/// 默认构造函数 +/// \param parent +/// +FindAndReplaceDock::FindAndReplaceDock(QWidget *parent) : + QDockWidget(parent), + ui(new Ui::FindAndReplaceDock) +{ + ui->setupUi(this); // 初始化界面 + this->init(); // 初始化 +} + +/// +/// \brief FindAndReplaceDock::init +/// 初始化,主要用于单例的构造函数 +void FindAndReplaceDock::init() +{ + //初始化成员 + count = 0; + ui->CountLineEdit->setText("0"); + ui->CountLineEdit->setEnabled(false); + + ui->ReplaceButton->setEnabled(false); + ui->ReplaceAllButton->setEnabled(false); + + this->initConnect(); // 初始化信号槽链接 +} + +/// +/// \brief FindAndReplaceDock::initConnect +/// 初始化链接 +/// +void FindAndReplaceDock::initConnect() +{ + + this->connect(ui->FindLineEdit, + SIGNAL(textChanged(QString)), + this, + SLOT(on_FindLineEdit_textChanged(QString))); +// qDebug() << "Finished constructing FindAndReplaceDock"; + this->connect(ui->CountLineEdit, + SIGNAL(textChanged(QString)), + this, + SLOT(on_CountLineEdit_textChanged(QString))); + this->connect(ui->FindNextButton, + SIGNAL(clicked(bool)), + this, + SLOT(locateNextPlace())); + this->connect(ui->FindPreviousButton, + SIGNAL(clicked(bool)), + this, + SLOT(locatePreviousPlace())); + this->connect(ui->ReplaceButton, + SIGNAL(clicked(bool)), + this, + SLOT(replaceText())); + this->connect(ui->ReplaceAllButton, + SIGNAL(clicked(bool)), + this, + SLOT(replaceAll())); + +} + + +FindAndReplaceDock::~FindAndReplaceDock() +{ + delete ui; +} + +/** + * @Author Pan + * @brief 设置当前活动的文档 + * @param DocPassage *current_passage + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::setCurrentPassage(DocPassage *current_passage) +{ + passage = current_passage; +} + +/** + * @Author Pan + * @brief 查找文本框的内容有改变后,就重新开始Find + * @param const QString &arg1 + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::on_FindLineEdit_textChanged(const QString &arg1) +{ + blocks_found.clear(); + blocks_flag.clear(); + count = 0; + + if (arg1.length() > 0) + findAllTargetTextBlock(arg1); + if (blocks_found.size() == 0) + { + ui->ReplaceButton->setEnabled(false); + ui->ReplaceAllButton->setEnabled(false); + } + else { + ui->ReplaceButton->setEnabled(true); + ui->ReplaceAllButton->setEnabled(true); + } + if (blocks_found.size() == 0) + { + ui->CountLineEdit->setText(QString::number(count)); + } + else + { + this->current_block_index = -1; + this->current_block_pos = -1; + ui->CountLineEdit->setText(QString::number(count)); + locateNextPlace(); + } +} + +/** + * @Author Pan + * @brief 找到所有包含目标字符串的DocTextBlock,并放到blocks_found容器中 + * @param const QString & str + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::findAllTargetTextBlock(const QString & str) +{ +// qDebug() << "Start finding all target blocks"; + for (int i = 0; i < passage->getPages()->size(); i++) + { + DocPage * cur_page = passage->getPages()->operator [](i); + DocLayer * foreground_layer = cur_page->getForegroundLayer(); + DocLayer * body_layer = cur_page->getBodyLayer(); + DocLayer * background_layer = cur_page->getBackgroundLayer(); + for (int j = 0; j < foreground_layer->getBlocks()->size(); j++) + { + DocBlock * cur_block = foreground_layer->getBlocks()->operator [](j); + if (cur_block->isTextBlock()) + { + if (cur_block->getTextBlock() + ->getContent().contains(str)) + { + blocks_found.push_back(cur_block->getTextBlock()); + blocks_flag.push_back(true); + QString sstr = cur_block->getTextBlock()->getContent(); + int i = -1; + do { + i = sstr.indexOf(str, i + 1); + if (i != -1) + count++; + } while (i != -1); + } + } + } +// qDebug() << "Finished processing all foreground layer blocks."; + for (int j = 0; j < body_layer->getBlocks()->size(); j++) + { + DocBlock * cur_block = body_layer->getBlocks()->operator [](j); + if (cur_block->isTextBlock()) + { +// qDebug() << "???"; + if (cur_block->getTextBlock() + ->getContent().contains(str)) + { +// qDebug() << "TextBlock Address = " << cur_block->getTextBlock(); + blocks_found.push_back(cur_block->getTextBlock()); + blocks_flag.push_back(true); +// qDebug() << "???"; + int i = -1; + do { + i = cur_block->getTextBlock()->getContent().indexOf(str, i + 1); +// qDebug() << " i = " << i; + if (i != -1) + count++; +// qDebug() << "Count++"; + } while (i != -1); +// qDebug() << "Finished processing a block"; + } + } + } +// qDebug() << "Finished processing all body layer blocks."; + for (int j = 0; j < background_layer->getBlocks()->size(); j++) + { + DocBlock * cur_block = body_layer->getBlocks()->operator [](j); + if (cur_block->isTextBlock()) + { + if (cur_block->getTextBlock() + ->getContent().contains(str)) + { + blocks_found.push_back(cur_block->getTextBlock()); + blocks_flag.push_back(true); + QString sstr = cur_block->getTextBlock()->getContent(); + int i = -1; + do { + i = sstr.indexOf(str, i + 1); + if (i != -1) + count++; + } while (i != -1); + } + } + } + } + qDebug() << "Finished finding all target blocks"; + qDebug() << blocks_found.size() << "blocks found."; +} + +/** + * @Author Pan + * @brief 聚焦、定位到当下的查找到的DocTextBlock中的文本 + * @param + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::focusOnFoundPart() +{ + DocTextBlock * current_block = blocks_found[current_block_index]; + current_block->setFocus(); + QTextCursor cursor = current_block->textCursor(); + cursor.setPosition(current_block_pos); + cursor.movePosition(QTextCursor::NextCharacter, + QTextCursor::KeepAnchor, + ui->FindLineEdit->text().length()); + current_block->setTextCursor(cursor); + QScrollBar * scroll_bar = passage->verticalScrollBar(); + + DocPassage * current_passage = current_block->getPassage(); + DocPage * current_page = current_block->getPage(); + int accumulated_height = 0; + for (int i = 0; i < current_passage->getPages()->size(); i++) + { + if (current_passage->getPages()->operator [](i) == current_page) + break; + else + accumulated_height += + 50 + current_passage->getPages()->operator [](i)->height(); + } + scroll_bar->setSliderPosition(accumulated_height + current_block->pos().ry()); +} + +/** + * @Author Pan + * @brief 辅助函数,通过blocks_flag找到下一个包含目标字符串的块 + * @param int cur_index + * @return int + * @date 2017/06/27 + */ +int FindAndReplaceDock::findNextAvaibleBlockIndex(int cur_index) +{ + int i = cur_index; + while (((++i) %= blocks_flag.size()) != cur_index) + { + if (blocks_flag[i] == true) + return i; + } + return -1; +} + +/** + * @Author Pan + * @brief 定位到上一处位置 + * @param + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::locatePreviousPlace() +{ + //To be implemented +} + +/** + * @Author Pan + * @brief 定位到下一处位置 + * @param + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::locateNextPlace() +{ + if (blocks_found.size() > 0) { + qDebug() << "locateNextPlace() called."; + // qDebug() << "Current_block_index = " << current_block_index; + // qDebug() << "Current_block_pos = " << current_block_pos; + DocTextBlock * cur_text_block; + QString str = ui->FindLineEdit->text(); + QString sstr; + if (current_block_index == -1 && current_block_pos == -1) { + current_block_index = 0; + cur_text_block = blocks_found[0]; + sstr = cur_text_block->getContent(); + current_block_pos = sstr.indexOf(str, 0); +// qDebug() << "In init str = " << str << " sstr = " << sstr; + } + else + { + qDebug() << "Output block_flags: "; + for (int i = 0; i < blocks_flag.size(); i++) + qDebug() << "blocks_flag at " << i << " = " << blocks_flag[i]; + qDebug() << "Current_block_index = " << current_block_index; + qDebug() << "Current_block_pos = " << current_block_pos; + qDebug() << "Next place position = " << sstr.indexOf(str, current_block_pos + 1); + qDebug() << "str = " << str << " sstr = " << sstr; + cur_text_block = blocks_found[current_block_index]; + sstr = cur_text_block->getContent(); + if (sstr.indexOf(str, current_block_pos + 1) != -1) { + current_block_pos = sstr.indexOf(str, current_block_pos + 1); + } + else { + qDebug() << "Current_block_index = " << current_block_index; + qDebug() << "Next available Index = " + << findNextAvaibleBlockIndex(current_block_index); + if ((current_block_index = + findNextAvaibleBlockIndex(current_block_index)) != -1) { + + cur_text_block = blocks_found[current_block_index]; + sstr = cur_text_block->getContent(); + current_block_pos = sstr.indexOf(str, 0); + } else { + QMessageBox::information(passage, "Message", "No text found.", "OK"); + return; + } + } + } + focusOnFoundPart(); + } else { + QMessageBox::information(passage, "Message", "No text found.", "OK"); + return; + } +} + +/** + * @Author Pan + * @brief 用ReplaceWithLineEdit中的文本替换当前选中的文本 + * @param + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::replaceText() +{ + if (blocks_found.size() > 0) + { + if (current_block_index >= 0 && current_block_pos >= 0) + { + DocTextBlock * cur_block = blocks_found[current_block_index]; + QTextCursor cursor = cur_block->textCursor(); + cursor.removeSelectedText(); + cursor.insertText(ui->ReplaceWithLineEdit->text()); + if (!cur_block->getContent().contains(ui->FindLineEdit->text())) + blocks_flag[current_block_index] = false; + locateNextPlace(); + } + } + else return; +} + +/** + * @Author Pan + * @brief 替换所有查找到的文本 + * @param + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::replaceAll() +{ + while (findNextAvaibleBlockIndex(0) >= 0) { + replaceText(); + } +} + +/** + * @Author Pan + * @brief 按钮的效果的槽函数 + * @param const QString &arg1 + * @return void + * @date 2017/06/27 + */ +void FindAndReplaceDock::on_CountLineEdit_textChanged(const QString &arg1) +{ + if (arg1.toInt() == 0) + { + ui->FindPreviousButton->setEnabled(false); + ui->FindNextButton->setEnabled(false); + } + else + { + ui->FindPreviousButton->setEnabled(true); + ui->FindNextButton->setEnabled(true); + } +} + + + diff --git a/ofdEditor/model/Widget/FindAndReplaceDock.h b/ofdEditor/model/Widget/FindAndReplaceDock.h new file mode 100644 index 0000000000000000000000000000000000000000..1ac31ab7162d1a1aa8d46e72b30c33969ed4f950 --- /dev/null +++ b/ofdEditor/model/Widget/FindAndReplaceDock.h @@ -0,0 +1,56 @@ +#ifndef FINDANDREPLACEDOCK_H +#define FINDANDREPLACEDOCK_H + +#include +#include +#include + +class DocTextBlock; +class DocPassage; + +namespace Ui { +class FindAndReplaceDock; +} + +class MODELSHARED_EXPORT FindAndReplaceDock + : public QDockWidget +{ + Q_OBJECT + +public: + static FindAndReplaceDock* getInstance(); // 获得实例 + static void DestoryInstance(); // 销毁实例 + + ~FindAndReplaceDock(); + + void setCurrentPassage(DocPassage * current_passage); +private slots: + void on_FindLineEdit_textChanged(const QString &arg1); // 查找的内容变化了 + void on_CountLineEdit_textChanged(const QString &arg1); // 查找到的内容数量变化了 + void locatePreviousPlace(); //定位到上一个位置 + void locateNextPlace(); //定位到下一个位置 + void replaceText(); //切换当前文本 + void replaceAll(); //切换所有文本 + +private: + + explicit FindAndReplaceDock(QWidget *parent = 0); + void init(); // 初始化 + void initConnect(); // 初始化信号槽 + void findAllTargetTextBlock(const QString & str); + void focusOnFoundPart(); + int findNextAvaibleBlockIndex(int cur_index); + + Ui::FindAndReplaceDock *ui; + static FindAndReplaceDock* m_instance; // 单例 + + QVector blocks_found; + QVector blocks_flag; //记录blocks_find中的元素是否依然有效 + DocPassage * passage; + int count; //找到的文本数量 + int current_block_index; //当前选中的DocTextBlock的下边,-1表示将从头开始 + int current_block_pos; //当前选中的DocTextBlock的当前位置,-1表示将从头开始 + +}; + +#endif // FINDANDREPLACEDOCK_H diff --git a/ofdEditor/model/Widget/FindAndReplaceDock.ui b/ofdEditor/model/Widget/FindAndReplaceDock.ui new file mode 100644 index 0000000000000000000000000000000000000000..5b92a799947de3ea61ddf55ac183ef01599d466a --- /dev/null +++ b/ofdEditor/model/Widget/FindAndReplaceDock.ui @@ -0,0 +1,159 @@ + + + FindAndReplaceDock + + + + 0 + 0 + 954 + 64 + + + + false + + + QDockWidget::DockWidgetClosable + + + Qt::BottomDockWidgetArea + + + Find/Replace + + + + + + + + Arial + 10 + + + + Find: + + + + + + + + + + + Arial + 10 + + + + Find Previous + + + + + + + + Arial + 10 + + + + Find Next + + + + + + + + Arial + 10 + + + + Found in: + + + + + + + + Arial + 10 + + + + + + + + + Arial + 10 + + + + places. + + + + + + + Qt::Vertical + + + + + + + + Arial + 10 + + + + Replace With: + + + + + + + + + + + Arial + 10 + + + + Replace + + + + + + + + Arial + 10 + + + + Replace All + + + + + + + + + diff --git a/ofdEditor/model/Widget/FontSettingDialog.cpp b/ofdEditor/model/Widget/FontSettingDialog.cpp index 5b2f4a5a13a362db8441a3786bb492ef20e475ae..e7795d914583d6dd2173c1233d405364d147d194 100644 --- a/ofdEditor/model/Widget/FontSettingDialog.cpp +++ b/ofdEditor/model/Widget/FontSettingDialog.cpp @@ -3,33 +3,61 @@ #include #include +#include #include "Doc/DocTextBlock.h" #include +FontSettingDialog* FontSettingDialog::m_instance = NULL; // 初始化静态变量 + FontSettingDialog::FontSettingDialog(QWidget *parent) : QDialog(parent), ui(new Ui::FontSettingDialog) { ui->setupUi(this); + init(); } -FontSettingDialog::FontSettingDialog(DocTextBlock *textBlock - , QWidget *parent) - :QDialog(parent), - ui(new Ui::FontSettingDialog) +/// +/// \brief FontSettingDialog::getInstance +/// 获得单例的实例 +/// \return +/// +FontSettingDialog *FontSettingDialog::getInstance() { - ui->setupUi(this); - this->textBlock = textBlock; // 记录下负责的DocTextBlock + if( m_instance != NULL) + { + return m_instance; + } - this->connect(this,SIGNAL(signal_updatePreview(QTextCharFormat)), - this,SLOT(updatePreview(QTextCharFormat))); // 更新预览的链接 + m_instance = new FontSettingDialog(); // 新建字体设置窗口实例 + return m_instance; +} + +/// +/// \brief FontSettingDialog::DestoryInstance +/// 用来销毁实例 +void FontSettingDialog::DestoryInstance() +{ + // Font窗口暂不释放,交由Qt机制处理 + m_instance = NULL; +} + +/// +/// \brief FontSettingDialog::init +/// 每次调出单例后可执行 +/// \param textBlock +/// +void FontSettingDialog::init(DocTextBlock *textBlock) +{ + this->textBlock = textBlock; // 纪录下当前操作的对象 + // 当用完后,记得将对象释放 + connect(this,SIGNAL(sendFont(QTextCharFormat&)), + this->textBlock,SLOT(setCharFormatOnSelection(QTextCharFormat&))); // 发送字体 QTextCursor cursor = this->textBlock->textCursor(); // 获得文本的光标 QTextCharFormat charFormat = cursor.charFormat(); // 获得光标的charFormat - this->init(charFormat); // 初始化字体窗口 - - initConnect(); // 初始化信号连接 + this->changeCharFormat(charFormat); // 更改字体窗口的当前字体 } FontSettingDialog::~FontSettingDialog() @@ -84,47 +112,55 @@ int FontSettingDialog::comboIndex(double pointSizeF) /** * @Author Chaoqun - * @brief 初始化链接 + * @brief 初始化链接 - 只需要执行一次 * @param void * @return void * @date 2017/05/26 */ void FontSettingDialog::initConnect() { + // 链接字体 this->connect(this->ui->comboFont, SIGNAL(currentFontChanged(QFont)), - this,SLOT(updateFontFamily(QFont))); // 链接字体 + this,SLOT(updateFontFamily(QFont))); + // 链接字号 this->connect(this->ui->comboFontSize, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFontSizeF(int))); // 链接字体大小 - + // 链接粗体 connect(this->ui->checkBold, SIGNAL(stateChanged(int)), this,SLOT(updateBold(int))); // 链接加粗 + // 链接斜体 connect(this->ui->checkItalic, SIGNAL(stateChanged(int)), this,SLOT(updateItalic(int))); // 链接斜体 + // 链接下划线 connect(this->ui->checkUnderline, SIGNAL(stateChanged(int)), this,SLOT(updateUnderline(int))); // 链接下划线 + // 链接字宽 connect(this->ui->checkFixedWidth, SIGNAL(stateChanged(int)), this,SLOT(updatefixedPitch(int))); // 固定字宽 + // 链接字粗 connect(this->ui->intFontWeight, SIGNAL(valueChanged(int)), this,SLOT(updateWeight(int))); // 字体粗细 + // 字间距 connect(this->ui->doubleFontSpace, SIGNAL(valueChanged(double)), this,SLOT(updateWordSpacing(double))); // 字间距 + // 链接预览窗口 + connect(this, SIGNAL(signal_updatePreview(QTextCharFormat)), + this,SLOT(updatePreview(QTextCharFormat))); - connect(this, SIGNAL(accepted()), - this, SLOT(accept_slots())); // 窗口接受确认的信号 - - connect(this,SIGNAL(sendFont(QTextCharFormat&)), - this->textBlock,SLOT(setCharFormatOnSelection(QTextCharFormat&))); // 发送字体 + // 当用户点击确认后,执行的函数 + connect(this, SIGNAL(finished(int)), + this, SLOT(finished_slots(int))); // 窗口完成任务时 } @@ -142,21 +178,11 @@ void FontSettingDialog::updatePreview(const QTextCharFormat &charFormat) cursor.setCharFormat(charFormat); // 设置格式 } -/** - * @Author Chaoqun - * @brief 初始化界面 - * @param const QTextCharFormat &charFormat - * @return void - * @date 2017/05/25 - */ -void FontSettingDialog::init(const QTextCharFormat &charFormat) +/// +/// \brief FontSettingDialog::init +/// 改成单例后,部分界面的初始化只需要做一次 +void FontSettingDialog::init() { - this->charFormat = new QTextCharFormat(charFormat); // 存下这个charFormat,后面可以使用 - - // 字体框 - QFont font = charFormat.font(); // 获得字体 - this->ui->comboFont->setCurrentFont(font); // 设置显示 - // 字体大小框 // 点大小与Index的对应关系 this->pointSizeTable.insert(0,42); // 初号 @@ -197,6 +223,25 @@ void FontSettingDialog::init(const QTextCharFormat &charFormat) this->pointSizeTable.insert(35,48); this->pointSizeTable.insert(36,72); + initConnect(); // 做链接 + + +} + +/** + * @Author Chaoqun + * @brief 初始化界面 + * @param const QTextCharFormat &charFormat + * @return void + * @date 2017/05/25 + */ +void FontSettingDialog::changeCharFormat(const QTextCharFormat &charFormat) +{ + this->charFormat = new QTextCharFormat(charFormat); // 存下这个charFormat,后面可以使用 + + // 字体框 + QFont font = charFormat.font(); // 获得字体 + this->ui->comboFont->setCurrentFont(font); // 设置显示 int fontsizeIndex = this->comboIndex(font.pointSizeF()); // 设置对应的字体大小 this->ui->comboFontSize->setCurrentIndex(fontsizeIndex); @@ -243,7 +288,6 @@ void FontSettingDialog::init(const QTextCharFormat &charFormat) this->ui->doubleFontStretch->setVisible(false); this->ui->checkFixedWidth->setVisible(false); - // weight int weight = font.weight(); this->ui->intFontWeight->setValue(weight); @@ -260,7 +304,6 @@ void FontSettingDialog::init(const QTextCharFormat &charFormat) emit signal_updatePreview(*this->charFormat); // 更新预览窗口 - } /** @@ -458,14 +501,22 @@ void FontSettingDialog::updateWeight(int i) emit this->signal_updatePreview(*this->charFormat); } -/** - * @Author Chaoqun - * @brief 用户确定事件 - * @param void - * @return void -* @date 2017/05/26 - */ -void FontSettingDialog::accept_slots() +/// +/// \brief FontSettingDialog::finished_slots +/// \param value +/// +void FontSettingDialog::finished_slots(int value) { - emit this->sendFont(*this->charFormat); + if(value = QDialog::Accepted) + { + // 如果点击的是确定键 + emit this->sendFont(*this->charFormat); + } + + disconnect(this, + SIGNAL(sendFont(QTextCharFormat&)), + this->textBlock, + SLOT(setCharFormatOnSelection(QTextCharFormat&))); } + + diff --git a/ofdEditor/model/Widget/FontSettingDialog.h b/ofdEditor/model/Widget/FontSettingDialog.h index fb97adb029277dde47c30e20e6e8b0aa5b66722b..4e71e8f6c3f4640ef6dce6599cef572cf31a0e9a 100644 --- a/ofdEditor/model/Widget/FontSettingDialog.h +++ b/ofdEditor/model/Widget/FontSettingDialog.h @@ -22,7 +22,10 @@ class MODELSHARED_EXPORT FontSettingDialog : public QDialog public: - FontSettingDialog(DocTextBlock* textBlock,QWidget *parent = 0); + static FontSettingDialog* getInstance(); // 获得单例--需要是静态的 + static void DestoryInstance(); // 销毁实例 + void init(DocTextBlock* textBlock); // 将窗口初始化 + ~FontSettingDialog(); signals: @@ -31,15 +34,16 @@ signals: private: explicit FontSettingDialog(QWidget *parent = 0); - Ui::FontSettingDialog *ui; + Ui::FontSettingDialog *ui; // 界面元素 + + static FontSettingDialog* m_instance; // 单例 DocTextBlock * textBlock; // 指向待调整文本框 QTextCharFormat* charFormat; // 预览框的格式 QTextCharFormat getQTextCharFormat(); // 获得更新后的字体 - - QMap pointSizeTable; // 字号与Index对应表 + QMap pointSizeTable; // 字号与Index对应表 double pointSizeF(int comboIndex); // 获取字号大小与Index的对应关系 int comboIndex(double pointSizeF); // 获得Index与pointSize的对应关系 void initConnect(); // 初始化各种函数的链接 @@ -47,10 +51,10 @@ private: private slots: void updatePreview(const QTextCharFormat& charFormat); // 设置为预览,用来更新预览文字的效果 + void init(); // 初始化界面 + void changeCharFormat(const QTextCharFormat& charFormat); // 根据字体更新界面选项 - void init(const QTextCharFormat& charFormat); - - void updateFontFamily(const QFont &font); // 更新字体 + void updateFontFamily(const QFont &font); // 更新字体类别 void updateFontSizeF(int index); // 更新字体大小 void updateBold(int state); // 加粗 void updateItalic(int state); // 斜体 @@ -60,8 +64,7 @@ private slots: void updatefixedPitch(int state); // 固定字宽 void updateWeight(int i); // 字体粗细 - void accept_slots(); // 向DocTextBlock传递成功事件 - + void finished_slots( int value ); // 接受对话框的结果 }; diff --git a/ofdEditor/model/Widget/FontSettingDialog.ui b/ofdEditor/model/Widget/FontSettingDialog.ui index 4a0f631a51c695d81a37c311bfbe73530922915a..bb388b82f79fd310d04026b576396bc5bbd33457 100644 --- a/ofdEditor/model/Widget/FontSettingDialog.ui +++ b/ofdEditor/model/Widget/FontSettingDialog.ui @@ -6,8 +6,8 @@ 0 0 - 481 - 606 + 336 + 469 @@ -17,589 +17,399 @@ - Dialog + 字体设置窗口 - - - - 20 - 20 - 451 - 571 - - - - - - - - 200 - 250 - - - - - 480 - 400 - - - - 字体 - - - - - 10 - 30 - 421 - 184 - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - 粗体 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - 字体 - - - Qt::AlignCenter - - - - - - - 字号 - - - Qt::AlignCenter - - - - - - - 下划线 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - 字体效果预览 - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + 字体 + + + + + + 字体 + + + Qt::AlignCenter + + + + + + + 字号 + + + Qt::AlignCenter + + + + + + + 粗体 + + + + + + + 字体效果预览 + + + + + + + QComboBox::AdjustToContents + + + + 初号 + + + + + 小初 + + + + + 一号 + + + + + 小一 + + + + + 二号 + + + + + 小二 + + + + + 三号 + + + + + 小三 + + + + + 四号 + + + + + 小四 + + + + + 五号 + + + + + 小五 + + + + + 六号 + + + + + 小六 + + + + + 七号 + + + + + 八号 + + + + + 5 + + + + + 5.5 + + + + + 6.5 + + + + + 7.5 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 10.5 + + + + + 11 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + 24 + + + + + 26 + + + + + 28 + + + + + 36 + + + + + 48 + + + + + 72 + + + + + + + + + 150 + 100 + + + + + 200 + 100 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">文字测试样例</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Text Demo</p></body></html> - - - - - - - 斜体 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - QComboBox::AdjustToContents - - - - 初号 - - - - - 小初 - - - - - 一号 - - - - - 小一 - - - - - 二号 - - - - - 小二 - - - - - 三号 - - - - - 小三 - - - - - 四号 - - - - - 小四 - - - - - 五号 - - - - - 小五 - - - - - 六号 - - - - - 小六 - - - - - 七号 - - - - - 八号 - - - - - 5 - - - - - 5.5 - - - - - 6.5 - - - - - 7.5 - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 10.5 - - - - - 11 - - - - - 12 - - - - - 14 - - - - - 16 - - - - - 18 - - - - - 20 - - - - - 22 - - - - - 24 - - - - - 26 - - - - - 28 - - - - - 36 - - - - - 48 - - - - - 72 - - - - - - - - QComboBox::AdjustToContents - - - - 黑体 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - 200 - 200 - - - - - 480 - 400 - - - - 高级 - - - - - 10 - 30 - 421 - 151 - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - 字间距 - - - Qt::AlignCenter - - - - - - - true - - - 拉伸字体 - - - Qt::AlignCenter - - - - - - - 字体粗细 - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - 1000.000000000000000 - - - - - - - - - - 等宽字体 - - - - - - - 1 - - - 4000 - - - - - - - - - - - - 0 - 50 - - - - - 16777215 - 100 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 40 - - - - - - + + + + + + + QComboBox::AdjustToContents + + + + 黑体 + + + + + + + + 斜体 + + + + + + + 下划线 + + + + + + + + + + 高级 + + + + + + 1 + + + 4000 + + + + + + + 等宽字体 + + + + + + + + + + 字体粗细 + + + Qt::AlignCenter + + + + + + + 字间距 + + + Qt::AlignCenter + + + + + + + 1000.000000000000000 + + + + + + + true + + + 拉伸字体 + + + Qt::AlignCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 50 + + + + + 16777215 + 100 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/ofdEditor/model/Widget/InsertPageDialog.cpp b/ofdEditor/model/Widget/InsertPageDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1fcef991fcd752fcc2c4abd88a078232862a3b81 --- /dev/null +++ b/ofdEditor/model/Widget/InsertPageDialog.cpp @@ -0,0 +1,14 @@ +#include "InsertPageDialog.h" +#include "ui_InsertPageDialog.h" + +InsertPageDialog::InsertPageDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::InsertPageDialog) +{ + ui->setupUi(this); +} + +InsertPageDialog::~InsertPageDialog() +{ + delete ui; +} diff --git a/ofdEditor/model/Widget/InsertPageDialog.h b/ofdEditor/model/Widget/InsertPageDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..fb4c77d7c8458938adf04421bfd1adb052daabdb --- /dev/null +++ b/ofdEditor/model/Widget/InsertPageDialog.h @@ -0,0 +1,27 @@ +#ifndef INSERTPAGEDIALOG_H +#define INSERTPAGEDIALOG_H + +#include + +namespace Ui { +class InsertPageDialog; +} + +/// +/// \brief The InsertPageDialog class +/// 用来在页面中弹出,插入页面的类 +/// +class InsertPageDialog + : public QDialog +{ + Q_OBJECT + +public: + explicit InsertPageDialog(QWidget *parent = 0); + ~InsertPageDialog(); + +private: + Ui::InsertPageDialog *ui; +}; + +#endif // INSERTPAGEDIALOG_H diff --git a/ofdEditor/model/Widget/InsertPageDialog.ui b/ofdEditor/model/Widget/InsertPageDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..80701388209f484e49394e62b962f997560b9cc7 --- /dev/null +++ b/ofdEditor/model/Widget/InsertPageDialog.ui @@ -0,0 +1,68 @@ + + + InsertPageDialog + + + + 0 + 0 + 683 + 547 + + + + 插入页 + + + + + 220 + 440 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + buttonBox + accepted() + InsertPageDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + InsertPageDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ofdEditor/model/Widget/InsertTableDialog.cpp b/ofdEditor/model/Widget/InsertTableDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2a39bb61678b0e138a25fb8b8218a09a54eb8d8 --- /dev/null +++ b/ofdEditor/model/Widget/InsertTableDialog.cpp @@ -0,0 +1,14 @@ +#include "InsertTableDialog.h" +#include "ui_InsertTableDialog.h" + +InsertTableDialog::InsertTableDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::InsertTableDialog) +{ + ui->setupUi(this); +} + +InsertTableDialog::~InsertTableDialog() +{ + delete ui; +} diff --git a/ofdEditor/model/Widget/InsertTableDialog.h b/ofdEditor/model/Widget/InsertTableDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..c92a639e9a60af8075a53feba72f6e7cd28314d9 --- /dev/null +++ b/ofdEditor/model/Widget/InsertTableDialog.h @@ -0,0 +1,23 @@ +#ifndef INSERTTABLEDIALOG_H +#define INSERTTABLEDIALOG_H +#include "model_global.h" + +#include + +namespace Ui { +class InsertTableDialog; +} + +class MODELSHARED_EXPORT InsertTableDialog : public QDialog +{ + Q_OBJECT + +public: + explicit InsertTableDialog(QWidget *parent = 0); + ~InsertTableDialog(); + +private: + Ui::InsertTableDialog *ui; +}; + +#endif // INSERTTABLEDIALOG_H diff --git a/ofdEditor/model/Widget/InsertTableDialog.ui b/ofdEditor/model/Widget/InsertTableDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..db807c6da748702692963e02f132bc9c51a5f69b --- /dev/null +++ b/ofdEditor/model/Widget/InsertTableDialog.ui @@ -0,0 +1,176 @@ + + + InsertTableDialog + + + + 0 + 0 + 268 + 362 + + + + 插入表格 + + + + + + 0 + + + + 表格 + + + + + + 行数列数 + + + + + + 行数: + + + + + + + + + + 列数: + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 总体尺寸 + + + + + + 宽: + + + + + + + + + + mm + + + + + + + 高: + + + + + + + + + + mm + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + InsertTableDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + InsertTableDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ofdEditor/model/Widget/PageDialog.cpp b/ofdEditor/model/Widget/PageDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83279fc9e90a3f3c20972db47f7e902f8137f856 --- /dev/null +++ b/ofdEditor/model/Widget/PageDialog.cpp @@ -0,0 +1,641 @@ +#include "PageDialog.h" +#include "ui_PageDialog.h" +#include "../Doc/DocPassage.h" +#include "../Doc/DocPage.h" +#include +#include "../Tool/UnitTool.h" + +PageDialog* PageDialog::m_instance = NULL; + + + +/// +/// \brief PageDialog::getInstance +/// \return +/// +PageDialog *PageDialog::getInstance() +{ + if(m_instance != NULL) + { + return m_instance; + } + m_instance = new PageDialog(); + return m_instance; +} + +void PageDialog::DestoryInstance() +{ + m_instance = NULL; +} + +/// +/// \brief PageDialog::init +/// \param current_page +/// \param default_width +/// \param default_height +/// \param using_working_area +/// \param default_working_width +/// \param default_working_height +/// \param default_working_x +/// \param default_working_y +/// +void PageDialog::init( + DocPassage* passage, + DocPage *current_page, + double default_width, + double default_height, + bool using_working_area, + double default_working_width, + double default_working_height, + double default_working_x, + double default_working_y) +{ + + this->passage = passage; + this->current_page = current_page; + this->changed_page_numbers.clear(); + + ui->CurrentPageRadioButton->setChecked(true); // 选择 当前页 + ui->CurrentPageRadioButton->click(); // 点击,发送信号 + + ui->CurrentSelectPageSize->setCurrentIndex(0); // 暂时默认置零 + + if (this->current_page) + { + ui->CurrentPageSizeWidth->setValue( + toNearestInt( + current_page->getWidth())); + ui->CurrentPageSizeHeight->setValue( + toNearestInt( + current_page->getHeight())); + +// //Working area to be implemented!!!! + ui->CurrentWorkingAreaWidth->setValue( + toNearestInt( + current_page->getContentWidth())); + ui->CurrentWorkingAreaHeight->setValue( + toNearestInt( + current_page->getContentHeight())); + ui->CurrentWorkingAreaX->setValue( + toNearestInt( + current_page->getContentX())); + ui->CurrentWorkingAreaY->setValue( + toNearestInt( + current_page->getContentY())); + + ui->DefaultPageSizeWidth->setValue( + toNearestInt(default_height)); + ui->DefaultPageSizeHeight->setValue( + toNearestInt(default_width)); + + //Working area to be implemented!!!! + ui->DefaultSetWorkingAreaChecked->setChecked(using_working_area); + ui->DefaultWorkingAreaWidth->setValue( + toNearestInt(default_working_width)); + ui->DefaultWorkingAreaHeight->setValue( + toNearestInt(default_working_height)); + ui->DefaultWorkingAreaX->setValue( + toNearestInt(default_working_x)); + ui->DefaultWorkingAreaY->setValue( + toNearestInt(default_working_y)); + + this->isDefaultPageSizeChanged = false; // 是否修改了默认尺寸 + + this->connect(this, + SIGNAL(modifyPageSize( + QVector*, + double, + double, + bool, + double, + double, + double, + double)), + this->passage, + SLOT(modifyPageSize( + QVector*, + double, + double, + bool, + double, + double, + double, + double))); + + this->connect(this, + SIGNAL(modifyDefaultPageSize( + double, + double, + bool, + double, + double, + double, + double)), + this->passage, + SLOT(modifyDefaultPageSize( + double, + double, + bool, + double, + double, + double, + double))); + + + } +} + + +PageDialog::~PageDialog() +{ + delete ui; +} + + +/// +/// \brief PageDialog::PageDialog +/// \param parent +/// +PageDialog::PageDialog(QWidget *parent) + :QDialog(parent),ui(new Ui::PageDialog) +{ + ui->setupUi(this); + this->initConnect(); +} + +/// +/// \brief PageDialog::initConnect +/// 初始化 信号槽 +/// +void PageDialog::initConnect() +{ + //创建信号槽 + + // 四种模式的选择 + // 当前页 + this->connect(ui->CurrentPageRadioButton, + SIGNAL(toggled(bool)), + this, + SLOT(onCurrentPageRadioButtonToggled(bool))); + // 所有页面 + this->connect(ui->AllPagesRadioButton, + SIGNAL(toggled(bool)), + this, + SLOT(onAllPagesRadioButtonToggled(bool))); + // 页面范围 + this->connect(ui->PageRangeRadioButton, + SIGNAL(toggled(bool)), + this, + SLOT(onPageRangeRadioButtonToggled(bool))); + // 特殊页面 + this->connect(ui->SpecificPageRadioButton, + SIGNAL(toggled(bool)), + this, + SLOT(onSpecificPageRadioButtonToggled(bool))); + + + this->connect(ui->CurrentSetWorkingAreaChecked, + SIGNAL(clicked(bool)), + this, + SLOT(on_CurrentSetWorkingAreaChecked_clicked(bool))); + + this->connect(ui->DefaultSetWorkingAreaChecked, + SIGNAL(clicked(bool)), + this, + SLOT(on_DefaultSetWorkingAreaChecked_clicked(bool))); + + this->connect(ui->CurrentPageSizeHeight, + SIGNAL(editingFinished()), + this, + SLOT(on_CurrentPageSize_valueChanged())); + + this->connect(ui->CurrentPageSizeWidth, + SIGNAL(editingFinished()), + this, + SLOT(on_CurrentPageSize_valueChanged())); + + this->connect(ui->OkAndCancel, + SIGNAL(accepted()), + this, + SLOT(accept())); + + this->connect(ui->OkAndCancel, + SIGNAL(rejected()), + this, + SLOT(reject())); + + this->connect(ui->PageRangeLowerBound, + SIGNAL(valueChanged(int)), + this, + SLOT(page_range_range_changed())); + + this->connect(ui->PageRangeUpperBound, + SIGNAL(valueChanged(int)), + this, + SLOT(page_range_range_changed())); + + this->connect(ui->PageRangeLowerBound, + SIGNAL(valueChanged(int)), + this, + SLOT(changed_page_range_changed())); + + this->connect(ui->PageRangeUpperBound, + SIGNAL(valueChanged(int)), + this, + SLOT(changed_page_range_changed())); + + // 选择确定后的操作 + this->connect(this, SIGNAL(finished(int)), + this,SLOT(finished_slots(int))); + + // 判断是否修改过默认值 + this->connect(ui->DefaultPageSizeWidth, + SIGNAL(valueChanged(double)), + this, + SLOT(on_DefaultSizeChanged(double))); + + this->connect(ui->DefaultPageSizeHeight, + SIGNAL(valueChanged(double)), + this, + SLOT(on_DefaultSizeChanged(double))); + + this->connect(ui->DefaultWorkingAreaHeight, + SIGNAL(valueChanged(double)), + this, + SLOT(on_DefaultSizeChanged(double))); + + this->connect(ui->DefaultWorkingAreaWidth, + SIGNAL(valueChanged(double)), + this, + SLOT(on_DefaultSizeChanged(double))); + + this->connect(ui->DefaultWorkingAreaX, + SIGNAL(valueChanged(double)), + this, + SLOT(on_DefaultSizeChanged(double))); + + this->connect(ui->DefaultWorkingAreaY, + SIGNAL(valueChanged(double)), + this, + SLOT(on_DefaultSizeChanged(double))); + +} + +/// +/// \brief PageDialog::caculatePages +/// 计算选择了哪些页面 +/// +void PageDialog::caculatePages() +{ + if(ui->CurrentPageRadioButton->isChecked()) + { + // 当前页 + int i; + if (current_page) + { + for (i = 0; i < passage->getPages()->size(); i++) + if (passage->getPages()->operator [](i) == current_page) + break; + } + else i = 1; + changed_page_numbers.push_back(i+1); + } + else if(ui->AllPagesRadioButton->isChecked()) + { + // 所有页面 + for (int i = 0; i < passage->getPages()->size(); i++) + changed_page_numbers.push_back(i + 1); + } + else if(ui->PageRangeRadioButton->isChecked()) + { + // 页面范围 + int start = ui->PageRangeLowerBound->value(); // 开始 + int end = ui->PageRangeUpperBound->value(); // 截止 + for (int j = start ; j <= end; j++) + changed_page_numbers.push_back(j); + } + else if(ui->SpecificPageRadioButton->isChecked()) + { + // 特殊页面 + + } +} + +void PageDialog::on_CurrentSelectPageSize_currentIndexChanged(const QString &arg1) +{ + if (arg1 == tr("A4")) + { + ui->CurrentPageSizeWidth->setValue(210); + ui->CurrentPageSizeHeight->setValue(297); + } else if (arg1 == tr("A3")) + { + ui->CurrentPageSizeWidth->setValue(297); + ui->CurrentPageSizeHeight->setValue(420); + } else if (arg1 == tr("A5")) + { + ui->CurrentPageSizeWidth->setValue(148); + ui->CurrentPageSizeHeight->setValue(210); + } else if (arg1 == tr("Letter")) + { + ui->CurrentPageSizeWidth->setValue(216); + ui->CurrentPageSizeHeight->setValue(279); + } else if (arg1 == tr("16K")) + { + ui->CurrentPageSizeWidth->setValue(184); + ui->CurrentPageSizeHeight->setValue(260); + } else if (arg1 == tr("32K")) + { + ui->CurrentPageSizeWidth->setValue(130); + ui->CurrentPageSizeHeight->setValue(184); + } +} + +void PageDialog::on_DefaultSelectPageSize_currentIndexChanged(const QString &arg1) +{ + if (arg1 == tr("A4")) + { + ui->DefaultPageSizeWidth->setValue(210); + ui->DefaultPageSizeHeight->setValue(297); + } else if (arg1 == tr("A3")) + { + ui->DefaultPageSizeWidth->setValue(297); + ui->DefaultPageSizeHeight->setValue(420); + } else if (arg1 == tr("A5")) + { + ui->DefaultPageSizeWidth->setValue(148); + ui->DefaultPageSizeHeight->setValue(210); + } else if (arg1 == tr("Letter")) + { + ui->DefaultPageSizeWidth->setValue(216); + ui->DefaultPageSizeHeight->setValue(279); + } else if (arg1 == tr("16K")) + { + ui->DefaultPageSizeWidth->setValue(184); + ui->DefaultPageSizeHeight->setValue(260); + } else if (arg1 == tr("32K")) + { + ui->DefaultPageSizeWidth->setValue(130); + ui->DefaultPageSizeHeight->setValue(184); + } + this->isDefaultPageSizeChanged = true; +} + +void PageDialog::on_SpecificPageCheckBox_clicked(bool checked) +{ + if (checked) + { + ui->SpecificPage->setEnabled(true); +// !!!!!!!!!!!!!!!!!!!!!! + } + else + { + ui->SpecificPage->setText(""); + ui->SpecificPage->setEnabled(false); + } +} + +void PageDialog::on_CurrentSetWorkingAreaChecked_clicked(bool checked) +{ + if (checked) + { + ui->CurrentWorkingAreaWidth->setEnabled(true); + ui->CurrentWorkingAreaHeight->setEnabled(true); + ui->CurrentWorkingAreaX->setEnabled(true); + ui->CurrentWorkingAreaY->setEnabled(true); + } + else + { + ui->CurrentWorkingAreaWidth->setEnabled(false); + ui->CurrentWorkingAreaHeight->setEnabled(false); + ui->CurrentWorkingAreaX->setEnabled(false); + ui->CurrentWorkingAreaY->setEnabled(false); + ui->CurrentWorkingAreaWidth->setValue(ui->CurrentPageSizeWidth->value()); + ui->CurrentWorkingAreaHeight->setValue(ui->CurrentPageSizeHeight->value()); + ui->CurrentWorkingAreaX->setValue(0.0); + ui->CurrentWorkingAreaY->setValue(0.0); + } +} + +void PageDialog::on_DefaultSetWorkingAreaChecked_clicked(bool checked) +{ + if (checked) + { + ui->DefaultWorkingAreaWidth->setEnabled(true); + ui->DefaultWorkingAreaHeight->setEnabled(true); + ui->CurrentWorkingAreaX->setEnabled(true); + ui->CurrentWorkingAreaY->setEnabled(true); + } + else + { + ui->DefaultWorkingAreaWidth->setEnabled(false); + ui->DefaultWorkingAreaHeight->setEnabled(false); + ui->DefaultWorkingAreaX->setEnabled(false); + ui->DefaultWorkingAreaY->setEnabled(false); + ui->DefaultWorkingAreaWidth->setValue(ui->DefaultPageSizeWidth->value()); + ui->DefaultWorkingAreaHeight->setValue(ui->DefaultPageSizeHeight->value()); + ui->DefaultWorkingAreaX->setValue(0.0); + ui->DefaultWorkingAreaY->setValue(0.0); + } + + this->isDefaultPageSizeChanged = true; +} + +void PageDialog::on_DefaultSizeChanged(double value) +{ + this->isDefaultPageSizeChanged = true; +} + +void PageDialog::on_CurrentPageSize_valueChanged() +{ +// qDebug() << "Called"; + ui->CurrentSelectPageSize->setCurrentIndex(ui->CurrentSelectPageSize->findText(tr("Customized"))); +} + +/// +/// \brief PageDialog::onCurrentPageRadioButtonToggled +/// 选择只选择当前页 +/// \param checked +/// +void PageDialog::onCurrentPageRadioButtonToggled(bool checked) +{ + if(checked) + { + // 页码范围 + ui->PageRangeLowerBound->setEnabled(false); + ui->PageRangeUpperBound->setEnabled(false); + + // 特定 + ui->SpecificPage->setEnabled(false); + ui->SpecificPage->setText(""); + } +} + +/// +/// \brief PageDialog::onAllPagesRadioButtonToggled +/// \param checked +/// +void PageDialog::onAllPagesRadioButtonToggled(bool checked) +{ + if(checked) + { + // 页码范围 + ui->PageRangeLowerBound->setEnabled(false); + ui->PageRangeUpperBound->setEnabled(false); + + // 特定 + ui->SpecificPage->setEnabled(false); + ui->SpecificPage->setText(""); + } +} + +/// +/// \brief PageDialog::onPageRangeRadioButtonToggled +/// \param checked +/// +void PageDialog::onPageRangeRadioButtonToggled(bool checked) +{ + if(checked) + { + // 页码范围 + ui->PageRangeLowerBound->setEnabled(true); + ui->PageRangeUpperBound->setEnabled(true); + + int i; + if (current_page) + { + for (i = 0; i < passage->getPages()->size(); i++) + if (passage->getPages()->operator [](i) == current_page) + break; + } + else i = 1; + + ui->PageRangeLowerBound->setValue(i); + ui->PageRangeUpperBound->setValue( + passage->getPages()->size()); + ui->PageRangeLowerBound->setRange( + 1, + ui->PageRangeUpperBound->value()); + ui->PageRangeUpperBound->setRange( + ui->PageRangeLowerBound->value(), + passage->getPages()->size()); + + // 特定 + ui->SpecificPage->setEnabled(false); + ui->SpecificPage->setText(""); + } +} + +void PageDialog::onSpecificPageRadioButtonToggled(bool checked) +{ + if(checked) + { + // 页码范围 + ui->PageRangeLowerBound->setEnabled(false); + ui->PageRangeUpperBound->setEnabled(false); + + // 特定 + ui->SpecificPage->setEnabled(true); + } +} + +void PageDialog::page_range_range_changed() +{ + ui->PageRangeLowerBound->setRange( + 1, + ui->PageRangeUpperBound->value()); + ui->PageRangeUpperBound->setRange( + ui->PageRangeLowerBound->value(), + passage->getPages()->size()); +} + +void PageDialog::changed_page_range_changed() +{ + changed_page_numbers.clear(); + for (int j = ui->PageRangeLowerBound->value(); j <= ui->PageRangeUpperBound->value(); j++) + changed_page_numbers.push_back(j); +} + +/// +/// \brief PageDialog::emitInformation +/// +void PageDialog::emitInformation() +{ + + +} + +/// +/// \brief PageDialog::finished_slots +/// \param value +/// +void PageDialog::finished_slots(int value) +{ + if(value == QDialog::Accepted) + { + // 如果用户选择了确定 + this->caculatePages(); // 计算选择的页数 + emit this->modifyPageSize( + &changed_page_numbers, + ui->CurrentPageSizeWidth->value(), + ui->CurrentPageSizeHeight->value(), + ui->CurrentSetWorkingAreaChecked->isChecked(), + ui->CurrentWorkingAreaWidth->value(), + ui->CurrentWorkingAreaHeight->value(), + ui->CurrentWorkingAreaX->value(), + ui->CurrentWorkingAreaY->value()); + + if(isDefaultPageSizeChanged) + { + emit this->modifyDefaultPageSize( + ui->DefaultPageSizeWidth->value(), + ui->DefaultPageSizeHeight->value(), + ui->DefaultSetWorkingAreaChecked->isChecked(), + ui->DefaultWorkingAreaWidth->value(), + ui->DefaultWorkingAreaHeight->value(), + ui->DefaultWorkingAreaX->value(), + ui->DefaultWorkingAreaY->value()); + } + } + + // 断开链接 + this->disconnect(this, + SIGNAL(modifyPageSize( + QVector*, + double, + double, + bool, + double, + double, + double, + double)), + this->passage, + SLOT(modifyPageSize( + QVector*, + double, + double, + bool, + double, + double, + double, + double))); + + this->disconnect(this, + SIGNAL(modifyDefaultPageSize( + double, + double, + bool, + double, + double, + double, + double)), + this->passage, + SLOT(modifyDefaultPageSize( + double, + double, + bool, + double, + double, + double, + double))); +} + diff --git a/ofdEditor/model/Widget/PageDialog.h b/ofdEditor/model/Widget/PageDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..eacd315009804b64098ad4e7fdd269572aa53014 --- /dev/null +++ b/ofdEditor/model/Widget/PageDialog.h @@ -0,0 +1,97 @@ +#ifndef PAGEDIALOG_H +#define PAGEDIALOG_H + +#include +#include + +class DocPassage; +class DocPage; + + +namespace Ui { +class PageDialog; +} + +/// +/// \brief The PageDialog class +/// +class PageDialog + : public QDialog +{ + Q_OBJECT + +public: + + static PageDialog* getInstance(); // 获得单例 + static void DestoryInstance(); // 销毁实例 + void init( + DocPassage* passage, + DocPage * current_page, + double default_width, + double default_height, + bool using_working_area, + double default_working_width, + double default_working_height, + double default_working_x, + double default_working_y); // 初始化时调用 + ~PageDialog(); + +private: + explicit PageDialog(QWidget *parent = 0); // 构造函数 + void initConnect(); + int toNearestInt(double n){ return n + 0.5; } + + static PageDialog* m_instance; + void caculatePages(); + + +private slots: + + void on_CurrentSelectPageSize_currentIndexChanged(const QString &arg1); + void on_DefaultSelectPageSize_currentIndexChanged(const QString &arg1); + void on_SpecificPageCheckBox_clicked(bool checked); + void on_CurrentSetWorkingAreaChecked_clicked(bool checked); + void on_DefaultSetWorkingAreaChecked_clicked(bool checked); + void on_DefaultSizeChanged(double value); // 用来判断是否有修改过默认值 + void on_CurrentPageSize_valueChanged(); + + // 选择应用类型 + void onCurrentPageRadioButtonToggled(bool checked); + void onAllPagesRadioButtonToggled(bool checked); + void onPageRangeRadioButtonToggled(bool checked); + void onSpecificPageRadioButtonToggled(bool checked); + + void page_range_range_changed(); + void changed_page_range_changed(); + void emitInformation(); + void finished_slots(int value); // 完成使命 + +signals: + void modifyPageSize( + QVector * ch_pages, + double _width, + double _height, + bool isUsingWorkingArea, + double contentWidth, + double contentHeight, + double contentX, + double contentY); + + void modifyDefaultPageSize( + double default_width, + double default_height, + bool default_isUsingWorkingArea, + double default_contentWidth, + double default_contentHeight, + double default_contentX, + double default_contentY); + +private: + Ui::PageDialog *ui; + DocPassage *passage; + QVector changed_page_numbers; + DocPage * current_page; + bool isDefaultPageSizeChanged; +}; + +#endif // PAGEDIALOG_H diff --git a/ofdEditor/model/Widget/PageDialog.ui b/ofdEditor/model/Widget/PageDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..c6666313c339e6fa65d5dacc0dc7e73de060f354 --- /dev/null +++ b/ofdEditor/model/Widget/PageDialog.ui @@ -0,0 +1,780 @@ + + + PageDialog + + + + 0 + 0 + 465 + 456 + + + + 页面设置 + + + + + + 0 + + + + 当前页面 + + + + + + 页面设置 + + + + + + + 宋体 + 11 + + + + 页面尺寸 + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + 选择尺寸 + + + + + + + + A4 + + + + + A3 + + + + + A5 + + + + + Letter + + + + + 16K + + + + + 32K + + + + + Customized + + + + + + + + 设置工作区域 + + + + + + + + 宋体 + 11 + + + + 工作区域尺寸 + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + 工作区域位置 + + + + + + + + 宋体 + 11 + + + + 水平 + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + 垂直 + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + + + 应用于 + + + + + + 当前页 + + + + + + + 所有页 + + + + + + + 特定页数 + + + + + + + 10000 + + + + + + + + + + + Agency FB + 11 + + + + + + + + + + + + Agency FB + 11 + + + + + + + + + + + + Agency FB + 11 + + + + + + + + + + + + Agency FB + 11 + + + + 页码 + + + + + + + + + + 页面范围 + + + + + + + + + + + 默认页面 + + + + + + + + + + + + + 宋体 + 11 + + + + 页面尺寸 + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + 选择尺寸 + + + + + + + + A4 + + + + + A3 + + + + + A5 + + + + + Letter + + + + + 16K + + + + + 32K + + + + + Customized + + + + + + + + 设置工作区域 + + + + + + + + 宋体 + 11 + + + + 工作区域尺寸 + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + 工作区域位置 + + + + + + + + 宋体 + 11 + + + + 水平 + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + 宋体 + 11 + + + + 垂直 + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + mm + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + false + + + + + + + + diff --git a/ofdEditor/model/Widget/ParagraphFormatDialog.cpp b/ofdEditor/model/Widget/ParagraphFormatDialog.cpp index 561eb2e54864f7870232822a83c7a94cff723208..324216e52a21c66f79d056d9f1ef113e6b4d98dc 100644 --- a/ofdEditor/model/Widget/ParagraphFormatDialog.cpp +++ b/ofdEditor/model/Widget/ParagraphFormatDialog.cpp @@ -2,16 +2,64 @@ #include "ui_ParagraphFormatDialog.h" #include "Doc/DocTextBlock.h" +#include + +ParagraphFormatDialog* ParagraphFormatDialog::m_instance = NULL; // 初始化静态单例 + +/// +/// \brief ParagraphFormatDialog::getInstance +/// 获得实例 +/// \return +/// +ParagraphFormatDialog *ParagraphFormatDialog::getInstance() +{ + if( m_instance != NULL) + { + return m_instance; + } + + m_instance = new ParagraphFormatDialog(); + return m_instance; +} + +void ParagraphFormatDialog::DestoryInstance() +{ + // 考虑到是QT 组件,暂时不去释放内存 + m_instance = NULL; +} + +/// +/// \brief ParagraphFormatDialog::init +/// 每次使用单例时都需要将界面初始化一次s +/// \param blockFormat 需要进行设置的段落格式 +/// \param textBlock 留下文本框引用 +/// +void ParagraphFormatDialog::init( + QTextBlockFormat &blockFormat, + DocTextBlock *textBlock) +{ + + this->init(blockFormat); + this->textBlock = textBlock; // 留下引用,仅用来连接信号槽 + + connect(this, + SIGNAL(finished(QTextBlockFormat&)), + this->textBlock, + SLOT(setTextBlockFormat(QTextBlockFormat&))); // 连接信号和信号槽 + + +} ParagraphFormatDialog::ParagraphFormatDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ParagraphFormatDialog) { - + ui->setupUi(this); // 设置默认选项 QTextBlockFormat blockformat; this->init(blockformat); + } ParagraphFormatDialog::~ParagraphFormatDialog() @@ -19,23 +67,25 @@ ParagraphFormatDialog::~ParagraphFormatDialog() delete ui; } +/// +/// \brief ParagraphFormatDialog::getQTextBlockFormat +/// 从设置页面中获得设置结果 +/// \return +/// QTextBlockFormat ParagraphFormatDialog::getQTextBlockFormat() { QTextBlockFormat blockFormat; // 用来纪录格式的 Qt::Alignment horizontalFlag; -// Qt::Alignment verticalFlag; // 水平布局 int comboHAlignIndex = ui->comboHAlignment->currentIndex(); switch (comboHAlignIndex) { case 0: -// horizontalFlag = (Qt::AlignLeft | Qt::AlignAbsolute); horizontalFlag = (Qt::AlignLeft); break; case 1: -// horizontalFlag = (Qt::AlignRight | Qt::AlignAbsolute); horizontalFlag = (Qt::AlignRight); break; case 2: @@ -49,43 +99,8 @@ QTextBlockFormat ParagraphFormatDialog::getQTextBlockFormat() } -// // 竖直布局 -// int comboVAlignIndex = ui->comboVAlignment->currentIndex(); -// switch (comboVAlignIndex) { -// case 0: -// verticalFlag = Qt::AlignTop; -// break; -// case 1: -// verticalFlag = Qt::AlignBottom; -// break; -// case 2: -// verticalFlag = Qt::AlignVCenter; -// break; -// default: -// break; -// } - - // 设置布局规则 -// blockFormat.setAlignment(verticalFlag | horizontalFlag); blockFormat.setAlignment(horizontalFlag); -// // 设置文字方向 - // 无法使用,仅对部分语言有效 -// Qt::LayoutDirection textDirection; -// int textDirectionIndex = ui->comboTextDirection->currentIndex(); -// switch (textDirectionIndex) { -// case 0: -// textDirection = Qt::LeftToRight; -// break; -// case 1: -// textDirection = Qt::RightToLeft; -// break; -// default: -// textDirection = Qt::LeftToRight; -// break; -// } -// blockFormat.setLayoutDirection(textDirection); - // 缩进规则 int paraIndent = ui->paraIndent->value(); double firstIndent = ui->doubleFirstIndent->value(); @@ -93,7 +108,6 @@ QTextBlockFormat ParagraphFormatDialog::getQTextBlockFormat() blockFormat.setIndent(paraIndent); blockFormat.setTextIndent(firstIndent); - // 设置段前段后 double spaceBefore = ui->doubleBefor->value(); double spaceAfter = ui->doubleAfter->value(); @@ -128,18 +142,6 @@ QTextBlockFormat ParagraphFormatDialog::getQTextBlockFormat() return blockFormat; } -ParagraphFormatDialog::ParagraphFormatDialog( - const QTextBlockFormat &blockFormat, - DocTextBlock *textBlock, QWidget *parent) - :QDialog(parent), - ui(new Ui::ParagraphFormatDialog) -{ - this->init(blockFormat); - this->textBlock = textBlock; // 留下引用,仅用来连接信号槽 - - connect(this, SIGNAL(finished(QTextBlockFormat&)), - this->textBlock, SLOT(setTextBlockFormat(QTextBlockFormat&))); // 连接信号和信号槽 -} /** * @Author Chaoqun @@ -150,19 +152,16 @@ ParagraphFormatDialog::ParagraphFormatDialog( */ void ParagraphFormatDialog::init(const QTextBlockFormat &blockFormat) { - ui->setupUi(this); // 此信号槽用来将accepted信号接收,然后通过函数发送finished信号 - connect(this,SIGNAL(accepted()), - this,SLOT(accept_slots())); + connect(this, SIGNAL(finished(int)), + this, SLOT(finished_slots(int))); // 设置对齐部分 Qt::Alignment flag = blockFormat.alignment(); // 先获取对齐的样式 Qt::Alignment horizontalFlag; -// Qt::Alignment verticalFlag; horizontalFlag = flag & Qt::AlignHorizontal_Mask; -// verticalFlag = flag & Qt::AlignVertical_Mask; // 水平对齐 switch (horizontalFlag) { @@ -183,43 +182,6 @@ void ParagraphFormatDialog::init(const QTextBlockFormat &blockFormat) break; } -// // 竖直对齐 -// switch (verticalFlag) { -// case Qt::AlignTop: -// ui->comboVAlignment->setCurrentIndex(0); -// break; -// case Qt::AlignBottom: -// ui->comboVAlignment->setCurrentIndex(1); -// break; -// case Qt::AlignCenter: -// ui->comboVAlignment->setCurrentIndex(2); -// break; -// default: -// ui->comboVAlignment->setCurrentIndex(-1); -// break; -// } - - // 因竖直对齐的调整并没有效果,这里选择去掉 - this->ui->comboVAlignment->setVisible(false); - this->ui->label_12->setVisible(false); - -// 因为文字方向无法使用,所以将其隐藏掉 -// //文字方向 -// Qt::LayoutDirection textDirection = blockFormat.layoutDirection(); -// switch (textDirection) { -// case Qt::LeftToRight: -// ui->comboTextDirection->setCurrentIndex(0); -// break; -// case Qt::RightToLeft: -// ui->comboTextDirection->setCurrentIndex(1); -// break; -// default: -// ui->comboTextDirection->setCurrentIndex(0); -// break; -// } - this->ui->comboTextDirection->setVisible(false); - this->ui->label_13->setVisible(false); - // 整段缩进 int indent = blockFormat.indent(); ui->paraIndent->setValue(indent); @@ -238,7 +200,6 @@ void ParagraphFormatDialog::init(const QTextBlockFormat &blockFormat) ui->doubleAfter->setValue(bottomMargin); // 行高 -// QTextBlockFormat::LineHeightTypes lineHeightTypes; int lineHeightTypes; lineHeightTypes = blockFormat.lineHeightType(); @@ -264,17 +225,26 @@ void ParagraphFormatDialog::init(const QTextBlockFormat &blockFormat) double lineHeightValue = blockFormat.lineHeight(); ui->doubleLineHight->setValue(lineHeightValue); + qDebug() << "LineHeightType" << lineHeightTypes + << "Value" << lineHeightValue; + + } -/** - * @Author Chaoqun - * @brief 绑定accepted信号,用来向外界发送信号 - * @param void - * @return void - * @date 2017/05/22 - */ -void ParagraphFormatDialog::accept_slots() +/// +/// \brief ParagraphFormatDialog::finished_slots +/// \param value +/// +void ParagraphFormatDialog::finished_slots(int value) { - QTextBlockFormat blockFormat = this->getQTextBlockFormat(); - emit this->finished(blockFormat); + if(value == QDialog::Accepted) + { + QTextBlockFormat blockFormat = this->getQTextBlockFormat(); + emit this->finished(blockFormat); + } + + disconnect(this, + SIGNAL(finished(QTextBlockFormat&)), + this->textBlock, + SLOT(setTextBlockFormat(QTextBlockFormat&))); // 断开信号与槽链接 } diff --git a/ofdEditor/model/Widget/ParagraphFormatDialog.h b/ofdEditor/model/Widget/ParagraphFormatDialog.h index c440a7abcaa6299538638b018fb1371c0253510f..a921347b3785258e28968bc5c3d83573a688fdc6 100644 --- a/ofdEditor/model/Widget/ParagraphFormatDialog.h +++ b/ofdEditor/model/Widget/ParagraphFormatDialog.h @@ -4,7 +4,6 @@ #include "model_global.h" #include #include -//#include "Doc/DocTextBlock.h" class DocTextBlock; @@ -12,18 +11,23 @@ namespace Ui { class MODELSHARED_EXPORT ParagraphFormatDialog; } -class MODELSHARED_EXPORT ParagraphFormatDialog : public QDialog +/// +/// \brief The ParagraphFormatDialog class +/// +class MODELSHARED_EXPORT ParagraphFormatDialog + : public QDialog { Q_OBJECT public: + static ParagraphFormatDialog* getInstance(); // 获得实例 + static void DestoryInstance(); // 销毁实例 + void init(QTextBlockFormat &blockFormat, + DocTextBlock* textBlock); // 每次使用时的初始化 + // 构造函数 explicit ParagraphFormatDialog(QWidget *parent = 0); - ParagraphFormatDialog(const QTextBlockFormat& blockFormat, - DocTextBlock * textBlock, - QWidget *parent = 0); - ~ParagraphFormatDialog(); // 自定义信号 @@ -34,13 +38,14 @@ signals: private: Ui::ParagraphFormatDialog *ui; DocTextBlock * textBlock; // 引用,将该效果作用于哪个文字之上 + static ParagraphFormatDialog* m_instance; // 实例 QTextBlockFormat getQTextBlockFormat(); // 从选项中得到QTextBlockFormat void init(const QTextBlockFormat & blockFormat); private slots: - void accept_slots(); // 用来绑定 QDialog的 accepted信号 + void finished_slots(int value); // 用户点击 }; #endif // PARAGRAPHFORMATDIALOG_H diff --git a/ofdEditor/model/Widget/ParagraphFormatDialog.ui b/ofdEditor/model/Widget/ParagraphFormatDialog.ui index c5adafc2e758005709db06753eb88cc5d43053d4..a89f418ce3fc91124a2d4b6c5faa90ddd5dfa355 100644 --- a/ofdEditor/model/Widget/ParagraphFormatDialog.ui +++ b/ofdEditor/model/Widget/ParagraphFormatDialog.ui @@ -6,8 +6,8 @@ 0 0 - 480 - 640 + 340 + 494 @@ -17,284 +17,230 @@ - Dialog + 段落 false - - - - 10 - 30 - 451 - 451 - - - - - - - 对齐方式 - - - - - 10 - 30 - 261 - 91 - - - - - - - 水平 - - + + + + + 对齐方式 + + + + + + 水平 + + + + + + + 0 + + + QComboBox::AdjustToContents + + + + 左对齐 + - - - - 0 - - - QComboBox::AdjustToContents - - - - 左对齐 - - - - - 右对齐 - - - - - 居中 - - - - - 两端对齐 - - - + + + 右对齐 + - - - - 竖直 - - + + + 居中 + - - - - QComboBox::AdjustToContents - - - - 居上 - - - - - 居下 - - - - - 居中 - - - + + + 两端对齐 + - - - - 文字方向 - - + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 缩进 + + + + + + 整体缩进 + + + + + + + 10000 + + + + + + + 首行缩进 + + + + + + + 10000.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 间距 + + + + + + 段前 + + + + + + + 10000.000000000000000 + + + + + + + 段后 + + + + + + + 10000.000000000000000 + + + + + + + 行距策略 + + + + + + + QComboBox::AdjustToContents + + + + 单倍行距 + - - - - QComboBox::AdjustToContents - - - - 左到右 - - - - - 右到左 - - - + + + 多倍行距 + - - - - - - - - 缩进 - - - - - 10 - 30 - 261 - 81 - - - - - - - 整体缩进 - - + + + 固定值 + - - - - 10000 - - + + + 最小值 + - - - - 首行缩进 - - - - - - - 10000.000000000000000 - - - - - - - - - - - 间距 - - - - - 10 - 30 - 431 - 91 - - - - - - - 段前 - - - - - - - 10000.000000000000000 - - - - - - - 段后 - - - - - - - 10000.000000000000000 - - - - - - - 行距策略 - - - - - - - QComboBox::AdjustToContents - - - - 单倍行距 - - - - - 多倍行距 - - - - - 固定值 - - - - - 最小值 - - - - - - - - - - - - - - - 10000.000000000000000 - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - + + + + + + + + + + + + + 10000.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/ofdEditor/model/Widget/ParagraphFormatWidget.cpp b/ofdEditor/model/Widget/ParagraphFormatWidget.cpp deleted file mode 100644 index 919781f6c93c858f707cb0c81da7f4fcfee51eac..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Widget/ParagraphFormatWidget.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "ParagraphFormatWidget.h" -#include "ui_ParagraphFormatWidget.h" - -ParagraphFormatWidget::ParagraphFormatWidget(QWidget *parent) : - QWidget(parent), - ui(new Ui::ParagraphFormatWidget) -{ - ui->setupUi(this); // 安装ui文件 - this->init(); - this->setWindowFlags(Qt::Dialog); -} - -ParagraphFormatWidget::~ParagraphFormatWidget() -{ - delete ui; -} - -ParagraphFormatWidget::ParagraphFormatWidget( - const QTextBlockFormat &blockFormat, QWidget *parent) - :QWidget(parent),ui(new Ui::ParagraphFormatWidget) -{ - ui->setupUi(this); // 安装ui文件 - this->init(blockFormat); // 初始化 - -} - -void ParagraphFormatWidget::init() -{ - -} - -void ParagraphFormatWidget::init(const QTextBlockFormat &blockFormat) -{ - -} - -void ParagraphFormatWidget::closeWidget() -{ - -} diff --git a/ofdEditor/model/Widget/ParagraphFormatWidget.h b/ofdEditor/model/Widget/ParagraphFormatWidget.h deleted file mode 100644 index 1f0916cf925dac1faec02f0de48a2afa64ecdb34..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Widget/ParagraphFormatWidget.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef PARAGRAPHFORMATWIDGET_H -#define PARAGRAPHFORMATWIDGET_H - -#include - -#include - -namespace Ui { -class ParagraphFormatWidget; -} - -class ParagraphFormatWidget : public QWidget -{ - Q_OBJECT - -public: - explicit ParagraphFormatWidget(QWidget *parent = 0); - ~ParagraphFormatWidget(); - ParagraphFormatWidget(const QTextBlockFormat& blockFormat, - QWidget *parent = 0); - -signals: - void finished(int ok, QTextBlockFormat& blockFormat); // 信号 - -private: - Ui::ParagraphFormatWidget *ui; // 界面函数 - void init(); // 初始化函数 - void init( const QTextBlockFormat& blockFormat); // 初始化函数 - -private slots: - void closeWidget(); -}; - -#endif // PARAGRAPHFORMATWIDGET_H diff --git a/ofdEditor/model/Widget/ParagraphFormatWidget.ui b/ofdEditor/model/Widget/ParagraphFormatWidget.ui deleted file mode 100644 index a4b4401bc2f678468393944bb293657859778e15..0000000000000000000000000000000000000000 --- a/ofdEditor/model/Widget/ParagraphFormatWidget.ui +++ /dev/null @@ -1,383 +0,0 @@ - - - ParagraphFormatWidget - - - Qt::NonModal - - - - 0 - 0 - 480 - 640 - - - - - 400 - 600 - - - - - 3940 - 2080 - - - - - 宋体 - 12 - - - - 段落属性 - - - - - 0 - 50 - 431 - 421 - - - - - - - - - - - 16 - - - - 常规 - - - Qt::AutoText - - - Qt::AlignCenter - - - - - - - 对齐方式: - - - - - - - QComboBox::AdjustToMinimumContentsLength - - - 10 - - - - 左对齐 - - - - - 右对齐 - - - - - 居中 - - - - - 自动对齐 - - - - - - - - 文字方向 - - - - - - - QComboBox::AdjustToMinimumContentsLength - - - 10 - - - - 自左向右 - - - - - 自右向左 - - - - - - - - Qt::Horizontal - - - - - - - - 宋体 - 16 - - - - 缩进 - - - Qt::AlignCenter - - - - - - - 整体缩进 - - - - - - - Qt::AlignCenter - - - - - - - 首行缩进 - - - - - - - Qt::AlignCenter - - - - - - - Qt::Horizontal - - - - - - - - 宋体 - 16 - - - - 间距 - - - Qt::AlignCenter - - - - - - - 段前 - - - - - - - Qt::AlignCenter - - - - - - - 段后 - - - - - - - Qt::AlignCenter - - - - - - - 行高策略 - - - - - - - QComboBox::AdjustToMinimumContentsLength - - - 10 - - - - 单倍行高 - - - - - 多倍行高 - - - - - 固定值 - - - - - 最小值 - - - - - - - - 行高值 - - - - - - - Qt::AlignCenter - - - - - - - Qt::Horizontal - - - - - - - - 宋体 - 16 - - - - 边距 - - - Qt::AlignCenter - - - - - - - 上边距 - - - - - - - Qt::AlignCenter - - - - - - - 左边距 - - - - - - - Qt::AlignCenter - - - - - - - 下边距 - - - - - - - Qt::AlignCenter - - - - - - - 右边距 - - - - - - - Qt::AlignCenter - - - - - - - 确定 - - - - - - - 取消 - - - - - - - - - diff --git a/ofdEditor/model/Widget/SelectTemplateDialog.cpp b/ofdEditor/model/Widget/SelectTemplateDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..693b9818e7f53906b382a458923d0bf2b0e9c8dd --- /dev/null +++ b/ofdEditor/model/Widget/SelectTemplateDialog.cpp @@ -0,0 +1,74 @@ +#include "SelectTemplateDialog.h" +#include "ui_SelectTemplateDialog.h" +#include +# +SelectTemplateDialog::SelectTemplateDialog(QWidget *parent, PassageMainWindow * mainwindow) : + QDialog(parent), + ui(new Ui::SelectTemplateDialog) +{ + ui->setupUi(this); + this->mainwindow = mainwindow; + //初始化成员 + current_template_index = 0; + ui->CountLabel->setAlignment(Qt::AlignCenter); + //置入模板Icon + this->icons.push_back(new QPixmap(":/template_icon/template_icons/template_1.png")); +// qDebug() << "Icon 1 is null: " << icons[0]->isNull(); + this->icons.push_back(new QPixmap(":/template_icon/template_icons/template_2 .png")); + this->icons.push_back(new QPixmap(":/template_icon/template_icons/template_3.png")); + this->icons.push_back(new QPixmap(":/template_icon/template_icons/template_4.png")); + this->icons.push_back(new QPixmap(":/template_icon/template_icons/template_5.png")); + + ui->TemplateIcon->setPixmap(*(icons[current_template_index])); + ui->CountLabel->setText(QString::number(current_template_index + 1) + + "/" + QString::number(icons.size())); + + //链接信号槽 + this->connect(ui->NextTemplateButton, + SIGNAL(clicked(bool)), + this, + SLOT(nextTemplate())); + this->connect(ui->LastTemplateButton, + SIGNAL(clicked(bool)), + this, + SLOT(lastTemplate())); + this->connect(ui->buttonBox, + SIGNAL(accepted()), + this, + SLOT(emitCreateTemplateSignal())); +} + +SelectTemplateDialog::~SelectTemplateDialog() +{ + delete ui; +} + + +void SelectTemplateDialog::nextTemplate() +{ + if (current_template_index + 1 < icons.size()) + { + current_template_index++; + ui->TemplateIcon->setPixmap(*icons[current_template_index]); + ui->CountLabel->setText(QString::number(current_template_index + 1) + + "/" + QString::number(icons.size())); + } +} + +void SelectTemplateDialog::lastTemplate() +{ + if (current_template_index - 1 >= 0) + { + current_template_index--; + ui->TemplateIcon->setPixmap(*icons[current_template_index]); + ui->CountLabel->setText(QString::number(current_template_index + 1) + + "/" + QString::number(icons.size())); + } +} + +void SelectTemplateDialog::emitCreateTemplateSignal() +{ + qDebug() << "Emit create template signal."; +// emit createTemplate(current_template_index); + emit createTemplate(0); +} diff --git a/ofdEditor/model/Widget/SelectTemplateDialog.h b/ofdEditor/model/Widget/SelectTemplateDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..f0a0359f23c3ed718fb6a422bfe8392074069482 --- /dev/null +++ b/ofdEditor/model/Widget/SelectTemplateDialog.h @@ -0,0 +1,40 @@ +#ifndef SELECTTEMPLATEDIALOG_H +#define SELECTTEMPLATEDIALOG_H + +#include +#include +#include +#include + +class PassageMainWindow; + +namespace Ui { +class SelectTemplateDialog; +} + +class MODELSHARED_EXPORT SelectTemplateDialog + : public QDialog +{ + Q_OBJECT + +public: + explicit SelectTemplateDialog(QWidget *parent, PassageMainWindow * mainwindow); + ~SelectTemplateDialog(); + +private: + Ui::SelectTemplateDialog *ui; + PassageMainWindow * mainwindow; + int current_template_index; + QVector icons; + +private slots: + void nextTemplate(); + void lastTemplate(); + void emitCreateTemplateSignal(); + +signals: + void createTemplate(int index); +}; + + +#endif // SELECTTEMPLATEDIALOG_H diff --git a/ofdEditor/model/Widget/SelectTemplateDialog.ui b/ofdEditor/model/Widget/SelectTemplateDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..ce61bafd3e985993d7da26c27e442a4dd3a0fd9b --- /dev/null +++ b/ofdEditor/model/Widget/SelectTemplateDialog.ui @@ -0,0 +1,165 @@ + + + SelectTemplateDialog + + + + 0 + 0 + 401 + 459 + + + + 选择模版 + + + + + 29 + 406 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 97 + 70 + 201 + 291 + + + + + + + :/template_icons/source/templates/template_1.png + + + + + + 19 + 17 + 101 + 21 + + + + + Arial + 12 + 50 + false + + + + 选择页面模板 + + + + + + 124 + 21 + 251 + 16 + + + + Qt::Horizontal + + + + + + 35 + 410 + 75 + 23 + + + + 上一个 + + + + + + 118 + 410 + 75 + 23 + + + + 下一个 + + + + + + 158 + 370 + 71 + 16 + + + + + Arial + 11 + 50 + false + + + + + + + + + + + buttonBox + accepted() + SelectTemplateDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SelectTemplateDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ofdEditor/model/Widget/TableSettingDialog.cpp b/ofdEditor/model/Widget/TableSettingDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62081e8c96c21d12aa1ba24c2cd816603d36c3f7 --- /dev/null +++ b/ofdEditor/model/Widget/TableSettingDialog.cpp @@ -0,0 +1,240 @@ +#include "TableSettingDialog.h" +#include "ui_TableSettingDialog.h" +#include "Doc/DocTable.h" +#include "Doc/DocBlock.h" +#include "Tool/UnitTool.h" +#include +#include +#include + +TableSettingDialog * TableSettingDialog::m_instance = NULL; + +TableSettingDialog::TableSettingDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::TableSettingDialog) +{ + ui->setupUi(this); + + connect(ui->balanceCol, SIGNAL(clicked(bool)), + this, SLOT(slot_selectBalanceCol())); + + connect(ui->customCol, SIGNAL(clicked(bool)), + this, SLOT(slot_selectCustomCol())); + + connect(this, SIGNAL(finished(int)), + this, SLOT(finished_slots(int))); + + connect(ui->table_color, SIGNAL(clicked(bool)), + this, SLOT(setColor())); +} + +/// +/// \brief TableSettingDialog::slot_selectBalanceCol +/// +void TableSettingDialog::slot_selectBalanceCol() +{ + this->isDefaultCellWidth = true; + + ui->setTableCellWidth->clear(); + int length = this->_table->getColumns(); + ui->setTableCellWidth->setColumnCount(length); + ui->setTableCellWidth->horizontalHeader()->setResizeMode( + QHeaderView::Stretch); + + for(int i =0; i < length; i++) + { + this->cellWidth.append( + QTextLength( + QTextLength::PercentageLength,(100.0 / length))); + } + +} + +/// +/// \brief TableSettingDialog::slot_selectCustomCol +/// +void TableSettingDialog::slot_selectCustomCol() +{ + this->isDefaultCellWidth = false; + + ui->setTableCellWidth->clear(); + int length = this->_table->getColumns(); + this->cellWidth = this->_table->getColumnWidth(); + ui->setTableCellWidth->setColumnCount(length); + ui->setTableCellWidth->horizontalHeader()->setResizeMode( + QHeaderView::Interactive); + ui->setTableCellWidth->horizontalHeader()->setResizeMode( + length-1, QHeaderView::Stretch); + + for(int i = 0; i < length; i++) + { + ui->setTableCellWidth->setHorizontalHeaderItem( + i, new QTableWidgetItem(QString::number(i+1))); + ui->setTableCellWidth->setColumnWidth( + i, ui->setTableCellWidth->viewport()->width() *this->cellWidth[i].rawValue() / 100); + } + +} + +void TableSettingDialog::setColor() +{ + QColor color = QColorDialog::getColor(this->tableColor, + NULL, + tr("Choose table border color")); + if(color.isValid()) + { + this->tableColor = color; + } +} + +/// +/// \brief TableSettingDialog::finished_slots +/// \param value +/// +void TableSettingDialog::finished_slots(int value) +{ + this->tableWidth_mm = ui->tableWidth->value(); + this->cellPadding = ui->cellPadding->value(); + this->tableX_mm = ui->table_x->value(); + this->tableY_mm = ui->table_y->value(); + + if(!this->isDefaultCellWidth) + { + // 如果是自定义列宽的话 + int length = this->_table->getColumns(); + this->cellWidth.clear(); + for(int i=0; icellWidth.append( + QTextLength( + QTextLength::PercentageLength, + 1.0 * ui->setTableCellWidth->columnWidth(i) / ui->setTableCellWidth->width() * 100.0)); + } + } + + if(value = QDialog::Accepted) + { + this->_table->setTableWidth( + UnitTool::mmToPixel(this->tableWidth_mm)); + this->_table->setCellPadding( + UnitTool::mmToPixel(this->cellPadding)); + this->_table->getBlock()->setPos( + UnitTool::mmToPixel(this->tableX_mm), + UnitTool::mmToPixel(this->tableY_mm)); + this->_table->setTableColor(this->tableColor); + this->_table->setDefaultStyle(this->isDefaultCellWidth); + + if(!this->isDefaultCellWidth) + { + this->_table->setColumnWidth(this->cellWidth); + } + + this->_table->setTableColor(this->tableColor); + } + +} + +TableSettingDialog *TableSettingDialog::getInstance() +{ + if(m_instance == NULL) + { + m_instance = new TableSettingDialog(); + } + + return m_instance; +} + +void TableSettingDialog::destroyInstance() +{ + delete m_instance; + m_instance = NULL; +} + +TableSettingDialog *TableSettingDialog::getInstance(DocTable *table) +{ + if(m_instance == NULL) + { + m_instance = new TableSettingDialog(); + } + + m_instance->init(table); + return m_instance; +} + +void TableSettingDialog::init(DocTable *table) +{ + this->_table = table; + // 表格整体宽度 + this->tableWidth_mm = UnitTool::pixelToMM( + table->getBlock()->size().rwidth()); + + // 表格整体位置 + this->tableX_mm = UnitTool::pixelToMM( + table->getBlock()->x()); + this->tableY_mm = UnitTool::pixelToMM( + table->getBlock()->y()); + + // 单元格留白 + this->cellPadding = UnitTool::pixelToMM( + table->cellPadding()); + + // 颜色 + this->tableColor = table->getTableColor(); + + // 是否均分 + this->isDefaultCellWidth = table->isDefaultWidth(); + + this->cellWidth.clear(); + this->cellWidth = table->getColumnWidth(); + + + ui->tableWidth->setValue(this->tableWidth_mm); + ui->table_x->setValue(this->tableX_mm); + ui->table_y->setValue(this->tableY_mm); + + ui->cellPadding->setValue(this->cellPadding); + this->cellWidth.clear(); + if(this->isDefaultCellWidth) + { + ui->balanceCol->setChecked(true); + ui->setTableCellWidth->clear(); + int length = table->getColumns(); + ui->setTableCellWidth->setColumnCount(length); + ui->setTableCellWidth->horizontalHeader()->setResizeMode( + QHeaderView::Stretch); + + for(int i =0; i < length; i++) + { + this->cellWidth.append( + QTextLength( + QTextLength::PercentageLength,(100.0 / length))); + } + + } + else + { + ui->customCol->setChecked(true); + ui->setTableCellWidth->clear(); + int length = table->getColumns(); + this->cellWidth = table->getColumnWidth(); + ui->setTableCellWidth->setColumnCount(length); + ui->setTableCellWidth->horizontalHeader()->setResizeMode( + QHeaderView::Interactive); + ui->setTableCellWidth->horizontalHeader()->setStretchLastSection(true); + + for(int i = 0; i < length; i++) + { + ui->setTableCellWidth->setHorizontalHeaderItem( + i, new QTableWidgetItem(QString::number(i+1))); + ui->setTableCellWidth->setColumnWidth( + i, ui->setTableCellWidth->viewport()->width() *this->cellWidth[i].rawValue() / 100); + } + + } + +} + +TableSettingDialog::~TableSettingDialog() +{ + delete ui; +} diff --git a/ofdEditor/model/Widget/TableSettingDialog.h b/ofdEditor/model/Widget/TableSettingDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..a95f01452e310644766071f8528d7f450596b036 --- /dev/null +++ b/ofdEditor/model/Widget/TableSettingDialog.h @@ -0,0 +1,60 @@ +#ifndef TABLESETTINGDIALOG_H +#define TABLESETTINGDIALOG_H + +#include +#include +#include "model_global.h" +#include +#include + + +class DocTable; + +namespace Ui { +class TableSettingDialog; +} + +class MODELSHARED_EXPORT TableSettingDialog + : public QDialog +{ + Q_OBJECT + +public: + + static TableSettingDialog* getInstance(); + static void destroyInstance(); + static TableSettingDialog* getInstance(DocTable* table); + void init(DocTable* table); + + ~TableSettingDialog(); + +private: + explicit TableSettingDialog(QWidget *parent = 0); + Ui::TableSettingDialog *ui; + static TableSettingDialog* m_instance; // instance + DocTable* _table; // 存储下临时可用的表格 + + int rows; + int columns; + + double tableWidth_mm; // 表格宽度 mm + double tableX_mm; // 表格左上角位置 + double tableY_mm; + double cellPadding; //单元格留白 + QVector cellWidth; // 单元格的宽度 + bool isDefaultCellWidth; // 是否均分列宽 + + QColor tableColor; // 表格颜色 + +private slots: + + void slot_selectBalanceCol(); // 选择等分 + void slot_selectCustomCol(); // 选择自定义调整列宽 + void setColor(); // 点击按钮修改颜色 + + + void finished_slots( int value ); // 完成后调用 + +}; + +#endif // TABLESETTINGDIALOG_H diff --git a/ofdEditor/model/Widget/TableSettingDialog.ui b/ofdEditor/model/Widget/TableSettingDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..eee8205ce2b6fb3524bcbe53d6b9e1d5016fc3fe --- /dev/null +++ b/ofdEditor/model/Widget/TableSettingDialog.ui @@ -0,0 +1,475 @@ + + + TableSettingDialog + + + + 0 + 0 + 334 + 574 + + + + 表格设置 + + + + + + <html><head/><body><p>大小位置</p></body></html> + + + 0 + + + + 大小位置 + + + + + + 表格线条颜色 + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 颜色 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 总体大小 + + + + + + 表格宽度: + + + + + + + 10000.000000000000000 + + + + + + + mm + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 位置 + + + + + + 距左方 + + + + + + + 距上方 + + + + + + + mm + + + + + + + mm + + + + + + + 10000.000000000000000 + + + + + + + 10000990000.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 单元格留白 + + + + + + 10000.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 单元格留白 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + mm + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 列宽 + + + + + + 列宽模式 + + + + + + 均等分列宽 + + + true + + + + + + + 自定义列宽 + + + + + + + + + + 100 + + + 10 + + + false + + + false + + + + New Row + + + + + New Column + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + TableSettingDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TableSettingDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ofdEditor/model/Widget/imagepropertiesdialog.cpp b/ofdEditor/model/Widget/imagepropertiesdialog.cpp index 0ad83ec3e330cfe336dbbd06632e219531dd2a7f..05ffb1eac0f56f1cc3ded88d5979b75c1de4b05a 100644 --- a/ofdEditor/model/Widget/imagepropertiesdialog.cpp +++ b/ofdEditor/model/Widget/imagepropertiesdialog.cpp @@ -1,113 +1,200 @@ #include "imagepropertiesdialog.h" #include "ui_imagepropertiesdialog.h" +#include "Doc/DocPage.h" +#include "Doc/DocImageBlock.h" +#include "Tool/UnitTool.h" #include -/** - * @Author Pan - * @brief 构造函数,完成了成员组件的初始化、设置,以及信号槽的连接 - * @param DocImageBlock * _block, QWidget * parent - * @return - * @date 2017/06/25 - */ -ImagePropertiesDialog::ImagePropertiesDialog(DocImageBlock * _block, QWidget *parent) : - QDialog(parent), - ui(new Ui::ImagePropertiesDialog), - block(_block) + +ImagePropertiesDialog* ImagePropertiesDialog::m_instance = NULL; // 静态变量初始化 + +/// +/// \brief ImagePropertiesDialog::getInstance +/// 获得单例 +/// \return +/// +ImagePropertiesDialog *ImagePropertiesDialog::getInstance() { - ui->setupUi(this); - this->connect(_block, - SIGNAL(sendImageInfo(double,double, - double,double, - double,double,bool)), - this, - SLOT(receiveImageInfo(double,double, - double,double, - double,double,bool))); - - ui->WidthInPixel->setRange(0.0, 100000); - ui->HeightInPixel->setRange(0.0, 100000); - ui->xInPixel->setRange(0.0, 10000); - ui->yInPixel->setRange(0.0, 10000); - ui->WidthInPercentage->setRange(0.0, 10000.0); - ui->HeightInPercentage->setRange(0.0, 10000.0); - ui->xInPercentage->setRange(0.0, 100.0); - ui->yInPercentage->setRange(0.0, 100.0); - this->connect(this, SIGNAL(accepted()), this, SLOT(emitMessage())); - this->connect(ui->LockRatio, SIGNAL(stateChanged(int)), this, SLOT(lockRatioStateChanged(int))); - this->connect(ui->HeightInPercentage, SIGNAL(valueChanged(double)), this, SLOT(Percentage2Pixel(double))); - this->connect(ui->WidthInPercentage, SIGNAL(valueChanged(double)), this, SLOT(Percentage2Pixel(double))); - this->connect(ui->xInPercentage, SIGNAL(valueChanged(double)), this, SLOT(Percentage2Pixel(double))); - this->connect(ui->yInPercentage, SIGNAL(valueChanged(double)), this, SLOT(Percentage2Pixel(double))); - this->connect(ui->HeightInPixel, SIGNAL(valueChanged(double)), this, SLOT(Pixel2Percentage(double))); - this->connect(ui->WidthInPixel, SIGNAL(valueChanged(double)), this, SLOT(Pixel2Percentage(double))); - this->connect(ui->xInPixel, SIGNAL(valueChanged(double)), this, SLOT(Pixel2Percentage(double))); - this->connect(ui->yInPixel, SIGNAL(valueChanged(double)), this, SLOT(Pixel2Percentage(double))); - this->connect(ui->WidthInPixel, - SIGNAL(valueChanged(double)), - this, SLOT(Width2HeightTrans(double))); - this->connect(ui->HeightInPixel, - SIGNAL(valueChanged(double)), - this, SLOT(Height2WidthTrans(double))); + if(m_instance != NULL) + { + return m_instance; + } + + m_instance = new ImagePropertiesDialog(); + return m_instance; } -/** - * @Author Pan - * @brief 槽函数,用语接收DocImageBlock的信号后更新自身的信息 - * @param 若干参数 - * @return void - * @date 2017/06/25 - */ -void ImagePropertiesDialog::receiveImageInfo(double image_width, - double image_height, - double image_x, - double image_y, - double page_width, - double page_height, - bool ratio_is_locked) { - ui->LockRatio->setChecked(ratio_is_locked); - ui->InitialSize->setText(tr("Width: ") + QString::number(image_width) + tr(", Height: ") + QString::number(image_height)); - initial_width = image_width; - initial_height = image_height; - ratio_locked = ratio_is_locked; - this->page_width = page_width; - this->page_height = page_height; -// ui->WidthInPercentage->setValue(100.0); -// ui->HeightInPercentage->setValue(100.0); -// ui->xInPercentage->setValue(image_x / page_width * 100.0); -// ui->yInPercentage->setValue(image_y / page_height * 100.0); +void ImagePropertiesDialog::DestoryInstance() +{ + m_instance = NULL; +} + +void ImagePropertiesDialog::init(DocImageBlock *_block) +{ + this->block = _block; // 记录下block + // 先更新数据,后建立连接 - ui->WidthInPixel->setValue(image_width); - ui->HeightInPixel->setValue(image_height); - ui->xInPixel->setValue(image_x); - ui->yInPixel->setValue(image_y); + // 保存图片原始尺寸 + this->initial_width = this->block->getRealWidth(); + this->initial_height = this->block->getRealHeight(); - ui->WidthInPercentage->setValue(ui->WidthInPixel->value() / image_width * 100.0); - ui->HeightInPercentage->setValue(ui->HeightInPixel->value() / image_height * 100.0); - ui->xInPercentage->setValue(ui->xInPixel->value() / page_width * 100.0); - ui->yInPercentage->setValue(ui->yInPixel->value() / page_width * 100.0); + // 页大小 + this->page_width = this->block->getPage()->getWidth(); + this->page_height = this->block->getPage()->getHeight(); -} + // 图片大小 + this->image_width = UnitTool::pixelToMM(this->block->width()); + this->image_height = UnitTool::pixelToMM(this->block->height()); + + // 图片位置+++ + this->pos_x = UnitTool::pixelToMM( this->block->x()); + this->pos_y = UnitTool::pixelToMM( this->block->y()); + + // 修改界面显示内容 + // 图片实际尺寸 + ui->InitialSize->setText( + tr("Width: ") + + QString::number(this->image_width) + + tr(" mm") + + tr(", Height: ") + + QString::number(this->image_height) + + tr(" mm")); + + // 图片采用毫米为单位 + ui->WidthInMM->setValue(this->image_width); + ui->HeightInMM->setValue(this->image_height); + + ui->xInMM->setValue( + UnitTool::pixelToMM( + this->block->x())); + ui->yInMM->setValue( + UnitTool::pixelToMM( + this->block->y())); + // 求比例 + ui->WidthInPercentage->setValue( + this->image_width / this->initial_width * 100.0); + ui->HeightInPercentage->setValue( + this->image_height / this->initial_height * 100.0); + ui->xInPercentage->setValue( + ui->xInMM->value() / this->page_width * 100.0); + ui->yInPercentage->setValue( + ui->yInMM->value() / this->page_height * 100.0); + + // 是否锁定纵横比 + ratio_locked = this->block->isWidthHeightRatioLocked(); + + // 设置界面显示 + ui->LockRatio->setChecked( + this->block->isWidthHeightRatioLocked()); // 是否锁定纵横比 + + // 建立连接 + this->connect( + this, + SIGNAL( + changeImageProperties( + double,double,double,double,bool)), + this->block, + SLOT( + imagePropertiesChanged( + double,double,double,double,bool))); + +} ImagePropertiesDialog::~ImagePropertiesDialog() { delete ui; } -/** - * @Author Pan - * @brief 发送信号 - * @param void - * @return void - * @date 2017/06/25 - */ -void ImagePropertiesDialog::emitMessage() + +ImagePropertiesDialog::ImagePropertiesDialog(QWidget *parent) + :QDialog(parent), ui(new Ui::ImagePropertiesDialog) +{ + ui->setupUi(this); + this->initConnect(); +} + +void ImagePropertiesDialog::initConnect() +{ + + // 关闭窗口后触发 + this->connect(this, SIGNAL(finished(int)), + this, SLOT(finished_slots(int))); + + // 锁定纵横比 + this->connect(ui->LockRatio, SIGNAL(stateChanged(int)), + this, SLOT(lockRatioStateChanged(int))); + + // x mm + this->connect(ui->xInMM, SIGNAL(editingFinished()), + this, SLOT(editfinished_MM_x())); + + // x percentage + this->connect(ui->xInPercentage, SIGNAL(editingFinished()), + this, SLOT(editfinished_percentage_x())); + + // y mm + this->connect(ui->yInMM, SIGNAL(editingFinished()), + this, SLOT(editfinished_MM_y())); + + // y percentage + this->connect(ui->yInPercentage, SIGNAL(editingFinished()), + this, SLOT(editfinished_percentage_y())); + + // 处理x改变 + this->connect(this, SIGNAL(valueChanged_x(double)), + this, SLOT(slots_valueChanged_x(double))); + + // 处理y改变 + this->connect(this, SIGNAL(valueChanged_y(double)), + this, SLOT(slots_valueChanged_y(double))); + + // width mm + this->connect(ui->WidthInMM, SIGNAL(editingFinished()), + this, SLOT(editfinished_MM_width())); + + // width percentage + this->connect(ui->WidthInPercentage, SIGNAL(editingFinished()), + this, SLOT(editfinished_percentage_width())); + + // height mm + this->connect(ui->HeightInMM, SIGNAL(editingFinished()), + this, SLOT(editfinished_MM_height())); + + // height percentage + this->connect(ui->HeightInPercentage, SIGNAL(editingFinished()), + this,SLOT(editfinished_percentage_height())); + + // 处理width改变 + this->connect(this, SIGNAL(valueChanged_width(double)), + this, SLOT(slots_valueChanged_width(double))); + + // 处理height改变 + this->connect(this, SIGNAL(valueChanged_height(double)), + this, SLOT(slots_valueChanged_height(double))); + +} + +/// +/// \brief ImagePropertiesDialog::finished_slots +/// \param value +/// +void ImagePropertiesDialog::finished_slots(int value) { - emit changeImageProperties(ui->WidthInPixel->value(), - ui->HeightInPixel->value(), - ui->xInPixel->value(), - ui->yInPixel->value(), - ui->LockRatio->isChecked()); + if(value == QDialog::Accepted) + { + // 点击确认 + emit changeImageProperties( + UnitTool::mmToPixel(ui->WidthInMM->value()), + UnitTool::mmToPixel(ui->HeightInMM->value()), + UnitTool::mmToPixel(ui->xInMM->value()), + UnitTool::mmToPixel(ui->yInMM->value()), + UnitTool::mmToPixel(ui->LockRatio->isChecked())); + } + + this->disconnect( this, SIGNAL(changeImageProperties(double,double,double,double,bool)), + this->block, SLOT(imagePropertiesChanged(double,double,double,double,bool))); + } /** @@ -119,91 +206,141 @@ void ImagePropertiesDialog::emitMessage() */ void ImagePropertiesDialog::lockRatioStateChanged(int locked) { - qDebug() << "Waaaa"; - if (locked == Qt::Checked && !ratio_locked) - { - qDebug() << "Set to Checked."; - ratio_locked = true; + this->ratio_locked = locked; - } - else if (locked == Qt::Unchecked && ratio_locked) - { - qDebug() << "Set to Unchecked."; - ratio_locked = false; - this->disconnect(ui->WidthInPercentage, - SIGNAL(valueChanged(double)), - this, SLOT(Width2HeightTrans(double))); - this->disconnect(ui->HeightInPercentage, - SIGNAL(valueChanged(double)), - this, SLOT(Height2WidthTrans(double))); - } } -/** - * @Author Pan - * @brief 锁定纵横比时,宽度到高度的按比例同步 - * @param double value - * @return void - * @date 2017/06/25 - */ -void ImagePropertiesDialog::Width2HeightTrans(double value) +/// +/// \brief ImagePropertiesDialog::editfinished_MM_x +/// 修改了 x mm +void ImagePropertiesDialog::editfinished_MM_x() { - //qDebug() << "W2H"; - if (ratio_locked) - { - double ratio = initial_height / initial_width; - ui->HeightInPixel->setValue(value * ratio); - } + this->pos_x = ui->xInMM->value(); + emit this->valueChanged_x(this->pos_x); + } -/** - * @Author Pan - * @brief 锁定纵横比时,高度到宽度的按比例同步 - * @param double value - * @return void - * @date 2017/06/25 - */ -void ImagePropertiesDialog::Height2WidthTrans(double value) +/// +/// \brief ImagePropertiesDialog::editfinished_MM_y +/// 修改了 y mm +/// +void ImagePropertiesDialog::editfinished_MM_y() { - if (ratio_locked) - { - double ratio = initial_width / initial_height; - ui->WidthInPixel->setValue(value * ratio); - } + this->pos_y = ui->yInMM->value(); + emit this->valueChanged_y(this->pos_y); } -/** - * @Author Pan - * @brief 从像素量到比例量的同步 - * @param double value - * @return void - * @date 2017/06/25 - */ -void ImagePropertiesDialog::Pixel2Percentage(double value) +/// +/// \brief ImagePropertiesDialog::editfinished_percentage_x +/// 修改了 x percentage +/// +void ImagePropertiesDialog::editfinished_percentage_x() { -// static int cnt = 1; -// qDebug() << cnt++; -// qDebug() << ui->HeightInPixel->value(); - ui->HeightInPercentage->setValue(100.0 * ui->HeightInPixel->value() / initial_height); - ui->WidthInPercentage->setValue(100.0 * ui->WidthInPixel->value() / initial_width); - ui->xInPercentage->setValue(100.0 * ui->xInPixel->value() / page_width); - ui->yInPercentage->setValue(100.0 * ui->yInPixel->value() / page_height); + this->pos_x = ui->xInPercentage->value() * this->page_width / 100.0; + emit this->valueChanged_x(this->pos_x); } -/** - * @Author Pan - * @brief 从比例量到像素量的同步 - * @param double value - * @return void - * @date 2017/06/25 - */ -void ImagePropertiesDialog::Percentage2Pixel(double value) +/// +/// \brief ImagePropertiesDialog::editfinished_percentage_y +/// 修改了 y percentages +/// +void ImagePropertiesDialog::editfinished_percentage_y() { - ui->HeightInPixel->setValue(ui->HeightInPercentage->value() * initial_height / 100.0); - ui->WidthInPixel->setValue(ui->WidthInPercentage->value() * initial_width / 100.0); - ui->xInPixel->setValue(ui->xInPercentage->value() * page_width / 100.0); - ui->yInPixel->setValue(ui->yInPercentage->value() * page_height / 100.0); + this->pos_y = ui->yInPercentage->value() * this->page_height / 100.0; + emit this->valueChanged_y(this->pos_y); } +void ImagePropertiesDialog::editfinished_MM_width() +{ + this->image_width = ui->WidthInMM->value(); + emit this->valueChanged_width(this->image_width); +} + +void ImagePropertiesDialog::editfinished_MM_height() +{ + this->image_height = ui->HeightInMM->value(); + emit this->valueChanged_height(this->image_height); +} + +void ImagePropertiesDialog::editfinished_percentage_width() +{ + this->image_width = ui->WidthInPercentage->value() * this->initial_width / 100.0; + emit this->valueChanged_width(this->image_width); +} + +void ImagePropertiesDialog::editfinished_percentage_height() +{ + this->image_height = ui->HeightInPercentage->value() / 100.0 * this->initial_height; + emit this->valueChanged_height(this->image_height); +} + +/// +/// \brief ImagePropertiesDialog::slots_valueChanged_x +/// 当x发生改变时进行处理 +/// \param x +/// +void ImagePropertiesDialog::slots_valueChanged_x(double x) +{ + ui->xInMM->setValue(x); + ui->xInPercentage->setValue( + 100.0 * x / this->page_width); +} + +/// +/// \brief ImagePropertiesDialog::slots_valueChanged_y +/// 当y发生改变时触发 +/// \param y +/// +void ImagePropertiesDialog::slots_valueChanged_y(double y) +{ + ui->yInMM->setValue(y); + ui->yInPercentage->setValue( + 100.0 * y / this->page_height); +} + +/// +/// \brief ImagePropertiesDialog::slots_valueChanged_width +/// 处理当宽度发生改变时 +/// \param width +/// +void ImagePropertiesDialog::slots_valueChanged_width(double width) +{ + ui->WidthInMM->setValue(width); + ui->WidthInPercentage->setValue( + 100.0 * width / this->initial_width); + + // 如果锁定纵横比 + if(this->ratio_locked) + { + double ratio = initial_height / initial_width; + this->image_height = width * ratio; + ui->HeightInMM->setValue(this->image_height); + ui->HeightInPercentage->setValue( + 100.0 * this->image_height / this->initial_height); + } +} + +/// +/// \brief ImagePropertiesDialog::slots_valueChanged_height +/// 处理当高度发生改变时 +/// \param height +/// +void ImagePropertiesDialog::slots_valueChanged_height(double height) +{ + ui->HeightInMM->setValue(height); + ui->HeightInPercentage->setValue( + 100.0 * height / this->initial_height); + + // 如果锁定纵横比 + if(this->ratio_locked) + { + double ratio = this->initial_width / this-> initial_height; + this->image_width = height * ratio; + + ui->WidthInMM->setValue(this->image_width); + ui->WidthInPercentage->setValue( + 100.0 * this->image_width / this->initial_width); + } +} diff --git a/ofdEditor/model/Widget/imagepropertiesdialog.h b/ofdEditor/model/Widget/imagepropertiesdialog.h index 6faf7f5fe1558489e30fb976a162f25cfc64635f..f94a51f264bf6d4edadfa04f37e1e415f7e15aa0 100644 --- a/ofdEditor/model/Widget/imagepropertiesdialog.h +++ b/ofdEditor/model/Widget/imagepropertiesdialog.h @@ -2,7 +2,7 @@ #define IMAGEPROPERTIESDIALOG_H #include -#include "../Doc/DocImageBlock.h" + class DocImageBlock; namespace Ui { @@ -14,38 +14,64 @@ class ImagePropertiesDialog : public QDialog Q_OBJECT public: - explicit ImagePropertiesDialog(DocImageBlock * _block, QWidget *parent = 0); + static ImagePropertiesDialog* getInstance(); // 获得单例 + static void DestoryInstance(); // 销毁单例 + void init(DocImageBlock* _block); // 使用时初始化 + ~ImagePropertiesDialog(); private: + ImagePropertiesDialog(QWidget *parent = 0); Ui::ImagePropertiesDialog *ui; DocImageBlock * block; + static ImagePropertiesDialog* m_instance; + + // 使用毫米为单位 double initial_width; double initial_height; + double pos_x; + double pos_y; bool ratio_locked; double page_width; double page_height; + double image_width; + double image_height; + + void initConnect(); + private slots: - void emitMessage(); - void lockRatioStateChanged(int locked); - void Width2HeightTrans(double value); - void Height2WidthTrans(double value); - void Pixel2Percentage(double value); - void Percentage2Pixel(double value); -public slots: - void receiveImageInfo(double image_width, - double image_height, - double image_x, - double image_y, - double page_width, - double page_height, - bool ratio_is_locked); + void finished_slots(int value); // 完成窗口后执行 + void lockRatioStateChanged(int locked); // 当纵横比锁定发生改变时 + + void editfinished_MM_x(); + void editfinished_MM_y(); + void editfinished_percentage_x(); + void editfinished_percentage_y(); + + + void editfinished_MM_width(); + void editfinished_MM_height(); + void editfinished_percentage_width(); + void editfinished_percentage_height(); + + void slots_valueChanged_x(double x); // 当x发生改变时处理 + void slots_valueChanged_y(double y); // 当y发生改变时处理 + + void slots_valueChanged_width(double width); // 当width发生改变时触发 + void slots_valueChanged_height(double height); // 当height发生改变时触发 + signals: void changeImageProperties(double new_width, double new_height, double new_x, double new_y, bool ratio_locked); + + void valueChanged_x(double x); // 图片位置被修改 + void valueChanged_y(double y); // 图片位置被修改 + + void valueChanged_width(double width); // 图片大小被修改 + void valueChanged_height(double height);// 图片大小被修改 }; #endif // IMAGEPROPERTIESDIALOG_H diff --git a/ofdEditor/model/Widget/imagepropertiesdialog.ui b/ofdEditor/model/Widget/imagepropertiesdialog.ui index e9fa6f1c0a7fc8e734cd15fe7f9cbe2cff9640c4..1c13d50952bdb8f579a273fcba3645ad835aa64e 100644 --- a/ofdEditor/model/Widget/imagepropertiesdialog.ui +++ b/ofdEditor/model/Widget/imagepropertiesdialog.ui @@ -6,488 +6,337 @@ 0 0 - 436 - 389 + 508 + 407 - Dialog + 图片设置窗口 - - - - 70 - 340 - 341 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 30 - 40 - 54 - 12 - - - - - - - - - - 30 - 20 - 71 - 21 - - - - - 宋体 - 12 - - - - 图片尺寸 - - - - - - 130 - 60 - 71 - 22 - - - - - - - 280 - 60 - 62 - 22 - - - - - - - 100 - 22 - 311 - 16 - - - - Qt::Horizontal - - - - - - 40 - 60 - 41 - 20 - - - - - 宋体 - 12 - - - - 高度 - - - - - - 40 - 100 - 41 - 20 - - - - - 宋体 - 12 - - - - 宽度 - - - - - - 130 - 100 - 71 - 22 - - - - - - - 280 - 100 - 62 - 22 - - - - - - - 210 - 60 - 31 - 20 - - - - - 宋体 - 11 - false - - - - 像素 - - - - - - 210 - 100 - 31 - 20 - - - - - 宋体 - 11 - false - - - - 像素 - - - - - - 350 - 60 - 71 - 20 - - - - - 宋体 - 11 - false - - - - %原尺寸 - - - - - - 350 - 100 - 71 - 16 - - - - - 宋体 - 11 - false - - - - %原尺寸 - - - - - - 290 - 140 - 110 - 20 - - - - - 宋体 - 12 - - - - 锁定纵横比 - - - - - - 40 - 140 - 81 - 20 - - - - - 宋体 - 11 - - - - 原始尺寸: - - - - - - 130 - 140 - 101 - 16 - - - - - Agency FB - 11 - - - - QFrame::WinPanel - - - QFrame::Sunken - - - 122 ,122 - - - Qt::AlignCenter - - - - - - 30 - 180 - 71 - 21 - - - - - 宋体 - 12 - - - - 图片位置 - - - - - - 100 - 183 - 311 - 16 - - - - Qt::Horizontal - - - - - - 40 - 220 - 41 - 20 - - - - - 宋体 - 12 - - - - 水平 - - - - - - 40 - 260 - 41 - 20 - - - - - 宋体 - 12 - - - - 垂直 - - - - - - 130 - 220 - 71 - 22 - - - - - - - 210 - 220 - 31 - 20 - - - - - 宋体 - 11 - false - - - - 像素 - - - - - - 280 - 260 - 62 - 22 - - - - - - - 130 - 260 - 71 - 22 - - - - - - - 210 - 260 - 31 - 20 - - - - - 宋体 - 11 - false - - - - 像素 - - - - - - 350 - 220 - 71 - 20 - - - - - 宋体 - 11 - false - - - - %页面 - - - - - - 350 - 260 - 71 - 16 - - - - - 宋体 - 11 - false - - - - %页面 - - - - - - 280 - 220 - 62 - 22 - - - + + + + + 图片位置 + + + + + + + 宋体 + 11 + false + + + + mm + + + + + + + + 宋体 + 12 + + + + 水平 + + + + + + + + 宋体 + 11 + false + + + + %页面 + + + + + + + + 宋体 + 11 + false + + + + mm + + + + + + + + 宋体 + 12 + + + + 垂直 + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + false + + + + %页面 + + + + + + + 10000.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 图片尺寸 + + + + + + + 宋体 + 12 + + + + 宽度 + + + + + + + + Agency FB + 11 + + + + QFrame::WinPanel + + + QFrame::Sunken + + + 200 ,200 + + + Qt::AlignCenter + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + + + + 原始尺寸: + + + + + + + + 宋体 + 11 + false + + + + %原尺寸 + + + + + + + + 宋体 + 11 + false + + + + mm + + + + + + + + 宋体 + 12 + + + + 高度 + + + + + + + 10000.000000000000000 + + + + + + + + 宋体 + 11 + false + + + + mm + + + + + + + + 宋体 + 11 + false + + + + %原尺寸 + + + + + + + + 宋体 + 12 + + + + 锁定纵横比 + + + + + + + 10000.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/ofdEditor/model/cn_model.ts b/ofdEditor/model/cn_model.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f8c1e75accd79a750b220f9cdfa6aa6552b37a3 --- /dev/null +++ b/ofdEditor/model/cn_model.ts @@ -0,0 +1,1280 @@ + + + + + BlockSizeAndPosSettingDialog + + + 调整块的大小尺寸 + + + + + DocBlock + + + Foreground + 前景层 + + + + Body + 正文层 + + + + Background + 背景层 + + + + Delete + 移除 + + + + size and position + 大小与位置 + + + + Layer + + + + + DocImageBlock + + + Change Image + 修改图片 + + + Set Image Properties + 设置图片属性 + + + Remove Image. + 移除图片。 + + + + + DocImageBlock + 图片块 + + + + Property + 属性 + + + + Open File + 打开文件 + + + + OFD Editor + OFD Editor + + + + Cannot open file %1. + 无法打开文件 %1. + + + + DocInfoDialog + + Dialog + 文档属性 + + + + 文档信息 + 文档信息 + + + + 说明 + + + + + 文件: + + + + + 文档ID: + + + + + 更改 + + + + + 标题: + + + + + 作者: + + + + + 主题: + + + + + 摘要: + + + + + 关键字: + + + + + 文档类型: + + + + + 文档封面: + + + + + 创建日期: + + + + + 高级 + + + + + 最近修改时间: + + + + + 创建应用程序: + + + + + 应用程序版本: + + + + + DocPage + + + Main + 主菜单 + + + + Insert + 插入 + + + + TextBlock + 文本块 + + + + ImageBlock + 图片块 + + + + Table + 表格 + + + + Page + + + + + Setting + 设置 + + + + Before + 在当前页之前 + + + + After + 在当前页之后 + + + + Delete This Page + 删除页面 + + + + Page Setting + 页面设置 + + + + Open File + 打开文件 + + + + OFD Editor + + + + + Cannot open file %1. + + + + + DocTable + + + + DocTable + 表格 + + + + insert Col After + 在之后插入列 + + + + insert Col Before + 在之前插入列 + + + + insert row after + 在之后插入行 + + + + insert row before + 在之前插入行 + + + + Merge Cells + 合并单元格 + + + + Split Cells + 拆分单元格 + + + + delete column + 移除当前列 + + + + delete row + 移除当前行 + + + + table setting + 表格设置 + + + + Insert Row or Col + 插入行或列 + + + + DocTextBlock + + + Choose a Color + 选择颜色 + + + Set the font + 设置字体 + + + + + DocTextBlock + 文本块 + + + + Cut + 剪切 + + + + Copy + 复制 + + + + Paste + 粘贴 + + + + Select All + 全选 + + + + Bold + 加粗 + + + + Italic + 斜体 + + + + Underline + 下划线 + + + + Color + 颜色 + + + Font + 字体 + + + + Paragraph + 段落 + + + Remove + 移除 + + + + FontDialogTest + 字体 + + + + FindAndReplaceDock + + + Find/Replace + 查找或替换 + + + + Find: + 查找: + + + + Replace With: + 替换: + + + + Find Previous + 往前查找 + + + + Find Next + 往后查找 + + + + Replace + 替换 + + + + Replace All + 替换全部 + + + + Found in: + 找到: + + + + places. + 处。 + + + + FontSettingDialog + + Dialog + 字体设置窗口 + + + + 字体设置窗口 + 字体 + + + + + 字体 + + + + + 粗体 + + + + + 字号 + + + + + 下划线 + + + + + 字体效果预览 + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">文字测试样例</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Text Demo</p></body></html> + + + + + 斜体 + + + + + 初号 + + + + + 小初 + + + + + 一号 + + + + + 小一 + + + + + 二号 + + + + + 小二 + + + + + 三号 + + + + + 小三 + + + + + 四号 + + + + + 小四 + + + + + 五号 + + + + + 小五 + + + + + 六号 + + + + + 小六 + + + + + 七号 + + + + + 八号 + + + + + 5 + + + + + 5.5 + + + + + 6.5 + + + + + 7.5 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 10.5 + + + + + 11 + + + + + 12 + + + + + 14 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + 24 + + + + + 26 + + + + + 28 + + + + + 36 + + + + + 48 + + + + + 72 + + + + + 高级 + + + + + 字间距 + + + + + 拉伸字体 + + + + + 字体粗细 + + + + + 等宽字体 + + + + + GlobalSetting + + + Test + 默认字体 + + + + ImagePropertiesDialog + + Dialog + 图片属性设置 + + + + 图片设置窗口 + 图片设置 + + + + + + + mm + mm + + + + 图片尺寸 + + + + + 200 ,200 + + + + + 高度 + + + + + 宽度 + + + + + + %原尺寸 + + + + + 锁定纵横比 + + + + + 原始尺寸: + + + + + 图片位置 + + + + + 水平 + + + + + 垂直 + + + + + + %页面 + + + + + Width: + + + + + + mm + mm + + + + , Height: + + + + + InsertPageDialog + + + 插入页 + + + + + InsertTableDialog + + + 插入表格 + + + + + 表格 + + + + + 行数列数 + + + + + 行数: + + + + + 列数: + + + + + 总体尺寸 + + + + + 宽: + + + + + + mm + + + + + 高: + + + + + PageDialog + + Dialog + 页面设置 + + + + 当前页面 + + + + + + + + + + + + + + + + mm + + + + + 所有页 + + + + + + + + 宽 + + + + + + + + 高 + + + + + + 垂直 + + + + + + 工作区域尺寸 + + + + + 特定页数 + + + + + 应用于 + + + + + + 设置工作区域 + + + + + + 水平 + + + + + + 页面尺寸 + + + + + + 工作区域位置 + + + + + + 页面设置 + + + + + 当前页 + + + + + 页面范围 + + + + + 从 + + + + + 到 + + + + + 页 + + + + + 页码 + + + + + + 选择尺寸 + + + + + + + + A4 + + + + + + + + A3 + + + + + + + + A5 + + + + + + + + Letter + + + + + + + + 16K + + + + + + + + 32K + + + + + + + Customized + + + + + 默认页面 + + + + + ParagraphFormatDialog + + Dialog + 段落属性设置 + + + + 段落 + + + + + 对齐方式 + + + + + 水平 + + + + + 左对齐 + + + + + 右对齐 + + + + + 居中 + + + + + 两端对齐 + + + + + 缩进 + + + + + 整体缩进 + + + + + 首行缩进 + + + + + 间距 + + + + + 段前 + + + + + 段后 + + + + + 行距策略 + + + + + 单倍行距 + + + + + 多倍行距 + + + + + 固定值 + + + + + 最小值 + + + + + 值 + + + + + SelectTemplateDialog + + + 选择模版 + + + + + 选择页面模板 + + + + + 上一个 + + + + + 下一个 + + + + + TableSettingDialog + + + 表格设置 + + + + + <html><head/><body><p>大小位置</p></body></html> + + + + + 大小位置 + + + + + 表格线条颜色 + + + + + 颜色 + + + + + 总体大小 + + + + + 表格宽度: + + + + + + + + mm + + + + + 位置 + + + + + 距左方 + + + + + 距上方 + + + + + + 单元格留白 + + + + + 列宽 + + + + + 列宽模式 + + + + + 均等分列宽 + + + + + 自定义列宽 + + + + + New Row + + + + + New Column + + + + + Choose table border color + 选择表格线条颜色 + + + diff --git a/ofdEditor/model/model.pro b/ofdEditor/model/model.pro index 5cdc451e13f97164aaa66410d61d88d5a5e46249..19953dafba85053ea8998c1bc639d800928ce253 100644 --- a/ofdEditor/model/model.pro +++ b/ofdEditor/model/model.pro @@ -29,21 +29,15 @@ SOURCES += model.cpp \ Doc/DocGraph.cpp \ Doc/DocLayer.cpp \ Doc/DocPage.cpp \ - Doc/DocParagraph.cpp \ Doc/DocPassage.cpp \ Doc/DocPicture.cpp \ Doc/DocTable.cpp \ Doc/DocTableCell.cpp \ - Doc/DocTableRow.cpp \ - Doc/DocTemplate.cpp \ Doc/DocText.cpp \ Doc/DocTextBlock.cpp \ - Doc/DocDrawParam.cpp \ - Doc/DocParaStyle.cpp \ Doc/DocTextStyle.cpp \ Tool/UnitTool.cpp \ Doc/DocPageScene.cpp \ - Widget/ParagraphFormatWidget.cpp \ Widget/ParagraphFormatDialog.cpp \ Widget/FontSettingDialog.cpp \ Convert/OFD_DocConvertor.cpp \ @@ -53,7 +47,17 @@ SOURCES += model.cpp \ Widget/DocInfoDialog.cpp \ Command/SetTextBlodCmd.cpp \ Doc/DocImageBlock.cpp \ - Widget/imagepropertiesdialog.cpp + Widget/imagepropertiesdialog.cpp \ + Widget/PageDialog.cpp \ + Widget/InsertTableDialog.cpp \ + Widget/FindAndReplaceDock.cpp \ + Widget/SelectTemplateDialog.cpp \ + Core/GlobalSetting.cpp \ + Widget/InsertPageDialog.cpp \ + Widget/TableSettingDialog.cpp \ + Widget/BlockSizeAndPosSettingDialog.cpp \ + Convert/BuildTextBlock.cpp \ + Convert/BuildTextTable.cpp HEADERS += model.h\ model_global.h \ @@ -61,40 +65,47 @@ HEADERS += model.h\ Doc/DocGraph.h \ Doc/DocLayer.h \ Doc/DocPage.h \ - Doc/DocParagraph.h \ Doc/DocPassage.h \ Doc/DocPicture.h \ Doc/DocTable.h \ Doc/DocTableCell.h \ - Doc/DocTableRow.h \ - Doc/DocTemplate.h \ Doc/DocText.h \ Doc/DocTextBlock.h \ - Doc/DocDrawParam.h \ Doc/DocBasicTypes.h \ - Doc/DocParaStyle.h \ Doc/DocTextStyle.h \ Tool/UnitTool.h \ Doc/DocPageScene.h \ - Widget/ParagraphFormatWidget.h \ Widget/ParagraphFormatDialog.h \ Widget/FontSettingDialog.h \ Convert/OFD_DocConvertor.h \ Convert/MergeCT_Texts.h \ Convert/Doc_OFDConvertor.h \ Convert/Objects/MinTextUnit.h \ - Widget/DocInfoDialog.h \ Command/SetTextBlodCmd.h \ Doc/DocImageBlock.h \ - Widget/imagepropertiesdialog.h + Widget/imagepropertiesdialog.h \ + Widget/PageDialog.h \ + Widget/FindAndReplaceDock.h \ + Widget/InsertTableDialog.h \ + Widget/SelectTemplateDialog.h \ + Core/GlobalSetting.h \ + Widget/DocInfoDialog.h \ + Widget/InsertPageDialog.h \ + Widget/TableSettingDialog.h \ + Widget/BlockSizeAndPosSettingDialog.h \ + Convert/BuildTextBlock.h \ + Convert/BuildTextTable.h DESTDIR = ../bin # 生成文件在这 MOC_DIR = ./moc # Q_OBJECT 类转换后的文件 RCC_DIR = ./rcc # .qrc 文件转换后存放路径 OBJECTS_DIR += ./tmp # .obj 文件存放路径 +TRANSLATIONS = cn_model.ts + INCLUDEPATH += $$PWD/../ofd \ - $$PWD/../model + $$PWD/../model \ + $$PWD/../libs/jsoncpp unix { target.path = /usr/lib @@ -111,8 +122,17 @@ win32{ } FORMS += \ - Widget/ParagraphFormatWidget.ui \ Widget/ParagraphFormatDialog.ui \ Widget/FontSettingDialog.ui \ Widget/DocInfoDialog.ui \ - Widget/imagepropertiesdialog.ui + Widget/imagepropertiesdialog.ui \ + Widget/PageDialog.ui \ + Widget/InsertTableDialog.ui \ + Widget/FindAndReplaceDock.ui \ + Widget/SelectTemplateDialog.ui \ + Widget/InsertPageDialog.ui \ + Widget/TableSettingDialog.ui \ + Widget/BlockSizeAndPosSettingDialog.ui + +RESOURCES += \ + resource.qrc diff --git a/ofdEditor/model/resource.qrc b/ofdEditor/model/resource.qrc new file mode 100644 index 0000000000000000000000000000000000000000..17998475f445d2457156b94addc8847b9e0040c7 --- /dev/null +++ b/ofdEditor/model/resource.qrc @@ -0,0 +1,9 @@ + + + template_icons/template_1.png + template_icons/template_2 .png + template_icons/template_3.png + template_icons/template_4.png + template_icons/template_5.png + + diff --git a/ofdEditor/model/template_icons/red_line.png b/ofdEditor/model/template_icons/red_line.png new file mode 100644 index 0000000000000000000000000000000000000000..1a49a19e0f2a8878e79d0c06a3dd5708db71f90d Binary files /dev/null and b/ofdEditor/model/template_icons/red_line.png differ diff --git a/ofdEditor/model/template_icons/template_1.png b/ofdEditor/model/template_icons/template_1.png new file mode 100644 index 0000000000000000000000000000000000000000..318faec03a383616fdf188e0588e3a688f8f802c Binary files /dev/null and b/ofdEditor/model/template_icons/template_1.png differ diff --git a/ofdEditor/model/template_icons/template_2 .png b/ofdEditor/model/template_icons/template_2 .png new file mode 100644 index 0000000000000000000000000000000000000000..e6db0a3c8ea32d8d88aecbbbca5c6f186734227f Binary files /dev/null and b/ofdEditor/model/template_icons/template_2 .png differ diff --git a/ofdEditor/model/template_icons/template_3.png b/ofdEditor/model/template_icons/template_3.png new file mode 100644 index 0000000000000000000000000000000000000000..7ac12154b89ab2ed380fc29ce0904dfc62273d62 Binary files /dev/null and b/ofdEditor/model/template_icons/template_3.png differ diff --git a/ofdEditor/model/template_icons/template_4.png b/ofdEditor/model/template_icons/template_4.png new file mode 100644 index 0000000000000000000000000000000000000000..2e0f7d343af8c5e7a2ba7adf07e60c41c93474f4 Binary files /dev/null and b/ofdEditor/model/template_icons/template_4.png differ diff --git a/ofdEditor/model/template_icons/template_5.png b/ofdEditor/model/template_icons/template_5.png new file mode 100644 index 0000000000000000000000000000000000000000..3bffeb770f9e7dad141ffae744d0924ab7738513 Binary files /dev/null and b/ofdEditor/model/template_icons/template_5.png differ diff --git a/ofdEditor/ofd/DataTypes/basic_datatype.h b/ofdEditor/ofd/DataTypes/basic_datatype.h index 785b3644d7db4a77a9d9214dc763ab0ece991099..7897961effaf9ad081e64b3cf37a454b0d027329 100644 --- a/ofdEditor/ofd/DataTypes/basic_datatype.h +++ b/ofdEditor/ofd/DataTypes/basic_datatype.h @@ -9,34 +9,41 @@ #include "../ofdexceptions.h" //6种基本数据类型 -class OFDSHARED_EXPORT ST_Loc { +class OFDSHARED_EXPORT ST_Loc +{ QString title; //该路径的标签,比如资源路径为"Res",页面路径为"Page"(与XML的标签等同) QString abs_path; //绝对路径 QString rela_path; public: ST_Loc(){} ST_Loc(QString tag, QString relative_path, QString current_path) : //构造方法,包括对路径的解析 - title(tag), rela_path(relative_path) { - // qDebug() << "cur = " << current_path << "rela = " << relative_path << endl; + title(tag), rela_path(relative_path) + { + // qDebug() << "cur = " << current_path << "rela = " << relative_path << endl; current_path.replace("\\", "/"); //路径分隔符标准化 - // qDebug() << "cur = " << current_path << endl; - if (relative_path.startsWith("../")) { //从父路径开始 + // qDebug() << "cur = " << current_path << endl; + if (relative_path.startsWith("../")) + { //从父路径开始 int i, cnt = 0; - for (i = current_path.length() - 1; i >= 0; i--) { + for (i = current_path.length() - 1; i >= 0; i--) + { if (current_path[i] == '/') - cnt++; - // qDebug() <<"Cnt = " << cnt << endl; + cnt++; + // qDebug() <<"Cnt = " << cnt << endl; if (cnt == 2) break; } current_path.chop(current_path.length() - i - 1); - // qDebug() <<"chop = " << current_path.length() - i << endl; + // qDebug() <<"chop = " << current_path.length() - i << endl; relative_path.remove(0, 3); - } else { //从当前路径开始 + } + else + { //从当前路径开始 int i, cnt = 0; - for (i = current_path.length() - 1; i >= 0; i--) { + for (i = current_path.length() - 1; i >= 0; i--) + { if (current_path[i] == '/') - cnt++; - // qDebug() <<"Cnt = " << cnt << endl; + cnt++; + // qDebug() <<"Cnt = " << cnt << endl; if (cnt == 1) break; } current_path.chop(current_path.length() - i - 1); //消去当前路径后面的无用内容 @@ -45,33 +52,46 @@ public: else if (relative_path.startsWith("/")) relative_path.remove(0, 1); } - // qDebug() << "cur = " << current_path << "rela = " << relative_path << endl; + // qDebug() << "cur = " << current_path << "rela = " << relative_path << endl; abs_path = current_path + relative_path; } //构造方法,包括对路径的解析 - ST_Loc(QString tag, QString _abs_path) : title(tag), abs_path(_abs_path) { //构造方法,在直接已有绝对路径时 - abs_path.replace("/", "\\"); + + ST_Loc(QString tag, QString _abs_path) + : title(tag), abs_path(_abs_path) + { //构造方法,在直接已有绝对路径时 + abs_path.replace("\\", "/"); } - operator QString() { //可以直接把ST_Loc作为一个路径字符串使用 + operator QString() + { //可以直接把ST_Loc作为一个路径字符串使用 return abs_path; } - QString getPath() { //返回绝对路径,以“\\”为分隔符 + + QString getPath() + { //返回绝对路径,以“\\”为分隔符 return abs_path; } - QString getRelativePath() { + + QString getRelativePath() + { return rela_path; } - QString getTitle() { //返回当该路径的标签 + QString getTitle() + { //返回当该路径的标签 return title; } - bool isNull() { - return abs_path.isNull(); + bool isNull() + { + return abs_path.length() == 0; } }; -class OFDSHARED_EXPORT ST_Array { //以QStringList的形式来实现(因为容器类型的多样性,不如返回QString,具体的类型留给调用者去处理) +class OFDSHARED_EXPORT ST_Array +{ + //以QStringList的形式来实现(因为容器类型的多样性,不如返回QString,具体的类型留给调用者去处理) +public: QString title; QStringList elements; QString all_content; @@ -106,48 +126,59 @@ public: //对QStringList的一些简单封装(在有需要时再拓展接口 }; -class OFDSHARED_EXPORT ST_ID { +class OFDSHARED_EXPORT ST_ID +{ long id; bool is_null; public: - ST_ID() { + + ST_ID() + { is_null = true; id = 0; } - ST_ID(int _id) { + ST_ID(int _id) + { id = _id; is_null = false; } operator long() { return id; } long getID() { return id; } - bool isNull() { + bool isNull() + { return is_null; } }; -class OFDSHARED_EXPORT ST_RefID { +class OFDSHARED_EXPORT ST_RefID +{ long ref_id; bool is_null; public: - ST_RefID() { + ST_RefID() + { is_null = true; ref_id = 0; } - ST_RefID(int _ref_id) { + ST_RefID(int _ref_id) + { ref_id = _ref_id; is_null = false; } operator long() { return ref_id; } long getRefID() { return ref_id; } - bool isNull() { + bool isNull() + { return is_null; } }; -class OFDSHARED_EXPORT ST_Pos { //坐标位置,简单封装即可 +class OFDSHARED_EXPORT ST_Pos +{ + //坐标位置,简单封装即可 double x, y; bool is_null; public: @@ -161,13 +192,15 @@ public: bool isNull() { return is_null; } }; -class OFDSHARED_EXPORT ST_Box { //坐标位置+边长,简单封装即可 +class OFDSHARED_EXPORT ST_Box +{ + //坐标位置+边长,简单封装即可 double start_x, start_y, delta_x, delta_y; bool is_null; public: ST_Box() { is_null = true; start_x = start_y = delta_x = delta_y = 0; } ST_Box(double _start_x, double _start_y, double _delta_x, double _delta_y) : - start_x(_start_x), start_y(_start_y), delta_x(_delta_x), delta_y(_delta_y), is_null(false) {} + start_x(_start_x), start_y(_start_y), delta_x(_delta_x), delta_y(_delta_y), is_null(false) {} double getX() { return start_x; } double getY() { return start_y; } double getDeltaX() { return delta_x; } @@ -181,7 +214,9 @@ public: class CT_Base; -class OFDSHARED_EXPORT ID_Table { //为方便ID的管理,为两者建一个基类 +class OFDSHARED_EXPORT ID_Table +{ + //为方便ID的管理,为两者建一个基类 private: QMap id_pool; //凡是出现过的ID,全都在其中记录 public: @@ -204,15 +239,18 @@ public: bool registerItem(int key, CT_Base * value); //重载 }; -class OFDSHARED_EXPORT CT_Base { //所有含有ID属性的元素的基类 +class OFDSHARED_EXPORT CT_Base +{ //所有含有ID属性的元素的基类 ST_ID id; public: - ST_ID getID() { + ST_ID getID() + { return id; } - void setID(ST_ID new_id, ID_Table * _id_table) { + void setID(ST_ID new_id, ID_Table * _id_table) + { if (_id_table->contains(new_id.getID())) throw InvalidIDException("试图注册重复的ID: " + QString::number(new_id)); id = new_id; diff --git a/ofdEditor/ofd/DataTypes/document/CT_CommonData.h b/ofdEditor/ofd/DataTypes/document/CT_CommonData.h index 799c40f6a64b0aef09d94e2bb86aca1a69be9c87..2eadbb26bf1f4f499bf984538ad759e3353ce59e 100644 --- a/ofdEditor/ofd/DataTypes/document/CT_CommonData.h +++ b/ofdEditor/ofd/DataTypes/document/CT_CommonData.h @@ -9,6 +9,7 @@ public: ST_ID max_unit_id; //当前文档中所有对象使用的最大标识 CT_PageArea *page_area; //指定多个页面区域的大小和位置 QVector *public_res; //公共资源序列,每个资源指向OFD包内部的一个XML文件 + QVector *document_res; //vector template_page; //模板页序列 ST_RefID default_cs; //缺省颜色空间 public: @@ -16,6 +17,7 @@ public: CT_CommonData() { public_res = new QVector(); + document_res = new QVector(); page_area = NULL; } diff --git a/ofdEditor/ofd/DataTypes/document/DocBody.h b/ofdEditor/ofd/DataTypes/document/DocBody.h index dcbbced3eecf1b42ac935226747298f13f9be1ed..975b0175ef641830a00cd623873cd67fe28d4e9b 100644 --- a/ofdEditor/ofd/DataTypes/document/DocBody.h +++ b/ofdEditor/ofd/DataTypes/document/DocBody.h @@ -40,7 +40,7 @@ public: } void setDocRoot(QString _doc_root_abs) { - ST_Loc p("DocRoot", _doc_root_abs); + ST_Loc p("DocRoot", _doc_root_abs,_doc_root_abs); doc_root = p; } diff --git a/ofdEditor/ofd/DataTypes/document/Document.h b/ofdEditor/ofd/DataTypes/document/Document.h index 0448abe1c0db6ad56399de50c1192c2c2b2ea540..d91c432ef39c309fef2561b625ff038cca38f3ed 100644 --- a/ofdEditor/ofd/DataTypes/document/Document.h +++ b/ofdEditor/ofd/DataTypes/document/Document.h @@ -10,13 +10,15 @@ class OFDSHARED_EXPORT Document { public: - CT_CommonData * common_data; //文档公共数据,定义了默认页面单位、页面区域定义、公共资源等数据 - CT_Outlines * outlines; //大纲树 - ST_Loc custom_tags; //指向自定义标引文件 - ST_Loc extensions; //指向拓展文件 - ST_Loc annotations; //指向注释文件 - ID_Table * id_table; //记录所有CT_Base的ID信息 + CT_CommonData * common_data; //文档公共数据,定义了默认页面单位、页面区域定义、公共资源等数据 + CT_Outlines * outlines; //大纲树 + ST_Loc custom_tags; //指向自定义标引文件 + ST_Loc extensions; //指向拓展文件 + ST_Loc annotations; //指向注释文件 + ID_Table * id_table; //记录所有CT_Base的ID信息 QVector * public_res; + QVector * document_res; + CT_Pages *pages; @@ -49,6 +51,8 @@ public: if (!_id_table) id_table = new ID_Table; else id_table = _id_table; + + document_res = new QVector(); } CT_CommonData * getCommonData() { diff --git a/ofdEditor/ofd/DataTypes/document/Res.h b/ofdEditor/ofd/DataTypes/document/Res.h index 59f99941c8460a400a66d1f9add2d4d07076a37b..12cce5917b7cca5090b69842c469bbbb299914b5 100644 --- a/ofdEditor/ofd/DataTypes/document/Res.h +++ b/ofdEditor/ofd/DataTypes/document/Res.h @@ -5,14 +5,17 @@ #include "../Color/CT_ColorSpace.h" #include "../image/CT_DrawParam.h" #include "../../ofd_global.h" // 生成库文件需要 +#include "DataTypes/image/CT_MultiMedia.h" -class OFDSHARED_EXPORT Res { +class OFDSHARED_EXPORT Res +{ //属性 ST_Loc base_loc; //定义此资源描述文件的通用数据存储路径 //成员 - QVector * fonts; - QVector * colorspaces; - QVector * draw_params; + QVector* fonts; + QVector* colorspaces; + QVector* draw_params; + QVector* multMedias; //Other resource collections to be implemented public: @@ -21,7 +24,8 @@ public: Res(QString _base_loc = "", QVector * _fonts = NULL, QVector * _colorspaces = NULL, - QVector * _draw_params = NULL) { + QVector * _draw_params = NULL) + { if (!_base_loc.isNull()) setBaseLoc(_base_loc); if (!_fonts) @@ -36,22 +40,34 @@ public: draw_params = new QVector(); else draw_params = _draw_params; + + multMedias = new QVector(); + } - ST_Loc getBaseLoc() { + ST_Loc getBaseLoc() + { return base_loc; } - void setBaseLoc(QString _base_loc_abs) { - ST_Loc p("Resource", _base_loc_abs); + void setBaseLoc(QString _base_loc_abs) + { + ST_Loc p("Resource", _base_loc_abs,_base_loc_abs); base_loc = p; } - QVector * getFonts() { + QVector * getFonts() + { return fonts; } - void setFonts(QVector * _fonts) { + QVector *getMultiMedia() + { + return this->multMedias; + } + + void setFonts(QVector * _fonts) + { if (!_fonts) throw InvalidValueException("Invalid value in Fonts in Res: null pointer"); for (int i = 0; i < fonts->size(); i++) @@ -60,11 +76,13 @@ public: fonts = _fonts; } - QVector * getColorSpaces() { + QVector * getColorSpaces() + { return colorspaces; } - void setColorSpaces(QVector * _colorspaces) { + void setColorSpaces(QVector * _colorspaces) + { if (!_colorspaces) throw InvalidValueException("Invalid value in ColorSpaces in Res: null pointer"); for (int i = 0; i < colorspaces->size(); i++) @@ -73,11 +91,13 @@ public: colorspaces = _colorspaces; } - QVector * getDrawParams() { + QVector * getDrawParams() + { return draw_params; } - void setDrawParams(QVector * _draw_params) { + void setDrawParams(QVector * _draw_params) + { if (!_draw_params) throw InvalidValueException("Invalid value in DrawParams in Res: null pointer"); for (int i = 0; i < draw_params->size(); i++) @@ -86,7 +106,8 @@ public: draw_params = _draw_params; } - ~Res() { + ~Res() + { for (int i = 0; i < fonts->size(); i++) delete fonts->at(i); for (int i = 0; i < colorspaces->size(); i++) diff --git a/ofdEditor/ofd/DataTypes/document/ct_commondata.h b/ofdEditor/ofd/DataTypes/document/ct_commondata.h index 799c40f6a64b0aef09d94e2bb86aca1a69be9c87..2eadbb26bf1f4f499bf984538ad759e3353ce59e 100644 --- a/ofdEditor/ofd/DataTypes/document/ct_commondata.h +++ b/ofdEditor/ofd/DataTypes/document/ct_commondata.h @@ -9,6 +9,7 @@ public: ST_ID max_unit_id; //当前文档中所有对象使用的最大标识 CT_PageArea *page_area; //指定多个页面区域的大小和位置 QVector *public_res; //公共资源序列,每个资源指向OFD包内部的一个XML文件 + QVector *document_res; //vector template_page; //模板页序列 ST_RefID default_cs; //缺省颜色空间 public: @@ -16,6 +17,7 @@ public: CT_CommonData() { public_res = new QVector(); + document_res = new QVector(); page_area = NULL; } diff --git a/ofdEditor/ofd/DataTypes/document/docbody.h b/ofdEditor/ofd/DataTypes/document/docbody.h index dcbbced3eecf1b42ac935226747298f13f9be1ed..975b0175ef641830a00cd623873cd67fe28d4e9b 100644 --- a/ofdEditor/ofd/DataTypes/document/docbody.h +++ b/ofdEditor/ofd/DataTypes/document/docbody.h @@ -40,7 +40,7 @@ public: } void setDocRoot(QString _doc_root_abs) { - ST_Loc p("DocRoot", _doc_root_abs); + ST_Loc p("DocRoot", _doc_root_abs,_doc_root_abs); doc_root = p; } diff --git a/ofdEditor/ofd/DataTypes/document/document.h b/ofdEditor/ofd/DataTypes/document/document.h index 0448abe1c0db6ad56399de50c1192c2c2b2ea540..d91c432ef39c309fef2561b625ff038cca38f3ed 100644 --- a/ofdEditor/ofd/DataTypes/document/document.h +++ b/ofdEditor/ofd/DataTypes/document/document.h @@ -10,13 +10,15 @@ class OFDSHARED_EXPORT Document { public: - CT_CommonData * common_data; //文档公共数据,定义了默认页面单位、页面区域定义、公共资源等数据 - CT_Outlines * outlines; //大纲树 - ST_Loc custom_tags; //指向自定义标引文件 - ST_Loc extensions; //指向拓展文件 - ST_Loc annotations; //指向注释文件 - ID_Table * id_table; //记录所有CT_Base的ID信息 + CT_CommonData * common_data; //文档公共数据,定义了默认页面单位、页面区域定义、公共资源等数据 + CT_Outlines * outlines; //大纲树 + ST_Loc custom_tags; //指向自定义标引文件 + ST_Loc extensions; //指向拓展文件 + ST_Loc annotations; //指向注释文件 + ID_Table * id_table; //记录所有CT_Base的ID信息 QVector * public_res; + QVector * document_res; + CT_Pages *pages; @@ -49,6 +51,8 @@ public: if (!_id_table) id_table = new ID_Table; else id_table = _id_table; + + document_res = new QVector(); } CT_CommonData * getCommonData() { diff --git a/ofdEditor/ofd/DataTypes/image/CT_GraphicUnit.h b/ofdEditor/ofd/DataTypes/image/CT_GraphicUnit.h index 0ae86be3932194d29c44e8de5bac710a172ef600..6e1bcd2ad214be84950a2175567870df6d1e36c8 100644 --- a/ofdEditor/ofd/DataTypes/image/CT_GraphicUnit.h +++ b/ofdEditor/ofd/DataTypes/image/CT_GraphicUnit.h @@ -40,30 +40,37 @@ public: public: friend class OFDParser; - CT_GraphicUnit(double _start_x = 0, - double _start_y = 0, - double _delta_x = 0, - double _delta_y = 0, - QString _name = "", - bool _visible = true, - int _draw_param = 0, - ID_Table * _id_table = NULL, - double _line_width = 0.353, - QString _cap = "Butt", - QString _join = "Miter", - double _miter_limit = 3.528, - double _dash_offset = 0.0, - QString _dash_pattern = "", - int _alpha = 255, - CT_Color * _fill_color = NULL, - CT_Color * _stroke_color = NULL - ) { + CT_GraphicUnit( + double _start_x = 0, + double _start_y = 0, + double _delta_x = 0, + double _delta_y = 0, + QString _name = "", + bool _visible = true, + int _draw_param = 0, + ID_Table * _id_table = NULL, + double _line_width = 0.353, + QString _cap = "Butt", + QString _join = "Miter", + double _miter_limit = 3.528, + double _dash_offset = 0.0, + QString _dash_pattern = "", + int _alpha = 255, + CT_Color * _fill_color = NULL, + CT_Color * _stroke_color = NULL) + { + fill_color = NULL; + stroke_color = NULL; + if (_start_x || _start_y || _delta_x || _delta_y) setBoundary(_start_x, _start_y, _delta_x, _delta_y); + setName(_name); setVisible(_visible); + if (_draw_param && _id_table) setDrawParam(_draw_param, _id_table); + setLineWidth(_line_width); setCap(_cap); setJoin(_join); @@ -73,56 +80,72 @@ public: setAlpha(_alpha); setFillColor(_fill_color); setStrokeColor(_stroke_color); + + } - ST_Box getBoundary() { + ST_Box getBoundary() + { return boundary; } - void setBoundary(double _start_x, double _start_y, double _delta_x, double _delta_y) { + void setBoundary(double _start_x, double _start_y, double _delta_x, double _delta_y) + { ST_Box b(_start_x, _start_y, _delta_x, _delta_y); boundary = b; } - QString getName() { + QString getName() + { return name; } - void setName(QString _name) { + void setName(QString _name) + { name = _name; } - bool getVisible() { + bool getVisible() + { return visible; } - void setVisible(bool _visible) { + void setVisible(bool _visible) + { visible = _visible; } - ST_RefID getDrawParam() { + ST_RefID getDrawParam() + { return draw_param; } - void setDrawParam(int _draw_param, ID_Table * _id_table) { + void setDrawParam(int _draw_param, ID_Table * _id_table) + { if (!_id_table->contains(_draw_param)) - throw InvalidIDException("CT_GraphicUnit对象中的DrawParam属性引用了未注册的ID: " + QString::number(_draw_param)); + throw InvalidIDException("CT_GraphicUnit对象中的DrawParam属性引用了未注册的ID: " + + QString::number(_draw_param)); + ST_RefID rd(_draw_param); draw_param = rd; } - double getLineWidth() { + double getLineWidth() + { return line_width; } - void setLineWidth(double _line_width) { + void setLineWidth(double _line_width) + { line_width = _line_width; } - QString getJoin() { + QString getJoin() + { return join; } - void setJoin(QString _join) { + void setJoin(QString _join) + { QStringList possible_values; possible_values.append("Miter"); possible_values.append("Round"); @@ -133,11 +156,13 @@ public: throw InvalidValueException("CT_GraphicUnit对象的Join属性使用了非法的值: " + _join); } - QString getCap() { + QString getCap() + { return cap; } - void setCap(QString _cap) { + void setCap(QString _cap) + { QStringList possible_values; possible_values.append("Butt"); possible_values.append("Round"); @@ -148,68 +173,82 @@ public: throw InvalidValueException("CT_GraphicUnit对象的Cap属性使用了非法的值: " + _cap); } - double getDashOffset() { + double getDashOffset() + { return dash_offset; } - void setDashOffset(double _dash_offset) { + void setDashOffset(double _dash_offset) + { if (dash_pattern.isNull()) throw InvalidValueException("CT_GraphicUnit对象的DashOffset属性,在DashPattern未出现时设置"); dash_offset = _dash_offset; } - ST_Array getDashPattern() { + ST_Array getDashPattern() + { return dash_pattern; } - void setDashPattern(QString _dash_pattern) { + void setDashPattern(QString _dash_pattern) + { ST_Array a("DashPattern", _dash_pattern); dash_pattern = a; } - double getMiterLimit() { + double getMiterLimit() + { return miter_limit; } - void setMiterLimit(double _miter_limit) { + void setMiterLimit(double _miter_limit) + { if (join != "Miter") throw InvalidValueException("Try to set set MiterLimit in CT_GraphicUnit, when its Join is not Miter"); miter_limit = _miter_limit; } - int getAlpha() { + int getAlpha() + { return alpha; } - void setAlpha(int _alpha) { + void setAlpha(int _alpha) + { if (_alpha < 0 || _alpha > 255) - throw InvalidValueException("CT_GraphicUnit的Alpha属性使用了无效的属性值: " + QString::number(_alpha)); + throw InvalidValueException("CT_GraphicUnit的Alpha属性使用了无效的属性值: " + + QString::number(_alpha)); alpha = _alpha; } - CT_Color * getFillColor() { + CT_Color * getFillColor() + { return fill_color; } - void setFillColor(CT_Color * _fill_color) { + void setFillColor(CT_Color * _fill_color) + { if (_fill_color) { delete fill_color; fill_color = _fill_color; } } - CT_Color * getStrokeColor() { + CT_Color * getStrokeColor() + { return stroke_color; } - void setStrokeColor(CT_Color * _stroke_color) { + void setStrokeColor(CT_Color * _stroke_color) + { if (_stroke_color) { delete stroke_color; stroke_color = _stroke_color; } } - ~CT_GraphicUnit() { + ~CT_GraphicUnit() + { delete fill_color; delete stroke_color; } diff --git a/ofdEditor/ofd/DataTypes/image/CT_Image.h b/ofdEditor/ofd/DataTypes/image/CT_Image.h index e3cd5bfcbd68b50fd2d31332dbb361356b49ff8d..02c8686d05ca8276b693d2a395c5f588f6106824 100644 --- a/ofdEditor/ofd/DataTypes/image/CT_Image.h +++ b/ofdEditor/ofd/DataTypes/image/CT_Image.h @@ -12,7 +12,6 @@ class OFDSHARED_EXPORT CT_Image : public CT_GraphicUnit ST_RefID resource_id; // 指向资源文件中定义的多媒体对象的ID ST_RefID substitution; // (可选)指定可替换图像, // 用于某些情况如高分辨率输出时进行图像替换。 - public: friend class OFDParser; diff --git a/ofdEditor/ofd/DataTypes/image/CT_MultiMedia.cpp b/ofdEditor/ofd/DataTypes/image/CT_MultiMedia.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40533d830c1a7864ac77f5493dcee5e0327ac96f --- /dev/null +++ b/ofdEditor/ofd/DataTypes/image/CT_MultiMedia.cpp @@ -0,0 +1,6 @@ +#include "CT_MultiMedia.h" + +CT_MultiMedia::CT_MultiMedia() +{ + +} diff --git a/ofdEditor/ofd/DataTypes/image/CT_MultiMedia.h b/ofdEditor/ofd/DataTypes/image/CT_MultiMedia.h new file mode 100644 index 0000000000000000000000000000000000000000..71bc3c45d9aefb19a80eb74d0b538385547a01da --- /dev/null +++ b/ofdEditor/ofd/DataTypes/image/CT_MultiMedia.h @@ -0,0 +1,22 @@ +#ifndef CT_MULTIMEDIA_H +#define CT_MULTIMEDIA_H + +#include "ofd_global.h" +#include "DataTypes/basic_datatype.h" +#include + + +class OFDSHARED_EXPORT CT_MultiMedia + :public CT_Base +{ +public: + friend class OFDParser; + CT_MultiMedia(); + + // 属性 + QString Type; // 多媒体资源主类型 + QString Format; // 多媒体资源格式 + QString MediaFile; // 多媒体文件路径 +}; + +#endif // CT_MULTIMEDIA_H diff --git a/ofdEditor/ofd/DataTypes/page/Page.h b/ofdEditor/ofd/DataTypes/page/Page.h index 2603a62dac08a5676de1cab93570df35ec720c94..c02f827f9d0f2f4742d434a3b5d5981edc59644b 100644 --- a/ofdEditor/ofd/DataTypes/page/Page.h +++ b/ofdEditor/ofd/DataTypes/page/Page.h @@ -28,7 +28,7 @@ public: } void setBaseLoc(QString _base_loc_abs) { - ST_Loc p("BaseLoc", _base_loc_abs); + ST_Loc p("BaseLoc", _base_loc_abs, _base_loc_abs); base_loc = p; } diff --git a/ofdEditor/ofd/DataTypes/page/page.h b/ofdEditor/ofd/DataTypes/page/page.h index 2603a62dac08a5676de1cab93570df35ec720c94..c02f827f9d0f2f4742d434a3b5d5981edc59644b 100644 --- a/ofdEditor/ofd/DataTypes/page/page.h +++ b/ofdEditor/ofd/DataTypes/page/page.h @@ -28,7 +28,7 @@ public: } void setBaseLoc(QString _base_loc_abs) { - ST_Loc p("BaseLoc", _base_loc_abs); + ST_Loc p("BaseLoc", _base_loc_abs, _base_loc_abs); base_loc = p; } diff --git a/ofdEditor/ofd/DataTypes/text/CT_Font.h b/ofdEditor/ofd/DataTypes/text/CT_Font.h index 237764f2d15118623160b34a975b56c67db82bf7..5294793c9e21961b72ee80e45238bd943f2f4929 100644 --- a/ofdEditor/ofd/DataTypes/text/CT_Font.h +++ b/ofdEditor/ofd/DataTypes/text/CT_Font.h @@ -15,6 +15,7 @@ class OFDSHARED_EXPORT CT_Font : public CT_Base { //字体声明类型 bool serif; bool fixed_width; //FontFile +public: CT_Font(){ charset = "GB18030"; italic = false; diff --git a/ofdEditor/ofd/DataTypes/text/CT_Text.h b/ofdEditor/ofd/DataTypes/text/CT_Text.h index 9498dea2019501b8ef345b3aac1358532e66cd55..b2b26145909a67dc9c9a29f8d3e7ae6e4935abe2 100644 --- a/ofdEditor/ofd/DataTypes/text/CT_Text.h +++ b/ofdEditor/ofd/DataTypes/text/CT_Text.h @@ -66,6 +66,7 @@ public: void setSize(double _size) { size = _size; + size_used = true; } bool sizeUsed() { @@ -119,8 +120,12 @@ public: void setWeight(int _weight) { if (_weight == 1000) weight = 900; - else if (_weight % 100 != 0 || _weight > 1000 || _weight <= 0) + else if (_weight % 100 != 0 + || _weight > 1000 + || _weight <= 0) weight = 400; + else + weight = _weight; } bool getItalic() { diff --git a/ofdEditor/ofd/DataTypes/text/ct_text.h b/ofdEditor/ofd/DataTypes/text/ct_text.h index 9498dea2019501b8ef345b3aac1358532e66cd55..b2b26145909a67dc9c9a29f8d3e7ae6e4935abe2 100644 --- a/ofdEditor/ofd/DataTypes/text/ct_text.h +++ b/ofdEditor/ofd/DataTypes/text/ct_text.h @@ -66,6 +66,7 @@ public: void setSize(double _size) { size = _size; + size_used = true; } bool sizeUsed() { @@ -119,8 +120,12 @@ public: void setWeight(int _weight) { if (_weight == 1000) weight = 900; - else if (_weight % 100 != 0 || _weight > 1000 || _weight <= 0) + else if (_weight % 100 != 0 + || _weight > 1000 + || _weight <= 0) weight = 400; + else + weight = _weight; } bool getItalic() { diff --git a/ofdEditor/ofd/Loaders/ZipTool.cpp b/ofdEditor/ofd/Loaders/ZipTool.cpp index d910294ea8bc4a9a1f4b2497d76be89d528c9826..b11c1e66d7d0eede0aafe8e09272d4ea2e155539 100644 --- a/ofdEditor/ofd/Loaders/ZipTool.cpp +++ b/ofdEditor/ofd/Loaders/ZipTool.cpp @@ -42,6 +42,10 @@ void ZipTool::extractDir(QString fileCompressed, QString dir) bool ZipTool::compressDir(QString fileCompressed, QString dir, bool deleteDir) { + QDir dirs; + if(dirs.exists(fileCompressed)) + deleteFolder(fileCompressed); + bool flag = false; flag = JlCompress::compressDir(fileCompressed,dir,true); // 递归 if(!flag) @@ -82,6 +86,7 @@ bool ZipTool::compressDir(QString fileCompressed, */ void ZipTool::deleteFolder(const QString &folderFullPath) { + qDebug() << "deleteFolder"; QDir dir(folderFullPath); QFileInfoList fileList; QFileInfo curFile; @@ -119,7 +124,8 @@ void ZipTool::deleteFolder(const QString &folderFullPath) if(fileListTemp.size() == 0) /* 下层没有文件或文件夹 则直接删除 */ { - dirTemp.rmdir("."); +// dirTemp.rmdir("."); + dirTemp.rmdir(QDir::toNativeSeparators(dirTemp.path())); fileList.removeAt(i); } else /* 下层有文件夹或文件 则将信息添加到列表 */ @@ -135,7 +141,10 @@ void ZipTool::deleteFolder(const QString &folderFullPath) } } } - dir.rmdir("."); +// dir.rmdir("."); + dir.rmdir(QDir::toNativeSeparators(dir.path())); + + qDebug() << "deleteFolder succeed"; /*删除目标文件夹, * 如果只是清空文件夹folderFullPath的内容 * 而不删除folderFullPath本身,则删掉本行即可 */ diff --git a/ofdEditor/ofd/ofd.pro b/ofdEditor/ofd/ofd.pro index d98011fa968511a2f837f9b3fdb39863ce4e2220..a918cce9faf89bb91d0b6fc7684939d53f28fb19 100644 --- a/ofdEditor/ofd/ofd.pro +++ b/ofdEditor/ofd/ofd.pro @@ -26,31 +26,23 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ - main.cpp \ - mainwindow.cpp \ ofd_parser.cpp \ DataTypes/basic_datatypes.cpp \ ofd_writer.cpp \ Loaders/ZipTool.cpp \ ofdexceptions.cpp \ - DataTypes/page/CT_PageBlock.cpp - + DataTypes/page/CT_PageBlock.cpp \ + DataTypes/image/CT_MultiMedia.cpp HEADERS +=\ - mainwindow.h \ DataTypes/basic_datatype.h \ -# DataTypes/CT_Action.h \ -# DataTypes/Color/CT_AxialShd.h \ DataTypes/Color/CT_Color.h \ DataTypes/Color/CT_ColorSpace.h \ -# DataTypes/Color/CT_Pattern.h \ -# DataTypes/Color/CT_RadialShd.h \ DataTypes/document/CT_CommonData.h \ DataTypes/document/CT_DocInfo.h \ DataTypes/document/DocBody.h \ DataTypes/document/Document.h \ DataTypes/document/OFD.h \ -# DataTypes/image/CT_Clip.h \ DataTypes/image/CT_DrawParam.h \ DataTypes/image/CT_GraphicUnit.h \ DataTypes/image/CT_Image.h \ @@ -62,7 +54,6 @@ HEADERS +=\ DataTypes/page/CT_Pages.h \ DataTypes/page/Page.h \ ofd_parser.h \ -# DataTypes/text/CT_CGTransform.h \ DataTypes/text/TextCode.h \ ofd_global.h \ ofd_writer.h \ @@ -72,7 +63,8 @@ HEADERS +=\ DataTypes/document/CT_Outlines.h \ DataTypes/document/CustomTags.h \ DataTypes/document/Res.h \ - DataTypes/text/CT_Font.h + DataTypes/text/CT_Font.h \ + DataTypes/image/CT_MultiMedia.h DESTDIR = ../bin # 生成文件在这 @@ -80,7 +72,8 @@ MOC_DIR = ./moc # Q_OBJECT 类转换后的文件 RCC_DIR = ./rcc # .qrc 文件转换后存放路径 OBJECTS_DIR += ./tmp # .obj 文件存放路径 -INCLUDEPATH += $$PWD/../libs/quazip/includes # 引用quazip库 +INCLUDEPATH += $$PWD/../libs/quazip/includes \ # 引用quazip库 + $$PWD/../libs/jsoncpp # $$PWD表示当前pro对应的文件夹路径 FORMS += mainwindow.ui \ diff --git a/ofdEditor/ofd/ofd_parser.cpp b/ofdEditor/ofd/ofd_parser.cpp index a8e738d1c470f20f41d2c3eadcb6adad9f96d722..76492bc7a37a148e4d6bbc13a39898fd9d3e8612 100644 --- a/ofdEditor/ofd/ofd_parser.cpp +++ b/ofdEditor/ofd/ofd_parser.cpp @@ -1,7 +1,5 @@ #include "ofd_parser.h" #include - - #include "DataTypes/document/OFD.h" #include "DataTypes/document/DocBody.h" #include "DataTypes/document/CT_DocInfo.h" @@ -12,6 +10,7 @@ #include "DataTypes/text/CT_Text.h" #include "DataTypes/image/CT_Path.h" #include "DataTypes/image/CT_Image.h" +#include "DataTypes/image/CT_MultiMedia.h" OFDParser::OFDParser(QString _path) : current_path("OFD", _path) { document = new QDomDocument(); @@ -21,7 +20,7 @@ OFDParser::OFDParser(QString _path) : current_path("OFD", _path) { void OFDParser::openFile() { QFile ofd_file(current_path.getPath()); if (!ofd_file.open(QFile::ReadOnly | QFile::Text)) { //检查文件是否存在&正常打开 - throw ParsingFileException("无法打开XML文件: " + current_path.getPath()); + qDebug() << "无法打开XML文件: " + current_path.getPath(); } if (document->setContent(&ofd_file, //解析OFD文档并将树状内容存在document文件中 false, @@ -30,7 +29,7 @@ void OFDParser::openFile() { &error_column)) { ofd_file.close(); } else { - throw ParsingFileException("XML文件格式有错误: " + current_path.getPath()); + qDebug() << "XML文件格式有错误: " + current_path.getPath(); } } @@ -43,11 +42,13 @@ OFD * OFDParser::readOFD() { if (new_ofd.hasAttribute("DocType")) ofd_data->doc_type = new_ofd.attribute("DocType"); else - throw ParsingFormatException("OFD类型的数据中中缺少必要的DocType属性\n位于" + current_path.getRelativePath()); + qDebug() << "OFD类型的数据中中缺少必要的DocType属性\n位于" + << current_path.getRelativePath(); if (new_ofd.hasAttribute("Version")) ofd_data->version = new_ofd.attribute("Version"); else - throw ParsingFormatException("OFD类型的数据中中缺少必要的Version属性\n位于" + current_path.getRelativePath()); + qDebug() << "OFD类型的数据中中缺少必要的Version属性\n位于" + << current_path.getRelativePath(); ofd_data->root_path = current_path; QDomElement new_docbody = new_ofd.firstChildElement("ofd:DocBody"); @@ -91,20 +92,23 @@ OFD * OFDParser::readOFD() { } } } else { - throw ParsingFormatException("DocBody类型的数据中中缺少必要的DocInfo成员\n位于" + current_path.getRelativePath()); + qDebug() << "DocBody类型的数据中中缺少必要的DocInfo成员\n位于" + << current_path.getRelativePath(); } QDomElement new_docroot = new_docbody.firstChildElement("ofd:DocRoot"); if (!new_docroot.isNull()) { ST_Loc p("Document", new_docroot.text(), current_path); docbody_data->doc_root = p; } else { - throw ParsingFormatException("DocBody类型的数据中中缺少必要的DocInfo成员\n位于" + current_path.getRelativePath()); + qDebug() << "DocBody类型的数据中中缺少必要的DocInfo成员\n位于" + << current_path.getRelativePath(); } new_docbody = new_ofd.nextSiblingElement("ofd:DocBody"); } } else { - throw ParsingFormatException("OFD类型的数据中中缺少必要的DocBody成员\n位于" + current_path.getRelativePath()); + qDebug() << "OFD类型的数据中中缺少必要的DocBody成员\n位于" + << current_path.getRelativePath(); } if (ofd_data) { for (int i = 0; i < ofd_data->docbodys->size(); i++) { @@ -123,27 +127,33 @@ Document * OFDParser::readDocument() { if (!new_document.isNull()) { document_data = new Document(); id_table = document_data->id_table; + // commonData QDomElement new_commondata = new_document.firstChildElement("ofd:CommonData"); if (!new_commondata.isNull()) { CT_CommonData * commondata_data = new CT_CommonData(); document_data->common_data = commondata_data; - qDebug() << "Checkpoint 1.1..."; + qDebug() << "Checkpoint 1.1..."; QDomElement t; + + // MaxUnitID if (!(t = new_commondata.firstChildElement("ofd:MaxUnitID")).isNull()) { commondata_data->max_unit_id = t.text().toInt(); } else { - throw ParsingFormatException("缺少MaxID"); + qDebug("缺少MaxID"); //Error } + // PageArea if (!(t = new_commondata.firstChildElement("ofd:PageArea")).isNull()) { CT_PageArea *pagearea_data = new CT_PageArea(); commondata_data->page_area = pagearea_data; readPageArea(pagearea_data, t); } else { - throw ParsingFormatException("PageArea"); + qDebug("PageArea"); } - qDebug() << "Checkpoint 1.1.1..."; + qDebug() << "Checkpoint 1.1.1..."; + + // publicRes t = new_commondata.firstChildElement("ofd:PublicRes"); while (!t.isNull()) { ST_Loc p("PublicRes", t.text(), current_path); @@ -152,14 +162,26 @@ Document * OFDParser::readDocument() { t = t.nextSiblingElement("ofd:PublicRes"); } + // documentRes + t = new_commondata.firstChildElement("ofd:DocumentRes"); + while (!t.isNull()) { + ST_Loc p("DocumentRes", t.text(), current_path); + //qDebug() << "PublicRes = " << t.text(); + commondata_data->document_res->push_back(p); + t = t.nextSiblingElement("ofd:DocumentRes"); + } + + if (!(t = new_commondata.firstChildElement("ofd:DefaultCS")).isNull()) { //to be implemented } } else { - throw ParsingFormatException("Document类型的数据中中缺少必要的CommonData成员\n位于Document.xml"); + qDebug("Document类型的数据中中缺少必要的CommonData成员\n位于Document.xml"); } - qDebug() << "Checkpoint 1.2..."; + + qDebug() << "Checkpoint 1.2..."; + // Pages QDomElement new_pages = new_document.firstChildElement("ofd:Pages"); CT_Pages *pages_data; if (!new_pages.isNull()) { @@ -176,10 +198,10 @@ Document * OFDParser::readDocument() { new_page = new_page.nextSiblingElement("ofd:Page"); } } else { - throw ParsingFormatException("Document类型的数据中中缺少必要的Pages成员\n位于Document.xml"); + qDebug("Document类型的数据中中缺少必要的Pages成员\n位于Document.xml"); } document_data->pages = pages_data; - qDebug() << "Checkpoint 1.3..."; + qDebug() << "Checkpoint 1.3..."; QDomElement new_outlines = new_document.firstChildElement("ofd:Outlines"); if (!new_outlines.isNull()) { //to be implemented @@ -202,9 +224,11 @@ Document * OFDParser::readDocument() { } } else { - throw ParsingFormatException("Document.xml文档中缺少必要的Document标签\n位于" + current_path.getRelativePath()); + qDebug() << "Document.xml文档中缺少必要的Document标签\n位于" + << current_path.getRelativePath(); } - //访问资源 + + // publicRes for (int i = 0; i < document_data->common_data->public_res->size(); i++) { current_path = document_data->common_data->public_res->at(i); Res * res_data = new Res(); @@ -212,6 +236,14 @@ Document * OFDParser::readDocument() { document_data->public_res->push_back(res_data); } + // documentRes + for (int i = 0; i < document_data->common_data->document_res->size(); i++) { + current_path = document_data->common_data->document_res->operator [](i); + Res * res_data = new Res(); + readResource(res_data); + document_data->public_res->push_back(res_data); + } + //访问页面 for (int i = 0; i < document_data->pages->pages->size(); i++) { current_path = document_data->pages->pages->at(i)->base_loc; @@ -226,20 +258,31 @@ Document * OFDParser::readDocument() { return document_data; } +/// +/// \brief OFDParser::readPage +/// 解析页 +/// \param page_data +/// void OFDParser::readPage(Page * page_data) { openFile(); QDomElement new_page = document->firstChildElement("ofd:Page"); qDebug() << "Checkpoint 2: Entering Page..."; - if (!new_page.isNull()) { + if (!new_page.isNull()) + { QDomElement t; - if (!(t = new_page.firstChildElement("ofd:Area")).isNull()) { + + // pageArea + if (!(t = new_page.firstChildElement("ofd:Area")).isNull()) + { CT_PageArea * area_data = new CT_PageArea(); readPageArea(area_data, t); page_data->area = area_data; } + // pageRes t = new_page.firstChildElement("ofd:PageRes"); - while (!t.isNull()) { + while (!t.isNull()) + { ST_Loc p("PageRes", t.text(), current_path); Res * new_res = new Res(); current_path = p; @@ -248,97 +291,170 @@ void OFDParser::readPage(Page * page_data) { t = t.nextSiblingElement("ofd:PageRes"); } - if (!(t = new_page.firstChildElement("ofd:Content")).isNull()) { -// qDebug() << "Checkpoint 2.1"; + // Content + if (!(t = new_page.firstChildElement("ofd:Content")).isNull()) + { + // qDebug() << "Checkpoint 2.1"; + // layer QDomElement new_layer = t.firstChildElement("ofd:Layer"); - while (!new_layer.isNull()) { + while (!new_layer.isNull()) + { CT_Layer * layer_data = new CT_Layer(); + // ID page_data->getContent()->push_back(layer_data); - if (new_layer.hasAttribute("ID")) { + if (new_layer.hasAttribute("ID")) + { ST_ID i(new_layer.attribute("ID").toInt()); layer_data->setID(i, id_table); - } else { - throw ParsingFormatException("CT_Layer类型数据中缺少必要的ID属性\n位于" + current_path.getRelativePath()); } - if (new_layer.hasAttribute("DrawParam")) { + else + { + qDebug() << "CT_Layer类型数据中缺少必要的ID属性\n位于" + << current_path.getRelativePath(); + } + + // Type + if(new_layer.hasAttribute("Type")) + { + QString tempType = new_layer.attribute("Type"); + layer_data->setType(tempType); + } + + // DrawParam + if (new_layer.hasAttribute("DrawParam")) + { ST_RefID ri(new_layer.attribute("DrawParam").toInt()); if (id_table->contains(ri.getRefID())) layer_data->draw_param = ri; - else { - qDebug() << "Checkpoint ID 1..."; - throw ParsingIDException("Layer类型数据的DrawParam属性引用了未注册的ID 位于" + current_path.getRelativePath()); + else + { + qDebug() << "Checkpoint ID 1..."; + qDebug() << "Layer类型数据的DrawParam属性引用了未注册的ID 位于" + << current_path.getRelativePath(); } } -// qDebug() << "Checkpoint 2.2"; + // qDebug() << "Checkpoint 2.2"; QDomElement t; //解析文字对象 bool is_first_textcode_x = true, is_first_textcode_y = true; double last_x = 0.0, last_y = 0.0; + + // TextObject t = new_layer.firstChildElement("ofd:TextObject"); - while (!t.isNull()) { + while (!t.isNull()) + { //qDebug() << "Start to read TextObject..." << endl; CT_Text * text_data = new CT_Text(); layer_data->text_object->push_back(text_data); + readGraphicUnit(text_data, t); //Read TextObject attributes - if (t.hasAttribute("Font")) { + if (t.hasAttribute("Font")) + { ST_RefID ri(t.attribute("Font").toInt()); if (id_table->contains(ri.getRefID())) text_data->font = ri; - else { + else + { qDebug() << "Checkpoint ID 2..."; - throw ParsingIDException("CT_Text类型数据的Font属性引用了未注册的ID:" + QString::number(ri.getRefID()) + " 位于" + current_path.getRelativePath()); + qDebug() << "CT_Text类型数据的Font属性引用了未注册的ID:" + << QString::number(ri.getRefID()) + << " 位于" + << current_path.getRelativePath(); } - } else { - throw ParsingFormatException("CT_Text类型数据中缺少必要的Font属性\n位于" + current_path.getRelativePath()); + } + else + { + qDebug() << "CT_Text类型数据中缺少必要的Font属性\n位于" + << current_path.getRelativePath(); } - if (t.hasAttribute("Size")) { + // size + if (t.hasAttribute("Size")) + { text_data->size = t.attribute("Size").toDouble(); text_data->size_used = true; - } else { - throw ParsingFormatException("CT_Text类型数据中缺少必要的Size属性\n位于" + current_path.getRelativePath()); } -// qDebug() << "Checkpoint 2.3"; + else + { + qDebug() << "CT_Text类型数据中缺少必要的Size属性\n位于" + << current_path.getRelativePath(); + } + + // Italic + if(t.hasAttribute("Italic")) + { + QString italic = t.attribute("Italic"); + italic = italic.toLower(); + if(italic == "true") + { + text_data->italic = true; + } + } + + // Weight + if(t.hasAttribute("Weight")) + { + text_data->weight = t.attribute("Weight").toInt(); + } + + + // qDebug() << "Checkpoint 2.3"; //many optional attributes to be implemented + // textCode QDomElement t2 = t.firstChildElement("ofd:TextCode"); - if (t2.isNull()) { - throw ParsingFormatException("CT_Text类型数据中缺少必要的TextCode成员\n位于" + current_path.getRelativePath()); + if (t2.isNull()) + { + qDebug() << "CT_Text类型数据中缺少必要的TextCode成员\n位于" + << current_path.getRelativePath(); } -// qDebug() << "Checkpoint 2.3.1"; - while(!t2.isNull()) { + // qDebug() << "Checkpoint 2.3.1"; + while(!t2.isNull()) + { TextCode * text_code_data = new TextCode(); -// qDebug() << "Checkpoint 2.3.1.0"; + // qDebug() << "Checkpoint 2.3.1.0"; text_data->text_code->push_back(text_code_data); -// qDebug() << "Checkpoint 2.3.1.1"; - if (t2.hasAttribute("X")) { + // qDebug() << "Checkpoint 2.3.1.1"; + if (t2.hasAttribute("X")) + { last_x = text_code_data->x = t2.attribute("X").toDouble(); if (is_first_textcode_x) is_first_textcode_x = false; - } else { + } + else + { if (!is_first_textcode_x && !is_first_textcode_y) text_code_data->x = last_x; - else { - throw ParsingFormatException("TextCode类型数据中缺少第一个X值\n位于" + current_path.getRelativePath()); + else + { + qDebug() << "TextCode类型数据中缺少第一个X值\n位于" + << current_path.getRelativePath(); } } -// qDebug() << "Checkpoint 2.3.2"; - if (t2.hasAttribute("Y")) { + // qDebug() << "Checkpoint 2.3.2"; + if (t2.hasAttribute("Y")) + { last_y = text_code_data->y = t2.attribute("Y").toDouble(); if (is_first_textcode_y) is_first_textcode_y = false; - } else { + } + else + { if (!is_first_textcode_x && !is_first_textcode_y) text_code_data->y = last_y; - else { - throw ParsingFormatException("TextCode类型数据中缺少第一个Y值\n位于" + current_path.getRelativePath()); + else + { + qDebug() << "TextCode类型数据中缺少第一个Y值\n位于" + << current_path.getRelativePath(); } } - if (t2.hasAttribute("DeltaX")) { + if (t2.hasAttribute("DeltaX")) + { ST_Array delta_x_data("DeltaX", t2.attribute("DeltaX")); text_code_data->delta_x = delta_x_data; } - if (t2.hasAttribute("DeltaY")) { + if (t2.hasAttribute("DeltaY")) + { ST_Array delta_y_data("DeltaX", t2.attribute("DeltaY")); text_code_data->delta_y = delta_y_data; } @@ -348,61 +464,86 @@ void OFDParser::readPage(Page * page_data) { } t = t.nextSiblingElement("ofd:TextObject"); } -// qDebug() << "Checkpoint 2.4"; + // qDebug() << "Checkpoint 2.4"; + //解析矢量图对象 t = new_layer.firstChildElement("ofd:PathObject"); - while (!t.isNull()) { + while (!t.isNull()) + { CT_Path * path_data = new CT_Path(); layer_data->path_object->push_back(path_data); readGraphicUnit(path_data, t); - if (t.hasAttribute("Stroke")) { + if (t.hasAttribute("Stroke")) + { path_data->stroke = t.attribute("Stroke") == "false" ? false : true; } - if (t.hasAttribute("Fill")) { + if (t.hasAttribute("Fill")) + { path_data->fill = t.attribute("Fill") == "false" ? false : true; } - if (t.hasAttribute("Rule")) { + if (t.hasAttribute("Rule")) + { if (t.attribute("Rule") == "NonZero") path_data->rule = "NonZero"; else if (t.attribute("Rule") == "Even-Odd") path_data->rule = "Even-Odd"; - else { - throw ParsingFormatException("CT_Path类型数据中的Rule属性值为非法值\n位于" + current_path.getRelativePath() + " 值为" + t.attribute("Rule")); + else + { + qDebug() << "CT_Path类型数据中的Rule属性值为非法值\n位于" + << current_path.getRelativePath() + << " 值为" + << t.attribute("Rule"); } } - if (!t.firstChildElement("ofd:AbbreviatedData").isNull()) { + // 图形变换的描述 + if (!t.firstChildElement("ofd:AbbreviatedData").isNull()) + { path_data->abbreviated_data = t.firstChildElement("ofd:AbbreviatedData").text(); - } else { - throw ParsingFormatException("CT_Path类型数据中缺少必要的AbbreviatedData成员\n位于" + current_path.getRelativePath()); + } + else + { + qDebug() << "CT_Path类型数据中缺少必要的AbbreviatedData成员\n位于" + << current_path.getRelativePath(); } t = t.nextSiblingElement("ofd:PathObject"); } //解析位图对象 + // ImageObject t = new_layer.firstChildElement("ofd:ImageObject"); - while (!t.isNull()) { + while (!t.isNull()) + { CT_Image * image_data = new CT_Image(); layer_data->image_object->push_back(image_data); - readGraphicUnit(image_data, t); - if (t.hasAttribute("ResourceID")) { + readGraphicUnit(image_data, t); // 读取图元里的共用的数据 + if (t.hasAttribute("ResourceID")) + { ST_RefID ri(t.attribute("ResourceID").toInt()); if (id_table->contains(ri.getRefID())) image_data->resource_id = ri; - else { + else + { qDebug() << ri.getRefID(); qDebug() << "Checkpoint ID 3..."; - //throw ParsingIDException("CT_Image类型数据的ResourceID属性引用了未注册的ID 位于" + current_path.getRelativePath()); + //qDebug("CT_Image类型数据的ResourceID属性引用了未注册的ID 位于" + current_path.getRelativePath()); } - } else { - throw ParsingFormatException("CT_Image类型数据中缺少必要的ResourceID属性\n位于" + current_path.getRelativePath()); } - if (t.hasAttribute("Substitution")) { + else + { + qDebug() << "CT_Image类型数据中缺少必要的ResourceID属性\n位于" + << current_path.getRelativePath(); + } + + if (t.hasAttribute("Substitution")) + { ST_RefID ri(t.attribute("Substitution").toInt()); if (id_table->contains(ri.getRefID())) image_data->substitution = ri; - else { + else + { qDebug() << "Checkpoint ID 4..."; - throw ParsingIDException("CT_Image类型数据的Substitution属性引用了未注册的ID 位于" + current_path.getRelativePath()); + qDebug() << "CT_Image类型数据的Substitution属性引用了未注册的ID 位于" + << current_path.getRelativePath(); } } t = t.nextSiblingElement("ofd:ImageObject"); @@ -412,104 +553,178 @@ void OFDParser::readPage(Page * page_data) { new_layer = new_layer.nextSiblingElement("ofd:Layer"); } } - } else { - throw ParsingFormatException("Content.xml文档中缺少必要的Page标签\n位于" + current_path.getRelativePath()); } -// qDebug() << "Checkpoint 3"; + else + { + qDebug() << "Content.xml文档中缺少必要的Page标签\n位于" + << current_path.getRelativePath(); + } + // qDebug() << "Checkpoint 3"; } void OFDParser::readPageArea(CT_PageArea * data, QDomElement & root_node) { QDomElement t; - qDebug() << "Checkpoint PA 1..."; - if (!(t = root_node.firstChildElement("ofd:PhysicalBox")).isNull()) { + // qDebug() << "Checkpoint PA 1..."; + if (!(t = root_node.firstChildElement("ofd:PhysicalBox")).isNull()) + { QStringList values = t.text().split(" "); //qDebug() << values[0] << values[1] << values[2] << endl; - if (values.size() == 4) { - data->physical_box = ST_Box(values[0].toDouble(), values[1].toDouble(), values[2].toDouble(), values[3].toDouble()); + if (values.size() == 4) + { + data->physical_box = ST_Box( + values[0].toDouble(), + values[1].toDouble(), + values[2].toDouble(), + values[3].toDouble()); } - else { - throw ParsingFormatException("CT_PageArea类型数据的PhysicalBox成员的值的数目错误\n位于" + current_path.getRelativePath()); + else + { + qDebug() << "CT_PageArea类型数据的PhysicalBox成员的值的数目错误\n位于" + << current_path.getRelativePath(); } - } else { - throw ParsingFormatException("CT_PageArea类型的数据中中缺少必要的PhysicalBox成员\n位于" + current_path.getRelativePath()); } - qDebug() << "Checkpoint PA 2..."; - if (!(t = root_node.firstChildElement("ofd:ApplicationBox")).isNull()) { + else + { + qDebug() << "CT_PageArea类型的数据中中缺少必要的PhysicalBox成员\n位于" + << current_path.getRelativePath(); + } + // qDebug() << "Checkpoint PA 2..."; + if (!(t = root_node.firstChildElement("ofd:ApplicationBox")).isNull()) + { QStringList values = t.text().split(" "); if (values.size() == 4) - data->application_box = ST_Box(values[0].toDouble(), values[1].toDouble(), values[2].toDouble(), values[3].toDouble()); - else { - throw ParsingFormatException("CT_PageArea类型数据的ApplicationBox成员的值的数目错误\n位于" + current_path.getRelativePath()); + data->application_box = ST_Box( + values[0].toDouble(), + values[1].toDouble(), + values[2].toDouble(), + values[3].toDouble()); + else + { + qDebug() << "CT_PageArea类型数据的ApplicationBox成员的值的数目错误\n位于" + << current_path.getRelativePath(); } } - qDebug() << "Checkpoint PA 3..."; - if (!(t = root_node.firstChildElement("ofd:ContentBox")).isNull()) { + // qDebug() << "Checkpoint PA 3..."; + if (!(t = root_node.firstChildElement("ofd:ContentBox")).isNull()) + { QStringList values = t.text().split(" "); if (values.size() == 4) - data->content_box = ST_Box(values[0].toDouble(), values[1].toDouble(), values[2].toDouble(), values[3].toDouble()); + data->content_box = ST_Box( + values[0].toDouble(), + values[1].toDouble(), + values[2].toDouble(), + values[3].toDouble()); else - throw ParsingFormatException("CT_PageArea类型数据的ContentBox成员的值的数目错误\n位于" + current_path.getRelativePath()); + qDebug() << "CT_PageArea类型数据的ContentBox成员的值的数目错误\n位于" + << current_path.getRelativePath(); } - if (!(t = root_node.firstChildElement("ofd:BleedBox")).isNull()) { + if (!(t = root_node.firstChildElement("ofd:BleedBox")).isNull()) + { QStringList values = t.text().split(" "); if (values.size() == 4) - data->bleed_box = ST_Box(values[0].toDouble(), values[1].toDouble(), values[2].toDouble(), values[3].toDouble()); - else { - throw ParsingFormatException("CT_PageArea类型数据的BleedBox成员的值的数目错误\n位于" + current_path.getRelativePath()); + data->bleed_box = ST_Box( + values[0].toDouble(), + values[1].toDouble(), + values[2].toDouble(), + values[3].toDouble()); + else + { + qDebug() << "CT_PageArea类型数据的BleedBox成员的值的数目错误\n位于" + << current_path.getRelativePath(); } } } -void OFDParser::readGraphicUnit(CT_GraphicUnit *data, QDomElement &root_node) { - //读取属性 - if (root_node.hasAttribute("ID")) { +/// +/// \brief OFDParser::readGraphicUnit +/// \param data +/// \param root_node +/// +void OFDParser::readGraphicUnit(CT_GraphicUnit *data, QDomElement &root_node) +{ + // ID + if (root_node.hasAttribute("ID")) + { ST_ID i(root_node.attribute("ID").toInt()); data->setID(i, id_table); - } else { - throw ParsingFormatException("CT_GraphicUnit类型数据中缺少必要的ID属性\n位于" + current_path.getRelativePath()); + } + else + { + qDebug() << "CT_GraphicUnit类型数据中缺少必要的ID属性\n位于" + << current_path.getRelativePath(); } - if (root_node.hasAttribute("Boundary")) { + // Boundary + if (root_node.hasAttribute("Boundary")) + { QStringList values = root_node.attribute("Boundary").split(" "); - if (values.size() == 4) { - data->boundary = ST_Box(values[0].toDouble(), values[1].toDouble(), values[2].toDouble(), values[3].toDouble()); + if (values.size() == 4) + { + data->boundary = ST_Box( + values[0].toDouble(), + values[1].toDouble(), + values[2].toDouble(), + values[3].toDouble()); } - else { - throw ParsingFormatException("CT_GraphicUnit类型数据的Boundary成员的值的数目错误\n位于" + current_path.getRelativePath()); + else + { + qDebug() << "CT_GraphicUnit类型数据的Boundary成员的值的数目错误\n位于" + << current_path.getRelativePath(); } - } else { - throw ParsingFormatException("CT_GraphicUnit类型数据中缺少必要的ID属性\n位于" + current_path.getRelativePath()); + } + else + { + qDebug() << "CT_GraphicUnit类型数据中缺少必要的ID属性\n位于" + << current_path.getRelativePath(); } //读取成员 QDomElement t; - if (!(t = root_node.firstChildElement("ofd:FillColor")).isNull()) { + if (!(t = root_node.firstChildElement("ofd:FillColor")).isNull()) + { CT_Color * fill_color_data = new CT_Color(); data->fill_color = fill_color_data; readColor(fill_color_data, t); + if (root_node.hasAttribute("ID") + && root_node.attribute("ID").toInt() == 3) + qDebug() << "In OFDParser: " << fill_color_data; } //Other members to be implemented } +/// +/// \brief OFDParser::readResource +/// 解析资源文件 +/// \param res_data +/// void OFDParser::readResource(Res * res_data) { + qDebug() << "read res-----------"; openFile(); QDomElement new_res = document->firstChildElement("ofd:Res"); - if (!new_res.isNull()) { + if (!new_res.isNull()) + { //读取属性 - if (new_res.hasAttribute("BaseLoc")) { + if (new_res.hasAttribute("BaseLoc")) + { ST_Loc new_baseloc("BaseLoc", new_res.attribute("BaseLoc"), current_path); res_data->base_loc = new_baseloc; - } else { - throw ParsingFormatException("Res类型数据中缺少必要的BaseLoc属性\n位于" + current_path.getRelativePath()); } - //读取成员 + else + { + qDebug() << "Res类型数据中缺少必要的BaseLoc属性\n位于" + << current_path.getRelativePath(); + } + + //读取成员--font QDomElement t; - if (!(t = new_res.firstChildElement("ofd:Fonts")).isNull()) { + if (!(t = new_res.firstChildElement("ofd:Fonts")).isNull()) + { QDomElement t2 = t.firstChildElement("ofd:Font"); - while (!t2.isNull()) { + while (!t2.isNull()) + { CT_Font * font_data = new CT_Font(); res_data->fonts->push_back(font_data); readFont(font_data, t2); @@ -517,9 +732,12 @@ void OFDParser::readResource(Res * res_data) { } } - if (!(t = new_res.firstChildElement("ofd:ColorSpaces")).isNull()) { + // colorSpaces + if (!(t = new_res.firstChildElement("ofd:ColorSpaces")).isNull()) + { QDomElement t2 = t.firstChildElement("ofd:ColorSpace"); - while (!t2.isNull()) { + while (!t2.isNull()) + { CT_ColorSpace * colorspace_data = new CT_ColorSpace(); res_data->colorspaces->push_back(colorspace_data); readColorSpace(colorspace_data, t2); @@ -527,150 +745,283 @@ void OFDParser::readResource(Res * res_data) { } } - if (!(t = new_res.firstChildElement("ofd:DrawParams")).isNull()) { + // DrawParams + if (!(t = new_res.firstChildElement("ofd:DrawParams")).isNull()) + { QDomElement t2 = t.firstChildElement("ofd:DrawParam"); - while (!t2.isNull()) { + while (!t2.isNull()) + { CT_DrawParam * draw_param_data = new CT_DrawParam(); res_data->draw_params->push_back(draw_param_data); readDrawParam(draw_param_data, t2); t2 = t2.nextSiblingElement("ofd:DrawParam"); } } + + // MultMedia + if (!(t = new_res.firstChildElement("ofd:MultiMedias")).isNull()) + { +// qDebug() << "multmedias flag read"; + + QDomElement t2 = t.firstChildElement("ofd:MultiMedia"); + while (!t2.isNull()) + { + + CT_MultiMedia *multimedia = new CT_MultiMedia(); + + // ID + if(t2.hasAttribute("ID")) + { + ST_ID i(t2.attribute("ID").toLong()); +// qDebug() << "multimedia set id"; + multimedia->setID(i, id_table); +// qDebug() << "multimedia set id"; + } + else + { + qDebug() << "multimedia don't has ID attribute"; + continue; + } + + // Type + if(t2.hasAttribute("Type")) + { + multimedia->Type = t2.attribute("Type"); + } + else + { + qDebug() << "Multimedia has no Type attribute"; + continue; + } + + // mediaFile + QDomElement mediaFile = t2.firstChildElement("ofd:MediaFile"); + // 直接转换为了绝对路径 + multimedia->MediaFile = res_data->base_loc + "/" + mediaFile.text(); // 文件路径 + res_data->multMedias->push_back(multimedia); // 插入 + +// qDebug() << multimedia->getID().getID() +// << multimedia->Type +// << multimedia->MediaFile; + + t2 = t2.nextSiblingElement("ofd:MultiMedia"); + } + } + //Other stuff to be implemented - } else { - throw ParsingFormatException("Resource.xml文档中缺少必要的Res标签\n位于" + current_path.getRelativePath()); } + else + { + qDebug() << "Resource.xml文档中缺少必要的Res标签\n位于" + << current_path.getRelativePath(); + } + + qDebug() << "read res-----------end"; //qDebug() << "End of reading Resourse..." << endl; } void OFDParser::readColor(CT_Color *data, QDomElement & root_node) { - if (root_node.hasAttribute("Value")) { + if (root_node.hasAttribute("Value")) + { ST_Array value_data("Value", root_node.attribute("Value")); data->value = value_data; } - if (root_node.hasAttribute("ColorSpace")) { + if (root_node.hasAttribute("ColorSpace")) + { ST_RefID colorspace_data(root_node.attribute("ColorSpace").toInt()); if (id_table->contains(colorspace_data.getRefID())) data->color_space = colorspace_data; - else { - throw ParsingIDException("CT_Color类型数据的ColorSpace属性引用了未注册的ID:" + QString::number(colorspace_data.getRefID()) + " 位于" + current_path.getRelativePath()); + else + { + qDebug() << "CT_Color类型数据的ColorSpace属性引用了未注册的ID:" + << QString::number(colorspace_data.getRefID()) + << " 位于" + << current_path.getRelativePath(); } } - if (root_node.hasAttribute("Index")) { + if (root_node.hasAttribute("Index")) + { data->index = root_node.attribute("Index").toInt(); data->index_used = true; } - if (root_node.hasAttribute("Alpha")) { + if (root_node.hasAttribute("Alpha")) + { data->alpha = root_node.attribute("Alpha").toInt(); } //Other stuff to be implemented } -void OFDParser::readFont(CT_Font * data, QDomElement & root_node) { - if (root_node.hasAttribute("ID")) { +void OFDParser::readFont(CT_Font * data, QDomElement & root_node) +{ + if (root_node.hasAttribute("ID")) + { ST_ID i(root_node.attribute("ID").toInt()); data->setID(i, id_table); - } else { - throw ParsingFormatException("CT_Font类型数据中缺少必要的ID属性\n位于" + current_path.getRelativePath()); } - if (root_node.hasAttribute("FontName")) { + else + { + qDebug() << "CT_Font类型数据中缺少必要的ID属性\n位于" + << current_path.getRelativePath(); + } + + if (root_node.hasAttribute("FontName")) + { data->font_name = root_node.attribute("FontName"); - } else { - throw ParsingFormatException("CT_Font类型数据中缺少必要的FontName属性\n位于" + current_path.getRelativePath()); } - if (root_node.hasAttribute("FamilyName")) { + else + { + qDebug() << "CT_Font类型数据中缺少必要的FontName属性\n位于" + << current_path.getRelativePath(); + } + + if (root_node.hasAttribute("FamilyName")) + { data->family_name = root_node.attribute("FamilyName"); } - if (root_node.hasAttribute("Charset")) { + + if (root_node.hasAttribute("Charset")) + { data->charset = root_node.attribute("Charset"); } - if (root_node.hasAttribute("Italic")) { + + if (root_node.hasAttribute("Italic")) + { data->italic = root_node.attribute("Italic") == "true" ? true : false; } - if (root_node.hasAttribute("Bold")) { + + if (root_node.hasAttribute("Bold")) + { data->bold = root_node.attribute("Bold") == "true" ? true : false; - }if (root_node.hasAttribute("Serif")) { + } + + if (root_node.hasAttribute("Serif")) + { data->serif = root_node.attribute("Serif") == "true" ? true : false; } - if (root_node.hasAttribute("FixedWidth")) { + + if (root_node.hasAttribute("FixedWidth")) + { data->fixed_width = root_node.attribute("FixedWidth") == "true" ? true : false; } } -void OFDParser::readColorSpace(CT_ColorSpace * data, QDomElement & root_node) { - if (root_node.hasAttribute("ID")) { +void OFDParser::readColorSpace(CT_ColorSpace * data, QDomElement & root_node) +{ + if (root_node.hasAttribute("ID")) + { ST_ID i(root_node.attribute("ID").toInt()); data->setID(i, id_table); - } else { - throw ParsingFormatException("CT_ColorSpace类型数据中缺少必要的ID属性\n位于" + current_path.getRelativePath()); } - if (root_node.hasAttribute("Type")) { + else + { + qDebug() << "CT_ColorSpace类型数据中缺少必要的ID属性\n位于" + << current_path.getRelativePath(); + } + + if (root_node.hasAttribute("Type")) + { data->type = root_node.attribute("Type"); - } else { - throw ParsingFormatException("CT_ColorSpace类型数据中缺少必要的Type属性\n位于" + current_path.getRelativePath()); } - if (root_node.hasAttribute("BitsPerComponent")) { + else + { + qDebug() << "CT_ColorSpace类型数据中缺少必要的Type属性\n位于" + << current_path.getRelativePath(); + } + + if (root_node.hasAttribute("BitsPerComponent")) + { data->bits_per_component = root_node.attribute("BitsPerComponent").toInt(); } - if (root_node.hasAttribute("Profile")) { + + if (root_node.hasAttribute("Profile")) + { ST_Loc p("Profile", root_node.attribute("Profile"), current_path); data->profile = p; } //Some other stuff to be implemented } -void OFDParser::readDrawParam(CT_DrawParam * data, QDomElement & root_node) { - if (root_node.hasAttribute("ID")) { +void OFDParser::readDrawParam(CT_DrawParam * data, QDomElement & root_node) +{ + if (root_node.hasAttribute("ID")) + { ST_ID i(root_node.attribute("ID").toInt()); data->setID(i, id_table); - } else { - throw ParsingFormatException("CT_DrawParam类型数据中缺少必要的ID属性\n位于" + current_path.getRelativePath()); } - if (root_node.hasAttribute("Relative")) { + else + { + qDebug() << "CT_DrawParam类型数据中缺少必要的ID属性\n位于" + << current_path.getRelativePath(); + } + + if (root_node.hasAttribute("Relative")) + { ST_RefID i(root_node.attribute("Relative").toInt()); if (id_table->contains(i.getRefID())) data->relative = i; - else { - throw ParsingIDException("CT_DrawParam类型数据的Relative属性引用了未注册的ID 位于" + current_path.getRelativePath()); + else + { + qDebug() << "CT_DrawParam类型数据的Relative属性引用了未注册的ID 位于" + << current_path.getRelativePath(); } } - if (root_node.hasAttribute("LineWidth")) { + + if (root_node.hasAttribute("LineWidth")) + { data->line_width = root_node.attribute("LineWidth").toDouble(); } - if (root_node.hasAttribute("Join")) { + + if (root_node.hasAttribute("Join")) + { QString j = root_node.attribute("Join"); if (j == "Miter" || j == "Round" || j == "Bevel") data->join = j; - else { - throw ParsingFormatException("CT_DrawParam类型数据中的Join属性值为非法值\n位于" + current_path.getRelativePath()); + else + { + qDebug() << "CT_DrawParam类型数据中的Join属性值为非法值\n位于" + << current_path.getRelativePath(); } } - if (root_node.hasAttribute("Cap")) { + + if (root_node.hasAttribute("Cap")) + { QString c = root_node.attribute("Cap"); if (c == "Butt" || c == "Round" || c == "Square") data->cap = c; - else { - throw ParsingFormatException("CT_DrawParam类型数据中的Cap属性值为非法值\n位于" + current_path.getRelativePath()); + else + { + qDebug() << "CT_DrawParam类型数据中的Cap属性值为非法值\n位于" + << current_path.getRelativePath(); } } - if (root_node.hasAttribute("DashOffset")) { + + if (root_node.hasAttribute("DashOffset")) + { data->dash_offset = root_node.attribute("DashOffset").toDouble(); } - if (root_node.hasAttribute("DashPattern")) { + + if (root_node.hasAttribute("DashPattern")) + { ST_Array d("DashPattern", root_node.attribute("DashPattern")); data->dash_pattern = d; } - if (root_node.hasAttribute("MiterLimit")) { + + if (root_node.hasAttribute("MiterLimit")) + { if (data->getJoin() == "Miter") data->miter_limit = root_node.attribute("MiterLimit").toDouble(); } - if (!root_node.firstChildElement("ofd:FillColor").isNull()) { + + if (!root_node.firstChildElement("ofd:FillColor").isNull()) + { CT_Color * fill_color_data = new CT_Color(); delete data->fill_color; data->fill_color = fill_color_data; readColor(fill_color_data, root_node); data->fill_color_used = true; } - if (!root_node.firstChildElement("ofd:StrokeColor").isNull()) { + + if (!root_node.firstChildElement("ofd:StrokeColor").isNull()) + { CT_Color * stroke_color_data = new CT_Color(); delete data->stroke_color; data->stroke_color = stroke_color_data; diff --git a/ofdEditor/ofd/ofd_writer.cpp b/ofdEditor/ofd/ofd_writer.cpp index 39c683d5ce70d2f05610f9fdfe6f4814a0c5c1db..8f1bad1e3dca59152564c0dde1cb24c62a615372 100644 --- a/ofdEditor/ofd/ofd_writer.cpp +++ b/ofdEditor/ofd/ofd_writer.cpp @@ -13,74 +13,138 @@ #include "DataTypes/image/CT_Path.h" #include "DataTypes/image/CT_Image.h" -OFDWriter::OFDWriter(OFD * _data, QString _path) : data(_data), - current_path("OFD", _path + "OFD.xml") { - writeOFD(); +OFDWriter::OFDWriter(OFD * _data, QString _path) + : data(_data), current_path("OFD", _path + "OFD.xml") +{ +// writeOFD(); } -void OFDWriter::createFile() { +void OFDWriter::createFile() +{ current_file = new QFile(current_path.getPath()); -// qDebug() << current_path.getPath() << endl; - if (!current_file->open(QFile::WriteOnly | QFile::Text)) { - throw WritingFileException("无法打开或创建XML文件: " + current_path.getPath()); + qDebug() << current_path.getPath() << endl; + if(current_file->exists()) + { + QFile::remove(current_path.getPath()); // 删除文件夹 + qDebug() << "remove exists file"; + } + else + qDebug() <<"file not exists"; + if (!current_file->open(QFile::ReadWrite | QFile::Text)) + { + qDebug() << "can't open or write file"; } writer.setDevice(current_file); } -void OFDWriter::writeOFD() { +/// +/// \brief OFDWriter::makePath +/// Res文件夹创建的时候有bug,尝试通过创建文件来创建文件夹 +/// \param path +/// +void OFDWriter::makePath(QString path_str) +{ + // path_str.chop(n); + int index = path_str.lastIndexOf('/'); + path_str = path_str.left(index + 1); + + qDebug() << path_str; + if (!QDir().mkpath(path_str)) + { + qDebug() << "can't mkPath:"<getDocBodies()->size(); i++) { - DocBody * cur_docbody = data->getDocBodies()->at(i); + qDebug() << "DocBodys size: "<< data->getDocBodies()->size(); + for (int i = 0; i < data->getDocBodies()->size(); i++) + { + DocBody * cur_docbody = data->getDocBodies()->operator [](i); writer.writeStartElement("ofd:DocBody"); CT_DocInfo * cur_docinfo = cur_docbody->getDocInfo(); writer.writeStartElement("ofd:DocInfo"); + //写DocInfo - if (!cur_docinfo->getDocID().isNull()) { + // qDebug() << "Checkpoint 1.1"; + if (!cur_docinfo->getDocID().isNull()) + { writer.writeTextElement("ofd:DocID", cur_docinfo->getDocID()); - } else { - throw WritingFormatException("DocInfo类型数据缺少必要的成员DocID"); } - if (!cur_docinfo->getTitle().isNull()) { + else + { + qDebug("DocInfo类型数据缺少必要的成员DocID"); + } + + // qDebug() << "Checkpoint 1.2"; + if (!cur_docinfo->getTitle().isNull()) + { + // qDebug() << "Checkpoint 1.2.1"; + cur_docinfo->getTitle(); + // qDebug() << "Checkpoint 1.2.1.5"; writer.writeTextElement("ofd:Title", cur_docinfo->getTitle()); + // qDebug() << "Checkpoint 1.2.2"; } - if (!cur_docinfo->getAuthor().isNull()) { + // qDebug() << "Checkpoint 1.3"; + if (!cur_docinfo->getAuthor().isNull()) + { + // qDebug() << "Checkpoint 1.3.1"; writer.writeTextElement("ofd:Author", cur_docinfo->getAuthor()); + // qDebug() << "Checkpoint 1.3.2"; } - if (!cur_docinfo->getSubject().isNull()) { + // qDebug() << "Checkpoint 1.4"; + if (!cur_docinfo->getSubject().isNull()) + { writer.writeTextElement("ofd:Subject", cur_docinfo->getSubject()); } - if (!cur_docinfo->getAbstract().isNull()) { + // qDebug() << "Checkpoint 1.5"; + if (!cur_docinfo->getAbstract().isNull()) + { writer.writeTextElement("ofd:Abstract", cur_docinfo->getAbstract()); } - if (!cur_docinfo->getCreationDate().isNull()) { + if (!cur_docinfo->getCreationDate().isNull()) + { writer.writeTextElement("ofd:CreationDate", cur_docinfo->getCreationDate()); } - if (!cur_docinfo->getModDate().isNull()) { + if (!cur_docinfo->getModDate().isNull()) + { writer.writeTextElement("ofd:ModDate", cur_docinfo->getModDate()); } - if (!cur_docinfo->getDocUsage().isNull()) { + if (!cur_docinfo->getDocUsage().isNull()) + { writer.writeTextElement("ofd:DocUsage", cur_docinfo->getDocUsage()); } //Cover, keywords to be implmented - if (!cur_docinfo->getCreator().isNull()) { + if (!cur_docinfo->getCreator().isNull()) + { writer.writeTextElement("ofd:Creator", cur_docinfo->getCreator()); } - if (!cur_docinfo->getCreatorVersion().isNull()) { + if (!cur_docinfo->getCreatorVersion().isNull()) + { writer.writeTextElement("ofd:CreatorVersion", cur_docinfo->getCreatorVersion()); } + // qDebug() << "Checkpoint 1.6"; //写CustomDatas QVector * cur_custom_datas = cur_docinfo->getCustomDatas(); - if (cur_custom_datas->size() != 0) { + if (cur_custom_datas->size() != 0) + { writer.writeStartElement("ofd:CustomDatas"); - for (int i = 0; i < cur_custom_datas->size(); i++) { + for (int i = 0; i < cur_custom_datas->size(); i++) + { writer.writeStartElement("ofd:CustomData"); writer.writeAttribute("Name", cur_custom_datas->at(i).at(0)); writer.writeCharacters(cur_custom_datas->at(i).at(1)); @@ -90,28 +154,41 @@ void OFDWriter::writeOFD() { } writer.writeEndElement(); //写DocRoot - if (!cur_docbody->getDocRoot().isNull()) { + if (!cur_docbody->getDocRoot().isNull()) + { ST_Loc root("", data->getRootPath().getPath().remove("OFD.xml")); writer.writeTextElement("ofd:DocRoot", cur_docbody->getDocRoot().getRelativePath()); + qDebug() << "DocRoot :" << cur_docbody->getDocRoot(); } writer.writeEndElement(); } //正文结束 + // qDebug() << "Checkpoint 1.3"; writer.writeEndDocument(); current_file->close(); //修改current_file ST_Loc cur_path = current_path; - for (int i = 0; i < data->getDocBodies()->size(); i++) { + for (int i = 0; i < data->getDocBodies()->size(); i++) + { ST_Loc p("Document", - data->getDocBodies()->at(i)->getDocRoot().getRelativePath(), cur_path); + data->getDocBodies()->at(i)->getDocRoot().getRelativePath(), + cur_path); current_path = p; + // qDebug() << "Checkpoint 1.4"; + qDebug() << " current Path" + << current_path.getRelativePath(); makePath(current_path); - writeDocument(data->getDocuments()->at(i)); + // qDebug() << "Checkpoint 1.5"; + writeDocument(data->getDocuments()->operator [](i)); } + qDebug() << "Document write finished"; } -void OFDWriter::writeDocument(Document * data) { +void OFDWriter::writeDocument(Document * data) +{ + qDebug() << "writeDocument"; createFile(); + // qDebug() << "Checkpoint 2"; //qDebug() << "Checkpoint 1 reached."; writer.writeStartDocument(); writer.setAutoFormatting(true); @@ -119,37 +196,58 @@ void OFDWriter::writeDocument(Document * data) { writer.writeStartElement("ofd:Document"); writer.writeAttribute("xmlns:ofd", "http://www.ofdspec.org"); //写CommonData - if (data->getCommonData() != NULL) { + if (data->getCommonData() != NULL) + { writer.writeStartElement("ofd:CommonData"); CT_CommonData * cur_common_data = data->getCommonData(); - if (!cur_common_data->getMaxUnitID().isNull()) { + if (!cur_common_data->getMaxUnitID().isNull()) + { writer.writeTextElement("ofd:MaxUnitID", QString::number(cur_common_data->getMaxUnitID().getID())); - } else { - throw WritingFormatException("CT_CommonData类型数据缺少必要的成员MaxUnitID"); } - if (cur_common_data->getPageArea()) { + else + { + // qDebug("CT_CommonData类型数据缺少必要的成员MaxUnitID"); + qDebug() << "CT_CommonData类型数据缺少必要的成员MaxUnitID"; + } + if (cur_common_data->getPageArea()) + { writer.writeStartElement("ofd:PageArea"); writePageArea(cur_common_data->getPageArea()); writer.writeEndElement(); //ofd:PageArea - } else { - throw WritingFormatException("CT_CommonData类型数据缺少必要的成员PageArea"); + } + else + { + // qDebug("CT_CommonData类型数据缺少必要的成员PageArea"); + qDebug() << "CT_CommonData类型数据缺少必要的成员PageArea"; } - for (int i = 0; i < data->getCommonData()->getPublicRes()->size(); i++) { + for (int i = 0; i < data->getCommonData()->getPublicRes()->size(); i++) + { ST_Loc p = data->getCommonData()->getPublicRes()->at(i); writer.writeTextElement("ofd:PublicRes", p.getRelativePath()); } + + for(int i = 0; i < data->getCommonData()->document_res->size(); i++) + { + ST_Loc p = data->getCommonData()->document_res->operator [](i); + writer.writeTextElement("ofd:DocumentRes", p.getRelativePath()); + } //TemplatePage & DefaultCS to be implemented writer.writeEndElement(); //ofd:CommonData - } else { - throw WritingFormatException("Document类型数据缺少必要的成员CommonData"); + } + else + { + // qDebug("Document类型数据缺少必要的成员CommonData"); + qDebug() << "Document类型数据缺少必要的成员CommonData"; } //写Pages - if (data->getPages()) { + if (data->getPages()) + { CT_Pages * cur_pages = data->getPages(); writer.writeStartElement("ofd:Pages"); - for (int i = 0; i < cur_pages->getPages()->size(); i++) { + for (int i = 0; i < cur_pages->getPages()->size(); i++) + { Page * cur_page = cur_pages->getPages()->at(i); writer.writeStartElement("ofd:Page"); writeBase(cur_page); @@ -157,36 +255,73 @@ void OFDWriter::writeDocument(Document * data) { writer.writeEndElement(); } writer.writeEndElement(); //ofd:Pages - } else { - throw WritingFormatException("Document类型数据缺少必要的成员Pages"); + } + else + { + // qDebug("Document类型数据缺少必要的成员Pages"); + qDebug() << "Document类型数据缺少必要的成员Pages"; } //写CustomTags - if (!data->getCustomTags().isNull()) { + if (!data->getCustomTags().isNull()) + { writer.writeTextElement("ofd:CustomTags", data->getCustomTags().getRelativePath()); } + + // qDebug() << "Document main part finished"; + //Outlines, extensions, annotations to be implemented //正文结束 writer.writeEndDocument(); current_file->close(); + ST_Loc cur_path = current_path; - for (int i = 0; i < data->getPages()->getPages()->size(); i++) { - ST_Loc p("Page", data->getPages()->getPages()->at(i)-> - getBaseLoc().getRelativePath(), cur_path); + for (int i = 0; i < data->getPages()->getPages()->size(); i++) + { + ST_Loc p("Page", data->getPages()->getPages()->operator [](i)-> + getBaseLoc().getRelativePath(), cur_path); + // qDebug() << "Page" << i << " : " + // << data->getPages()->getPages()->operator [](i)->getBaseLoc().getRelativePath(); current_path = p; makePath(current_path); - writePage(data->getPages()->getPages()->at(i)); + writePage(data->getPages()->getPages()->operator [](i)); + } + // qDebug() << "write pages finished"; + qDebug() << "PublicRes size = " << data->getPublicRes()->size(); + for (int i = 0; i < data->getPublicRes()->size(); i++) + { + ST_Loc p("PublicRes", + (data->getCommonData()->getPublicRes()->operator [](i)).getRelativePath(), + cur_path); + qDebug() << "publicRes loc: " << p.getRelativePath(); + current_path = p; + makePath(current_path); + qDebug() << "current path = " << current_path; + writeRes(data->getPublicRes()->operator [](i)); + qDebug() << "current res baseloc = " << (data->getPublicRes()->operator [](i))->getBaseLoc(); } - for (int i = 0; i < data->getPublicRes()->size(); i++) { - ST_Loc p("PublicRes", data->getPublicRes()->at(i)->getBaseLoc().getRelativePath(), cur_path); + // qDebug() << "write publicRes finished"; + + qDebug() << "DocumentRes size " <document_res->size(); + for (int i = 0; i < data->document_res->size(); i++) + { + ST_Loc p("DocumentRes", + (data->getCommonData()->document_res->operator [](i)).getRelativePath(), + cur_path); + qDebug() << "DocumentRes loc: " << p.getRelativePath(); current_path = p; makePath(current_path); - writeRes(data->getPublicRes()->at(i)); + qDebug() << "current path = " << current_path; + writeRes(data->document_res->operator [](i)); + qDebug() << "current res baseloc = " << (data->document_res->operator [](i))->getBaseLoc(); } + //write CustomTags to be implemented } -void OFDWriter::writePage(Page * data) { +void OFDWriter::writePage(Page * data) +{ createFile(); + // qDebug() << "Checkpoint 3"; writer.writeStartDocument(); writer.setAutoFormatting(true); //进入正文 @@ -194,38 +329,48 @@ void OFDWriter::writePage(Page * data) { writer.writeAttribute("xmlns:ofd", "http://www.ofdspec.org"); //Template to be implemented //写Area - if (data->getArea()) { + if (data->getArea()) + { writer.writeStartElement("ofd:Area"); writePageArea(data->getArea()); writer.writeEndElement(); //ofd:Area } -// qDebug() << "Checkpoint 1 reached."; + // qDebug() << "Checkpoint 1 reached."; //写PageRes - for (int i = 0; i < data->getPageResLocations()->size(); i++) { + for (int i = 0; i < data->getPageResLocations()->size(); i++) + { ST_Loc p = data->getPageResLocations()->at(i); writer.writeTextElement("ofd:PageRes", p.getRelativePath()); } -// qDebug() << "Checkpoint 2 reached."; + // qDebug() << "Checkpoint 2 reached."; //写Content - if (data->getContent()->size()) { + if (data->getContent()->size()) + { writer.writeStartElement("ofd:Content"); - for (int i = 0; i < data->getContent()->size(); i++) { -// qDebug() << data->getContent()->size(); - CT_Layer * cur_layer = data->getContent()->at(i); - writer.writeStartElement("ofd:Layer"); - writeBase(cur_layer); -// qDebug() << "Checkpoint 2.1 reached."; - QXmlStreamAttributes a = getAttributes(cur_layer); - writer.writeAttributes(a); -// qDebug() << "Checkpoint 2.2 reached."; -// qDebug() << "???"; - //写文档页面的内容(QGraphicUnits的子类集合) - writePageBlock(cur_layer, true); + for (int i = 0; i < data->getContent()->size(); i++) + { + // qDebug() << data->getContent()->size(); + CT_Layer * cur_layer = data->getContent()->operator [](i); + if (cur_layer->getImageObject()->size() + cur_layer->getPathObject()->size() + +cur_layer->getTextObject()->size() + cur_layer->getPageBlock()->size() + > 0) + { + writer.writeStartElement("ofd:Layer"); + writeBase(cur_layer); + // qDebug() << "Checkpoint 2.1 reached."; + QXmlStreamAttributes a = getAttributes(cur_layer); + writer.writeAttributes(a); + // qDebug() << "Checkpoint 2.2 reached."; + // qDebug() << "???"; + //写文档页面的内容(QGraphicUnits的子类集合) + writePageBlock(cur_layer, true); + writer.writeEndElement(); + } } writer.writeEndElement(); //ofd:Content - //qDebug() << "????"; + // qDebug() << "????"; } -// qDebug() << "Checkpoint 3 reached."; + // qDebug() << "Checkpoint 3 reached."; //Actions to be implemented writer.writeEndElement(); //ofd:Page //正文结束 @@ -233,58 +378,116 @@ void OFDWriter::writePage(Page * data) { current_file->close(); } -void OFDWriter::writeRes(Res * data) { +void OFDWriter::writeRes(Res * data) +{ createFile(); writer.writeStartDocument(); writer.setAutoFormatting(true); //进入正文 writer.writeStartElement("ofd:Res"); writer.writeAttribute("xmlns:ofd", "http://www.ofdspec.org"); + QString resFloderPath; + //写属性 - if (!data->getBaseLoc().isNull()) { + if (!data->getBaseLoc().isNull()) + { writer.writeAttribute("BaseLoc", data->getBaseLoc().getRelativePath()); - } else { - throw WritingFormatException("Res类型数据缺少必要的属性BaseLoc"); + + resFloderPath = current_path.getPath().left(current_path.getPath().lastIndexOf('/') + 1) + + data->getBaseLoc().getPath() + "/"; // 获得绝对路径 + qDebug() << "Res "<< resFloderPath; + + if(!QDir(resFloderPath).exists()) + { + this->makePath(resFloderPath); + } + } + else + { + qDebug() << "class Res lack the required attribute baseloc"; + // qDebug("Res类型数据缺少必要的属性BaseLoc"); } //写成员 - if (data->getColorSpaces()->size()) { + // colorSpaces + if (data->getColorSpaces()->size()) + { + qDebug() << "Res Save colorspaces"; writer.writeStartElement("ofd:ColorSpaces"); - for (int i = 0; i < data->getColorSpaces()->size(); i++) { - CT_ColorSpace * cur_colorspace = data->getColorSpaces()->at(i); + for (int i = 0; i < data->getColorSpaces()->size(); i++) + { + CT_ColorSpace * cur_colorspace = data->getColorSpaces()->operator [](i); writer.writeStartElement("ofd:ColorSpace"); writeColorSpace(cur_colorspace); writer.writeEndElement(); //ofd:ColorSpace } writer.writeEndElement(); //ofd:ColorSpaces } - if (data->getDrawParams()->size()) { + + // drawParams + if (data->getDrawParams()->size()) + { + qDebug() << "Res save drawparams"; writer.writeStartElement("ofd:DrawParams"); - for (int i = 0; i < data->getDrawParams()->size(); i++) { - CT_DrawParam * cur_draw_param = data->getDrawParams()->at(i); + for (int i = 0; i < data->getDrawParams()->size(); i++) + { + CT_DrawParam * cur_draw_param = data->getDrawParams()->operator [](i); writer.writeStartElement("ofd:DrawParam"); writeDrawParam(cur_draw_param); writer.writeEndElement(); //ofd:DrawParam } writer.writeEndElement(); //ofd:DrawParams } - if (data->getFonts()->size()) { + + // font + if (data->getFonts()->size()) + { + qDebug() << "Res Save fonts"; writer.writeStartElement("ofd:Fonts"); - for (int i = 0; i < data->getFonts()->size(); i++) { - CT_Font * cur_font = data->getFonts()->at(i); + for (int i = 0; i < data->getFonts()->size(); i++) + { + CT_Font * cur_font = data->getFonts()->operator [](i); writer.writeStartElement("ofd:Font"); writeFont(cur_font); writer.writeEndElement(); //ofd:Font } writer.writeEndElement(); //ofd:Fonts } + //MultiMedias & CompositeGraphicUnits to be implemented + if (data->getMultiMedia()->size()) + { + qDebug() << "Res Save multimedia"; + writer.writeStartElement("ofd:MultiMedias"); + for(int i = 0; i < data->getMultiMedia()->size(); i++) + { + CT_MultiMedia* multMedia = data->getMultiMedia()->operator [](i); + writer.writeStartElement("ofd:MultiMedia"); + writeMultiMedia(multMedia); + writer.writeStartElement("ofd:MediaFile"); + writer.writeCharacters(multMedia->MediaFile); + writer.writeEndElement(); // mediafile + + writer.writeEndElement(); // ofd:MultiMedia + qDebug() << this->tempPath + "/" + multMedia->MediaFile; + qDebug() << current_path.getPath().left(current_path.getPath().lastIndexOf('/') + 1) + + data->getBaseLoc().getRelativePath() + "/" + multMedia->MediaFile; + + // 将图片拷贝过去 + qDebug() << QFile::copy(this->tempPath + "/" + multMedia->MediaFile, + resFloderPath + "/" + multMedia->MediaFile); + } + writer.writeEndElement(); // ofd:MultiMedias + + } + writer.writeEndElement(); //ofd:Res //正文结束 writer.writeEndDocument(); current_file->close(); } -void OFDWriter::writePageArea(CT_PageArea * cur_page_area) { +void OFDWriter::writePageArea(CT_PageArea * cur_page_area) +{ if (!cur_page_area->getPhysicalBox().isNull()) { ST_Box b = cur_page_area->getPhysicalBox(); writer.writeTextElement("ofd:PhysicalBox", @@ -292,10 +495,13 @@ void OFDWriter::writePageArea(CT_PageArea * cur_page_area) { QString::number(b.getY()) + " " + QString::number(b.getDeltaX())+ " " + QString::number(b.getDeltaY())); - } else { - throw WritingFormatException("CT_PageArea类型数据缺少必要的成员PhysicalBox"); } - if (!cur_page_area->getApplicationBox().isNull()) { + else + { + qDebug("CT_PageArea类型数据缺少必要的成员PhysicalBox"); + } + if (!cur_page_area->getApplicationBox().isNull()) + { ST_Box b = cur_page_area->getApplicationBox(); writer.writeTextElement("ofd:ApplicationBox", QString::number(b.getX()) + " " + @@ -303,7 +509,8 @@ void OFDWriter::writePageArea(CT_PageArea * cur_page_area) { QString::number(b.getDeltaX())+ " " + QString::number(b.getDeltaY())); } - if (!cur_page_area->getContentBox().isNull()) { + if (!cur_page_area->getContentBox().isNull()) + { ST_Box b = cur_page_area->getContentBox(); writer.writeTextElement("ofd:ContentBox", QString::number(b.getX()) + " " + @@ -311,7 +518,8 @@ void OFDWriter::writePageArea(CT_PageArea * cur_page_area) { QString::number(b.getDeltaX())+ " " + QString::number(b.getDeltaY())); } - if (!cur_page_area->getBleedBox().isNull()) { + if (!cur_page_area->getBleedBox().isNull()) + { ST_Box b = cur_page_area->getBleedBox(); writer.writeTextElement("ofd:BleedBox", QString::number(b.getX()) + " " + @@ -321,204 +529,276 @@ void OFDWriter::writePageArea(CT_PageArea * cur_page_area) { } } -void OFDWriter::writePageBlock(CT_PageBlock * cur_page_block, bool is_layer) { - writeBase(cur_page_block); +void OFDWriter::writePageBlock(CT_PageBlock * cur_page_block, bool is_layer) +{ + if (!is_layer) + writeBase(cur_page_block); //文字内容 -// qDebug() << "TextObject: " << cur_page_block->getTextObject()->size(); - for (int i = 0; i < cur_page_block->getTextObject()->size(); i++) { - CT_Text * cur_text = cur_page_block->getTextObject()->at(i); + // qDebug() << "TextObject: " << cur_page_block->getTextObject()->size(); + for (int i = 0; i < cur_page_block->getTextObject()->size(); i++) + { + CT_Text * cur_text = cur_page_block->getTextObject()->operator [](i); writer.writeStartElement("ofd:TextObject"); + // qDebug() << "About to write Text Object."; writeTextObject(cur_text); writer.writeEndElement(); //ofd:TextObject } //矢量图内容 -// qDebug() << "PathObject: " << cur_page_block->getPathObject()->size(); - for (int i = 0; i < cur_page_block->getPathObject()->size(); i++) { - CT_Path * cur_path = cur_page_block->getPathObject()->at(i); + // qDebug() << "PathObject: " << cur_page_block->getPathObject()->size(); + for (int i = 0; i < cur_page_block->getPathObject()->size(); i++) + { + CT_Path * cur_path = cur_page_block->getPathObject()->operator [](i); writer.writeStartElement("ofd:PathObject"); writePathObject(cur_path); writer.writeEndElement(); //ofd:PathObject } //位图内容 -// qDebug() << "ImageObject: " << cur_page_block->getImageObject()->size(); - for (int i = 0; i < cur_page_block->getImageObject()->size(); i++) { - CT_Image * cur_image = cur_page_block->getImageObject()->at(i); + // qDebug() << "ImageObject: " << cur_page_block->getImageObject()->size(); + for (int i = 0; i < cur_page_block->getImageObject()->size(); i++) + { + CT_Image * cur_image = cur_page_block->getImageObject()->operator [](i); writer.writeStartElement("ofd:ImageObject"); writeImageObject(cur_image); writer.writeEndElement(); //ofd:ImageObject } //PageBlock嵌套 -// qDebug() << "PageBlock: " << cur_page_block->getPageBlock()->size(); - for (int i = 0; i < cur_page_block->getPageBlock()->size(); i++) { - CT_PageBlock * cur_inner_page_block = cur_page_block->getPageBlock()->at(i); + // qDebug() << "PageBlock: " << cur_page_block->getPageBlock()->size(); + for (int i = 0; i < cur_page_block->getPageBlock()->size(); i++) + { + CT_PageBlock * cur_inner_page_block = cur_page_block->getPageBlock()->operator [](i); writer.writeStartElement("ofd:PageBlock"); writePageBlock(cur_inner_page_block); writer.writeEndElement(); } } -void OFDWriter::writeTextObject(CT_Text * cur_text) { +void OFDWriter::writeTextObject(CT_Text * cur_text) +{ writeGraphicUnitAttributes(cur_text); -// qDebug() << "Checkpoint 4 reached."; + // qDebug() << "!!!!"; QXmlStreamAttributes a = getAttributes(cur_text); + // qDebug() << "!!!!????"; + // qDebug() << "cur_text->attributes is empty: " << a.isEmpty(); + // for (int i = 0; i < a.size(); i++) + // qDebug() << a.at(i).name() << " " << a.at(i).value(); writer.writeAttributes(a); -// qDebug() << "Checkpoint 5 reached."; + // qDebug() << "Checkpoint 5 reached."; writeGraphicUnitMemebers(cur_text); + // qDebug() << "Checkpoint 6 reached."; //CGTransform to be implemented - if (cur_text->getTextCode()) { + if (cur_text->getTextCode()) + { QVector * cur_textcode = cur_text->getTextCode(); - for (int i = 0; i < cur_textcode->size(); i++) { + for (int i = 0; i < cur_textcode->size(); i++) + { writer.writeStartElement("ofd:TextCode"); QXmlStreamAttributes a = getAttributes(cur_textcode->at(i)); writer.writeAttributes(a); writer.writeCharacters(cur_textcode->at(i)->getText()); writer.writeEndElement(); //ofd:TextCode } - } else { - throw WritingFormatException("CT_Text类型数据缺少必要的成员TextObject"); + // qDebug() << "Checkpoint 7 reached."; + } + else + { + qDebug("CT_Text类型数据缺少必要的成员TextObject"); } } -void OFDWriter::writePathObject(CT_Path * cur_path) { +void OFDWriter::writePathObject(CT_Path * cur_path) +{ writeGraphicUnitAttributes(cur_path); QXmlStreamAttributes a = getAttributes(cur_path); writer.writeAttributes(a); writeGraphicUnitMemebers(cur_path); -// qDebug() << "???"; - if (!cur_path->getAbbreviatedData().isNull()) { + // qDebug() << "???"; + if (!cur_path->getAbbreviatedData().isNull()) + { writer.writeTextElement("ofd:AbbreviatedData", cur_path->getAbbreviatedData()); -// qDebug() << "????"; - } else { - throw WritingFormatException("CT_Path类型数据缺少必要的成员AbbreviatedData"); + // qDebug() << "????"; + } + else + { + qDebug("CT_Path类型数据缺少必要的成员AbbreviatedData"); } } -void OFDWriter::writeImageObject(CT_Image * cur_image) { +void OFDWriter::writeImageObject(CT_Image * cur_image) +{ writeGraphicUnitAttributes(cur_image); QXmlStreamAttributes a = getAttributes(cur_image); writer.writeAttributes(a); writeGraphicUnitMemebers(cur_image); } -void OFDWriter::writeGraphicUnitAttributes(CT_GraphicUnit * cur_graphic_unit) { +void OFDWriter::writeGraphicUnitAttributes(CT_GraphicUnit * cur_graphic_unit) +{ writeBase(cur_graphic_unit); QXmlStreamAttributes a = getAttributes(cur_graphic_unit); writer.writeAttributes(a); } -void OFDWriter::writeGraphicUnitMemebers(CT_GraphicUnit * cur_graphic_unit) { - if (cur_graphic_unit->getFillColor()) { +void OFDWriter::writeGraphicUnitMemebers(CT_GraphicUnit * cur_graphic_unit) +{ + // qDebug() << "Checkpoint 10 reached."; + // qDebug() << cur_graphic_unit->getID(); + // qDebug() << "Checkpoint 10.1 reached."; + if (cur_graphic_unit->getFillColor()) + { writer.writeStartElement("ofd:FillColor"); writeColor(cur_graphic_unit->getFillColor()); writer.writeEndElement(); //ofd:FillColor } - //qDebug() << "Checkpoint 5 reached."; - if (cur_graphic_unit->getStrokeColor()) { + // qDebug() << "Checkpoint 11 reached."; + if (cur_graphic_unit->getStrokeColor()) + { + qDebug() << "Checkpoint 11.1 reached."; writer.writeStartElement("ofd:StrokeColor"); writeColor(cur_graphic_unit->getStrokeColor()); + qDebug() << "Checkpoint 11.2 reached."; writer.writeEndElement(); //ofd:StrokeColor } + // qDebug() << "Checkpoint 12 reached."; } -void OFDWriter::writeColor(CT_Color * cur_color) { +void OFDWriter::writeColor(CT_Color * cur_color) +{ + + // qDebug() << "Checkpoint 20 reached."; + // qDebug() << "cur_color = " << cur_color; QXmlStreamAttributes a = getAttributes(cur_color); writer.writeAttributes(a); //Pattern and AxialShd / RadialShd to be implemented } -void OFDWriter::writeBase(CT_Base * cur_base) { +void OFDWriter::writeBase(CT_Base * cur_base) +{ //qDebug() << "Base???"; - if (!cur_base->getID().isNull()) { + if (!cur_base->getID().isNull()) + { writer.writeAttribute("ID", QString::number(cur_base->getID().getID())); - } else { - throw WritingFormatException("CT_Base类型数据缺少必要的属性ID"); + } + else + { + qDebug("CT_Base类型数据缺少必要的属性ID"); } } -void OFDWriter::writeColorSpace(CT_ColorSpace * cur_colorspace) { +void OFDWriter::writeColorSpace(CT_ColorSpace * cur_colorspace) +{ writeBase(cur_colorspace); QXmlStreamAttributes a = getAttributes(cur_colorspace); writer.writeAttributes(a); //Palette to be implemented } -void OFDWriter::writeDrawParam(CT_DrawParam * cur_draw_param) { +void OFDWriter::writeDrawParam(CT_DrawParam * cur_draw_param) +{ writeBase(cur_draw_param); QXmlStreamAttributes a = getAttributes(cur_draw_param); writer.writeAttributes(a); - if (cur_draw_param->fillColorUsed()) { + if (cur_draw_param->fillColorUsed()) + { writer.writeStartElement("ofd:FillColor"); writeColor(cur_draw_param->getFillColor()); writer.writeEndElement(); //ofd:FillColor } - if (cur_draw_param->strokeColorUsed()) { + if (cur_draw_param->strokeColorUsed()) + { writer.writeStartElement("ofd:StrokeColor"); writeColor(cur_draw_param->getStrokeColor()); writer.writeEndElement(); //ofd:StrokeColor } } -void OFDWriter::writeFont(CT_Font * cur_font) { +void OFDWriter::writeFont(CT_Font * cur_font) +{ + writeBase(cur_font); QXmlStreamAttributes a = getAttributes(cur_font); writer.writeAttributes(a); //FontFile to be implemented } -QXmlStreamAttributes getAttributes(OFD * data) { +void OFDWriter::writeMultiMedia(CT_MultiMedia *cur_multiMedia) +{ + writeBase(cur_multiMedia); + QXmlStreamAttributes a = getAttributes(cur_multiMedia); + writer.writeAttributes(a); +// qDebug() << "writemultimedia finished"; +} + +QXmlStreamAttributes getAttributes(OFD * data) +{ QXmlStreamAttributes a; - if (!data->getDocType().isNull()) { + if (!data->getDocType().isNull()) + { a.append("DocType", data->getDocType()); - } else { - throw WritingFormatException("OFD类型数据缺少必要的属性DocType"); } - if (!data->getOfdVersion().isNull()) { + else + { + qDebug("OFD类型数据缺少必要的属性DocType"); + } + if (!data->getOfdVersion().isNull()) + { a.append("Version", data->getOfdVersion()); - } else { - throw WritingFormatException("OFD类型数据缺少必要的属性Version"); + } + else + { + qDebug("OFD类型数据缺少必要的属性Version"); } return a; } -QXmlStreamAttributes getAttributes(CT_Layer * cur_layer) { +QXmlStreamAttributes getAttributes(CT_Layer * cur_layer) +{ QXmlStreamAttributes a; - if (cur_layer->getType() != "Body") - a.append("Type", cur_layer->getType()); - if (!cur_layer->getDrawParam().isNull()) { + // if (cur_layer->getType() != "Body") + a.append("Type", cur_layer->getType()); + if (!cur_layer->getDrawParam().isNull()) + { a.append("DrawParam",QString::number(cur_layer->getDrawParam().getRefID())); } return a; } -QXmlStreamAttributes getAttributes(CT_GraphicUnit * cur_graphic_unit) { +QXmlStreamAttributes getAttributes(CT_GraphicUnit * cur_graphic_unit) +{ QXmlStreamAttributes a; - - if (!cur_graphic_unit->getBoundary().isNull()) { + // qDebug() << "Boundary is null: " << cur_graphic_unit->getBoundary().isNull(); + if (!cur_graphic_unit->getBoundary().isNull()) + { ST_Box b = cur_graphic_unit->getBoundary(); a.append("Boundary", QString::number(b.getX()) + " " + QString::number(b.getY()) + " " + QString::number(b.getDeltaX()) + " " + QString::number(b.getDeltaY())); - } else { - throw WritingFormatException("CT_GraphicUnit类型数据缺少必要的属性Boundary"); } - - if (!cur_graphic_unit->getName().isNull()) { + else + { + qDebug("CT_GraphicUnit类型数据缺少必要的属性Boundary"); + } + // qDebug() << "CT_Graphic Unit Name: " << cur_graphic_unit->getName(); + // qDebug() << "CT_Graphic Unit Name is Null: " << cur_graphic_unit->getName().isNull(); + if (cur_graphic_unit->getName().length() != 0) + { a.append("Name", cur_graphic_unit->getName()); } //当Visible为false时才写出 - if (!cur_graphic_unit->getVisible()) { + if (!cur_graphic_unit->getVisible()) + { a.append("Visible", "false"); } //CTM to be implemented - if (!cur_graphic_unit->getDrawParam().isNull()) { + if (!cur_graphic_unit->getDrawParam().isNull()) + { a.append("DrawParam", QString::number(cur_graphic_unit->getDrawParam())); } @@ -527,186 +807,289 @@ QXmlStreamAttributes getAttributes(CT_GraphicUnit * cur_graphic_unit) { } -QXmlStreamAttributes getAttributes(CT_Color *cur_color) { +QXmlStreamAttributes getAttributes(CT_Color *cur_color) +{ QXmlStreamAttributes a; - - if (!cur_color->getValue().isNull()) { + // qDebug() << "Checkpoint 30 reached."; + if (!cur_color->getValue().isNull()) + { + // qDebug() << "Checkpoint 30.1 reached."; a.append("Value", cur_color->getValue().getAllContent()); } - if (cur_color->indexUsed()) { + // qDebug() << "Checkpoint 31 reached."; + if (cur_color->indexUsed()) + { a.append("Index", QString::number(cur_color->getIndex())); } - if (!cur_color->getColorSpace().isNull()) { + // qDebug() << "Checkpoint 32 reached."; + if (!cur_color->getColorSpace().isNull()) + { a.append("ColorSpace", QString::number(cur_color->getColorSpace().getRefID())); } //只有当Alpha值为非默认的255时才显示 - if (cur_color->getAlpha() != 255) { + // qDebug() << "Checkpoint 33 reached."; + if (cur_color->getAlpha() != 255) + { a.append("Alpha", QString::number(cur_color->getAlpha())); } return a; } -QXmlStreamAttributes getAttributes(CT_Text * cur_text) { +QXmlStreamAttributes getAttributes(CT_Text * cur_text) +{ + // qDebug() << "??"; QXmlStreamAttributes a; + // qDebug() << "???"; + // qDebug() << "cur_text->getFont().isNull(): " + // <getFont().isNull(); - if (!cur_text->getFont().isNull()) { + if (!cur_text->getFont().isNull()) + { a.append("Font", QString::number(cur_text->getFont().getRefID())); - } else { - throw WritingFormatException("CT_Text类型数据缺少必要的属性Font"); - } - - if (cur_text->sizeUsed()) { - a.append("Size", QString::number(cur_text->getSize())); - } else { - throw WritingFormatException("CT_Text类型数据缺少必要的属性Size"); } + else + { + qDebug("CT_Text类型数据缺少必要的属性Font"); + } + // qDebug() << "cur_text size used: " << cur_text->sizeUsed(); + // qDebug() << "cur_text size: " << cur_text->getSize(); + // if (cur_text->sizeUsed()) { + a.append("Size", QString::number(cur_text->getSize())); + // } else { + // qDebug() << "CT_Text类型数据缺少必要的属性Size"; + // } //Stroke属性不为默认值false时才显示 - if (cur_text->getStroke()) { + if (cur_text->getStroke()) + { a.append("Stroke", "true"); } //Fill属性不为默认值true时才显示 - if (!cur_text->getFill()) { + if (!cur_text->getFill()) + { a.append("Fill", "false"); } //HScale属性不为默认值1.0时才显示 - if (abs(cur_text->getHScale() - 1.0) > 0.00000001) { + if (abs(cur_text->getHScale() - 1.0) > 0.00000001) + { a.append("HScale", QString::number(cur_text->getHScale())); } - if (cur_text->getReadDirection() != 0) { + if (cur_text->getReadDirection() != 0) + { a.append("ReadDirection", QString::number(cur_text->getReadDirection())); } - if (cur_text->getWeight() != 400) { - a.append("ReadDirection", QString::number(cur_text->getWeight())); + qDebug() << "weight ------" << cur_text->getWeight(); + if (cur_text->getWeight() != 400) + { + a.append("Weight", QString::number(cur_text->getWeight())); } - if (cur_text->getItalic()) { + if (cur_text->getItalic()) + { a.append("Italic", "true"); } return a; } -QXmlStreamAttributes getAttributes(TextCode * cur_textcode) { +QXmlStreamAttributes getAttributes(TextCode * cur_textcode) +{ QXmlStreamAttributes a; a.append("X", QString::number(cur_textcode->getX())); a.append("Y", QString::number(cur_textcode->getY())); - if (!cur_textcode->getDeltaX().isNull()) { + if (!cur_textcode->getDeltaX().isNull()) + { a.append("DeltaX", cur_textcode->getDeltaX().getAllContent()); } - if (!cur_textcode->getDeltaY().isNull()) { + if (!cur_textcode->getDeltaY().isNull()) + { a.append("DeltaY", cur_textcode->getDeltaY().getAllContent()); } return a; } -QXmlStreamAttributes getAttributes(CT_Path * cur_path) { +QXmlStreamAttributes getAttributes(CT_Path * cur_path) +{ QXmlStreamAttributes a; //Stroke属性为非默认值false时才显示。下同 - if (!cur_path->getStroke()) { + if (!cur_path->getStroke()) + { a.append("Stroke", "false"); } - if (cur_path->getFill()) { + if (cur_path->getFill()) + { a.append("Fill", "true"); } - if (cur_path->getRule() != "NonZero") { + if (cur_path->getRule() != "NonZero") + { a.append("Rule", cur_path->getRule()); } return a; } -QXmlStreamAttributes getAttributes(CT_Image * cur_image) { +QXmlStreamAttributes getAttributes(CT_Image * cur_image) +{ + QXmlStreamAttributes a; - if (!cur_image->getResourceID().isNull()) { + if (!cur_image->getResourceID().isNull()) + { a.append("ResourceID", QString::number(cur_image->getResourceID().getRefID())); - } else { - throw WritingFormatException("CT_Image类型数据缺少必要的属性ResourceID"); } - if (!cur_image->getSubstitution().isNull()) { + else + { + qDebug("CT_Image类型数据缺少必要的属性ResourceID"); + } + + if (!cur_image->getSubstitution().isNull()) + { a.append("Substitution", QString::number(cur_image->getSubstitution().getRefID())); } + + // 图片对象似乎需要插入CTM + double width = cur_image->boundary.getDeltaX(); + double height = cur_image->boundary.getDeltaY(); + + a.append( + "CTM", + QString::number(width) + " 0 0 " + +QString::number(height) + " 0 0"); + + return a; } -QXmlStreamAttributes getAttributes(CT_ColorSpace * cur_colorspace) { +QXmlStreamAttributes getAttributes(CT_ColorSpace * cur_colorspace) +{ QXmlStreamAttributes a; - if (!cur_colorspace->getType().isNull()) { + if (!cur_colorspace->getType().isNull()) + { a.append("Type", cur_colorspace->getType()); - } else { - throw WritingFormatException("CT_ColorSpace类型数据缺少必要的属性Type"); } - if (cur_colorspace->getBitsPerComponent() != 8) { + else + { + qDebug("CT_ColorSpace类型数据缺少必要的属性Type"); + } + if (cur_colorspace->getBitsPerComponent() != 8) + { a.append("BitsPerComponent", QString::number(cur_colorspace->getBitsPerComponent())); } - if (!cur_colorspace->getProfile().isNull()) { + // qDebug() << "Colorspace Profile: " << cur_colorspace->getProfile(); + // qDebug() << "Colorspace Profile abs_path: " << cur_colorspace->getProfile().getPath(); + // qDebug() << "Colorspace Profile is NUll: " << cur_colorspace->getProfile().isNull(); + if (!cur_colorspace->getProfile().isNull()) + { ST_Loc p = cur_colorspace->getProfile(); a.append("Profile", p.getRelativePath()); } return a; } -QXmlStreamAttributes getAttributes(CT_DrawParam * cur_draw_param) { +QXmlStreamAttributes getAttributes(CT_DrawParam * cur_draw_param) +{ QXmlStreamAttributes a; - if (!cur_draw_param->getRelative().isNull()) { + if (!cur_draw_param->getRelative().isNull()) + { ST_RefID p = cur_draw_param->getRelative(); a.append("Relative", QString::number(p.getRefID())); } - if (abs(cur_draw_param->getLineWidth() - 0.353) > 0.0000001) { + if (abs(cur_draw_param->getLineWidth() - 0.353) > 0.0000001) + { a.append("LineWidth", QString::number(cur_draw_param->getLineWidth())); } - if (cur_draw_param->getJoin() != "Miter") { + if (cur_draw_param->getJoin() != "Miter") + { a.append("Join", cur_draw_param->getJoin()); } - if (cur_draw_param->getCap() != "Butt") { + if (cur_draw_param->getCap() != "Butt") + { a.append("Cap", cur_draw_param->getCap()); } - if (abs(cur_draw_param->getDashOffset() - 0.0) > 0.0000001) { + if (abs(cur_draw_param->getDashOffset() - 0.0) > 0.0000001) + { a.append("DashOffset", QString::number(cur_draw_param->getDashOffset())); } - if (!cur_draw_param->getDashPattern().isNull()) { + if (!cur_draw_param->getDashPattern().isNull()) + { a.append("DashPattern", cur_draw_param->getDashPattern().getAllContent()); } - if (abs(cur_draw_param->getMiterLimit() - 3.528) > 0.0000001) { + if (abs(cur_draw_param->getMiterLimit() - 3.528) > 0.0000001) + { a.append("MiterLimit", QString::number(cur_draw_param->getMiterLimit())); } return a; } -QXmlStreamAttributes getAttributes(CT_Font * cur_font) { +QXmlStreamAttributes getAttributes(CT_Font * cur_font) +{ QXmlStreamAttributes a; - if (!cur_font->getFontName().isNull()) { + if (cur_font->getFontName().length() != 0) + { a.append("FontName", cur_font->getFontName()); - } else { - throw WritingFormatException("CT_Font类型数据缺少必要的属性FontName"); } - if (!cur_font->getFamilyName().isNull()) { + else + { + qDebug("CT_Font类型数据缺少必要的属性FontName"); + } + if (cur_font->getFamilyName().length() != 0) + { a.append("FamilyName", cur_font->getFamilyName()); } - if (cur_font->getCharset() != "GB18030") { + if (cur_font->getCharset() != "GB18030") + { a.append("Charset", cur_font->getCharset()); } - if (cur_font->getItalic()) { + if (cur_font->getItalic()) + { a.append("Italic", "true"); } - if (cur_font->getBold()) { + if (cur_font->getBold()) + { a.append("Bold", "true"); } - if (cur_font->getSerif()) { + if (cur_font->getSerif()) + { a.append("Serif", "true"); } - if (cur_font->getFixedWidth()) { + if (cur_font->getFixedWidth()) + { a.append("FixedWidth", "true"); } return a; } -void OFDWriter::makePath(ST_Loc path) { +void OFDWriter::makePath(ST_Loc path) +{ QString path_str = path.getPath(); - int n = 0; - while (path_str[path_str.length() - n - 1] != '\\') - n++; - path_str.chop(n); - //qDebug() << path_str; - if (!QDir().mkpath(path_str)) { - throw WritingFileException("无法创建文件路径: " + path.getPath()); +// int n = 0; +// while (path_str[path_str.length() - n - 1] != '/') +// n++; +// path_str.chop(n); + int index = path_str.lastIndexOf('/'); + path_str = path_str.left(index + 1); + + qDebug() << path_str; + if (!QDir().mkpath(path_str)) + { + qDebug() << "can't mkPath:"<Format.size() != 0) + { + a.append("Format", cur_multiMedia->Format); + } + + if(cur_multiMedia->Type.size() != 0) + { + a.append("Type" ,cur_multiMedia->Type); + } + +// if(cur_multiMedia->MediaFile.size() != 0) +// { +// a.append("MediaFile",cur_multiMedia->MediaFile); +// } + + return a; +} diff --git a/ofdEditor/ofd/ofd_writer.h b/ofdEditor/ofd/ofd_writer.h index 9c62c45c7279baef0add6393ebaa1fe9c22d1e18..9acaef5c07f65a4573dd4a62b4e2f7b3e4f70505 100644 --- a/ofdEditor/ofd/ofd_writer.h +++ b/ofdEditor/ofd/ofd_writer.h @@ -24,6 +24,7 @@ class CT_DrawParam; class CT_Font; class Res; class CT_PageArea; +class CT_MultiMedia; class OFDSHARED_EXPORT OFDWriter { @@ -32,9 +33,12 @@ private: ST_Loc current_path; //当前文档节点的路径 QFile * current_file; //当前输出的文件 QXmlStreamWriter writer; + QString tempPath; // 临时文件夹 + void makePath(ST_Loc path); void createFile(); - void writeOFD(); + void makePath(QString path_str); + void writeDocument(Document * data); void writePage(Page * data); void writeRes(Res * data); @@ -44,6 +48,7 @@ private: void writeColor(CT_Color * cur_color); void writeColorSpace(CT_ColorSpace * cur_colorspace); void writeFont(CT_Font * cur_font); + void writeMultiMedia(CT_MultiMedia* cur_multiMedia); void writeDrawParam(CT_DrawParam * cur_draw_param); void writeTextObject(CT_Text * cur_text); void writePathObject(CT_Path * cur_path); @@ -53,6 +58,9 @@ private: void writeBase(CT_Base * cur_base); public: OFDWriter(OFD * _data, QString _path); + void writeOFD(); + void setTempPath(QString tmpPath){ this->tempPath = tmpPath;} + QString getTempPath(){ return this->tempPath; } // 转换时,将临时路径的图片等资源文件拷贝过来 }; QXmlStreamAttributes getAttributes(OFD * data); //返回OFD类型标签的属性,方便书写 @@ -64,4 +72,7 @@ QXmlStreamAttributes getAttributes(CT_Path * cur_path); QXmlStreamAttributes getAttributes(CT_ColorSpace * cur_colorspace); QXmlStreamAttributes getAttributes(CT_DrawParam * cur_draw_param); QXmlStreamAttributes getAttributes(CT_Font * cur_font); +QXmlStreamAttributes getAttributes(CT_Text * cur_text); +QXmlStreamAttributes getAttributes(CT_Image * cur_image); +QXmlStreamAttributes getAttributes(CT_MultiMedia* cur_multiMedia); #endif // OFD_WRITER_H diff --git a/ofdEditor/start/ActionConnector/ActionConnector.cpp b/ofdEditor/start/ActionConnector/ActionConnector.cpp index e9712e35847a277b5c85a9f90da599572d8e26fc..720b005ce4490c466d056e5d6894e080c047efca 100644 --- a/ofdEditor/start/ActionConnector/ActionConnector.cpp +++ b/ofdEditor/start/ActionConnector/ActionConnector.cpp @@ -3,10 +3,8 @@ #include "ui/PassageMainWindow.h" #include "Doc/DocPage.h" #include "DataTypes/document/ct_docinfo.h" +#include "Widget/InsertTableDialog.h" #include "Widget/DocInfoDialog.h" - -#include "app/APPInfo.h" - #include #include @@ -22,6 +20,11 @@ ActionConnector::ActionConnector(PassageMainWindow *mainWindow) init(); } +DocPassage *ActionConnector::getActivePassage() +{ + return this->passage; +} + void ActionConnector::showAttribute() { if(this->passage == NULL) @@ -30,11 +33,10 @@ void ActionConnector::showAttribute() return; } - CT_DocInfo * docInfo = this->passage->getDocInfo(); - DocInfoDialog* dialog = new DocInfoDialog(docInfo,this->mainWindow); // 设置窗口 + DocInfoDialog* dialog = DocInfoDialog::getInstance(); // 获得实例 + dialog->init(docInfo); // 设置窗口 dialog->exec(); // 运行 - qDebug() << "show Attribute"; } @@ -68,7 +70,7 @@ void ActionConnector::addNewPage() *@return 返回值 *@date 2017/05/15 */ -void ActionConnector::addNewBlock(InsertBlockInfo& blockInfo) +void ActionConnector::addNewBlock(InsertBlockInfo blockInfo) { if(this->passage == NULL) { @@ -76,32 +78,35 @@ void ActionConnector::addNewBlock(InsertBlockInfo& blockInfo) } // this->updateActivePassage(); // 更新文章 - DocPage * page = qobject_cast(this->passage->focusWidget()); + DocPage *page = this->passage->getLastedActivedPage(); // 获得最近操作过的页面 if(page == NULL) { - qDebug() <<"No Focus Widget"; + qDebug() <<"NO Last actived page"; return; } else { - //插入文本框 + if (blockInfo.type == DocPage::text) { - qDebug() << "get Focus Sucess"; - page->setBlockFlag(DocPage::draw); // 进入绘画状态 - - // InsertBlockInfo blockInfo(type,layer); // 设置插入文本框信息 - page->setInsertBlockType(blockInfo); // 设置插入文本框信息 - - page->viewport()->setCursor(Qt::CrossCursor); // 将鼠标设置为加号形状 + //插入文本框 +// qDebug() << "get Focus Sucess"; + page->setBlockFlag(DocPage::draw); // 进入绘画状态 + page->setInsertBlockType(blockInfo); // 设置插入文本框信息 + page->viewport()->setCursor(Qt::CrossCursor); // 将鼠标设置为加号形状 } - //插入图片框 else if (blockInfo.type == DocPage::image) { - page->setInsertBlockType(blockInfo); // 设置插入文本框信息 - qDebug() << "!!!"; + //插入图片框 + page->setInsertBlockType(blockInfo); // 设置插入文本框信息 page->addImage(); } + else if( blockInfo.type == DocPage::table ) + { + // 插入表格 + page->setInsertBlockType(blockInfo); // 设置插入为表格 + page->addTable(); // 从对话框来设置 + } } } @@ -118,6 +123,7 @@ void ActionConnector::addImageBlock() if(this->passage == NULL) return; InsertBlockInfo blockInfo(this->defaultLayer,DocPage::image); // 设置插入文本框信息 +// qDebug() << "add imageBlock"; this->addNewBlock(blockInfo); } @@ -125,8 +131,11 @@ void ActionConnector::addTableBlock() { if(this->passage == NULL) return; + InsertBlockInfo blockInfo(this->defaultLayer,DocPage::table); // 设置插入文本框信息 this->addNewBlock(blockInfo); +// InsertTableDialog * tableDialog = new InsertTableDialog(0); +// tableDialog->exec(); } void ActionConnector::undo() @@ -146,35 +155,20 @@ void ActionConnector::setDocPassage(DocPassage *passage) this->passage = passage; } +void ActionConnector::updateActivePassage(DocPassage *passage) +{ + this->passage = passage; +} +void ActionConnector::startFindAndReplace() +{ + mainWindow->activateFindAndReplaceDock(); +} -/** - * @Author Chaoqun - * @brief 更新当前的活跃窗口 - * @param 参数 - * @return 返回值 - * @date 2017/06/23 - */ -void ActionConnector::updateActivePassage(QMdiSubWindow *window) +DocPage *ActionConnector::getActivePage() { - if(window == NULL) - { - qDebug() << "updateActivePassage NULL" - << "there's no actived window"; - this->passage = NULL; - return; - } - DocPassage* passage = qobject_cast(window->widget()); // 获得文档 - if(passage == NULL) - { - qDebug()<< "The active MdiWindow may not DocPassage"; - this->passage = NULL; - } - else - { - this->passage = passage; - } + return qobject_cast(this->passage->focusWidget()); } void ActionConnector::init() diff --git a/ofdEditor/start/ActionConnector/ActionConnector.h b/ofdEditor/start/ActionConnector/ActionConnector.h index 878056ba29c007670847a09b24d993b27ee61623..f0c6a069515ed20a7fa995fcec946fa19df21344 100644 --- a/ofdEditor/start/ActionConnector/ActionConnector.h +++ b/ofdEditor/start/ActionConnector/ActionConnector.h @@ -24,12 +24,13 @@ public: ActionConnector(PassageMainWindow * mainWindow); DocPage::Layer getDefaultLayer(){return this->defaultLayer;} - + DocPassage * getActivePassage(); //获取当前操作的文档 + DocPage *getActivePage(); //获取当前操作的页面 public slots: void showAttribute(); // 显示文档元信息 void setMainWindow(PassageMainWindow * mainWindow); // 设置主窗口 void addNewPage(); // 添加一个新页面 - void addNewBlock(InsertBlockInfo &blockInfo); // 插入一个块 + void addNewBlock(InsertBlockInfo blockInfo); // 插入一个块 void addTextBlock(); // 插入文本框 void addImageBlock(); // 插入图片框 void addTableBlock(); // 插入表格 @@ -39,7 +40,9 @@ public slots: void setDefaultLayer(DocPage::Layer layer){this->defaultLayer = layer;} - void updateActivePassage(QMdiSubWindow * window ); // 更新当前操作的文章 + void updateActivePassage(DocPassage* passage); // 更新当前操作的文章 + + void startFindAndReplace(); //打开查找和替换界面 private: PassageMainWindow * mainWindow; // 主窗口 diff --git a/ofdEditor/start/Settings/RecentFileItem.cpp b/ofdEditor/start/Settings/RecentFileItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c263913bed3f6773d9a83e3b9f1b7d9e1fa47c7 --- /dev/null +++ b/ofdEditor/start/Settings/RecentFileItem.cpp @@ -0,0 +1,90 @@ +#include "RecentFileItem.h" +#include +#include + +RecentFileItem::RecentFileItem(QObject *parent) : QObject(parent) +{ + +} + +RecentFileItem::RecentFileItem( + QString fileName, + QString author, + QString recentEditTime, + QString recentOpenTime, + QString filePath): + QObject(0) +{ + this->fileName = fileName; + this->author = author; + this->recentEditTime = QDateTime::fromString( + recentEditTime, + "yyyy-MM-dd"); + this->recentOpenTime = QDateTime::fromString( + recentOpenTime, + "yyyy-MM-dd HH:mm:ss"); + this->filePath = filePath; +} + +void RecentFileItem::setRecentOpenTime(QString recentOpenTime) +{ + this->recentOpenTime = QDateTime::fromString( + recentOpenTime, + "yyyy-MM-dd HH:mm:ss"); +} + +void RecentFileItem::setRecentOpenTime(QDateTime recentOpenTime) +{ + this->recentOpenTime = recentOpenTime; +} + +void RecentFileItem::setRecentEditTime(QString recentEditTime) +{ + this->recentEditTime = QDateTime::fromString( + recentEditTime, + "yyyy-MM-dd"); +} + +void RecentFileItem::setRecentEditTime(QDateTime recentEditTime) +{ + this->recentEditTime = recentEditTime; +} + +void RecentFileItem::setFilePath(QString filePath) +{ + this->filePath = filePath; +} + +void RecentFileItem::init( + QString fileName, + QString author, + QString recentEditTime, + QString recentOpenTime, + QString filePath) +{ + this->fileName = fileName; + this->author = author; + this->recentOpenTime = QDateTime::fromString( + recentOpenTime, + "yyyy-MM-dd HH:mm:ss"); + this->recentOpenTime = QDateTime::fromString( + recentEditTime, + "yyyy-MM-dd"); + this->filePath = filePath; +} + +void RecentFileItem::print() +{ + qDebug() << "fileName " << this->fileName + << " author " << this->author + << " recent open time " << this->recentOpenTime.toString("yyyy-MM-dd HH:mm:ss") + << " recent edit time" << this->recentEditTime.toString("yyyy-MM-dd") + << " filePath" << this->filePath; +} + +bool RecentFileItem::isExist() +{ + QFile qfile; + qfile.setFileName(this->filePath); + return qfile.exists(); +} diff --git a/ofdEditor/start/Settings/RecentFileItem.h b/ofdEditor/start/Settings/RecentFileItem.h new file mode 100644 index 0000000000000000000000000000000000000000..759f3acc2d5242b3f84135eaa2c4aaeefb1468e9 --- /dev/null +++ b/ofdEditor/start/Settings/RecentFileItem.h @@ -0,0 +1,67 @@ +#ifndef RECENTFILEITEM_H +#define RECENTFILEITEM_H + +#include +#include + +class RecentFileItem + : public QObject +{ + Q_OBJECT +public: + explicit RecentFileItem(QObject *parent = 0); + RecentFileItem( + QString fileName, + QString author, + QString recentEditTime, + QString recentOpenTime, + QString filePath); + + QString getFileName(){return this->fileName;} + QString getAuthor(){return this->author;} + QDateTime getRecentOpenTime(){return this->recentOpenTime;} + QString getRecentOpenTime_str(){ + return this->recentOpenTime.toString( + "yyyy-MM-dd HH:mm:ss");} + QDateTime getRecentEditTime(){return this->recentEditTime;} + QString getRecentEditTime_str(){ + return this->recentEditTime.toString( + "yyyy-MM-dd");} + QString getFilePath(){return this->filePath;} + + void setFileName(QString fileName){this->fileName = fileName;} + void setAuthor(QString author){this->author = author;} + void setRecentOpenTime(QString recentOpenTime); + void setRecentOpenTime(QDateTime recentOpenTime); + void setRecentEditTime(QString recentEditTime); + void setRecentEditTime(QDateTime recentEditTime); + void setFilePath(QString filePath); + + void init( + QString fileName, + QString author, + QString recentEditTime, + QString recentOpenTime, + QString filePath); + + void print(); // 通过qDebug方式输出 + bool isExist(); // 检查该文件是否存在 + + +private: + QString fileName; // 文件名 + QString author; // 作者 + + // 根据文件格式,资金修改的时间精确到天 + QDateTime recentOpenTime; // 最近打开文件时间 + QDateTime recentEditTime; // 最近编辑文件时间 + QString filePath; // 文件路径 + +signals: + +public slots: + + +}; + +#endif // RECENTFILEITEM_H diff --git a/ofdEditor/start/Settings/RecentFileList.cpp b/ofdEditor/start/Settings/RecentFileList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6013b13173c4d1d7ed29105646d0a9f39f6d3a9f --- /dev/null +++ b/ofdEditor/start/Settings/RecentFileList.cpp @@ -0,0 +1,359 @@ +#include "RecentFileList.h" +#include "RecentFileItem.h" + + +#include "jsoncpp.cpp" + +#include +#include +#include +#include + +using std::string; + + +RecentFileList* RecentFileList::m_instance = NULL; + +/// +/// \brief RecentFileList::getInstance +/// 获得实例 +/// \return +/// +RecentFileList *RecentFileList::getInstance() +{ + if(m_instance == NULL) + { + m_instance = new RecentFileList(); + } + + return m_instance; +} + +/// +/// \brief RecentFileList::qDebugFileList +/// 通过qDebug方式输出文件列表 +/// +void RecentFileList::qDebugFileList() +{ + for(int i = 0 ; i < this->fileList.size(); i++) + { + this->fileList[i]->print(); + } +} + +/// +/// \brief RecentFileList::RecentFileList +/// 默认初始化函数 +/// \param parent +/// +RecentFileList::RecentFileList(QObject *parent) + : QObject(parent) +{ + this->filePath = "recent_log.json"; + this->loadRecentFileList(this->filePath); +} + +/// +/// \brief RecentFileList::loadRecentFileList +/// \param filepath 完整路径 +/// +void RecentFileList::loadRecentFileList(QString filepath) +{ + QFile qfile; + qfile.setFileName(filepath); // 设置文件路径 + this->fileList.clear(); + + // 如果文件不存在 + if(!qfile.exists()) + { + qDebug() << "Recent List is not exists."; + + this->setDefault(); + this->exportRecentFileList(filepath); + return; + } + + // 打开文件 + if(!qfile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qDebug() << "Recent list file opening failed"; + this->setDefault(); + this->exportRecentFileList(filepath); + return; + } + + QTextStream textInput(&qfile); // 设置文件流 + QString qstr = textInput.readAll(); // 读取文件的全部内容 + string str = qstr.toStdString(); // 转换为标准字符串 + + Reader reader; // json 解析器 + Value value; // 值 + + if(!reader.parse(str,value)) + { + // 如果解析失败 + this->setDefault(); + this->exportRecentFileList(filepath); + return; + } + + if(value.empty()) + { + this->setDefault(); + return; + } + Value files = value["files"]; + for(int i = 0; i < files.size(); i++) + { + RecentFileItem* item = this->JsonToRecentFileItem(files[i]); + if(item != NULL) + this->fileList.append(item); + } + + this->deleteEmptyItem(); // 清除已经失效的项 + +} + +/// +/// \brief RecentFileList::exportRecentFileList +/// 将文件导出 +/// \param filepath +/// +void RecentFileList::exportRecentFileList(QString filepath) +{ + QFile qfile; // qt 文件支持 + qfile.setFileName(filepath); // 设置文件路径 + + // 检查文件是否可用 + if(!qfile.open(QIODevice::ReadWrite + | QIODevice::Text + | QIODevice::Truncate)) + { + qDebug() << "Program open file failed."; + return; + } + + this->deleteEmptyItem(); // 删除已经失效的最近的文件 + + QTextStream textOutput(&qfile); // 用来写出文件 + Value root; // 根节点 + Value files; // 文件数组节点 + + for(int i = 0; i < this->fileList.size(); i++) + { + Value item = this->recentFileItemToJson( + this->fileList.operator [](i)); + if(item.empty()) + continue; + files.append(item); + } + + root["files"] = files; // 保存根节点 + textOutput << QString::fromStdString( + root.toStyledString()) + << endl; // 写出文件 + textOutput.flush(); + qfile.close(); +} + +/// +/// \brief RecentFileList::recentFileItemToJson +/// \param item +/// \return +/// +Json::Value RecentFileList::recentFileItemToJson(RecentFileItem *item) +{ + Value value; + if(item == NULL) + { + return value; + } + + value["fileName"] = item->getFileName().toStdString(); + value["author"] = item->getAuthor().toStdString(); + value["recentOpenTime"] = item->getRecentOpenTime_str().toStdString(); + value["recentEditTime"] = item->getRecentEditTime_str().toStdString(); + value["filePath"] = item->getFilePath().toStdString(); + + return value; + +} + +/// +/// \brief RecentFileList::JsonToRecentFileItem +/// \return +/// +RecentFileItem *RecentFileList::JsonToRecentFileItem(Json::Value value) +{ + if(value.empty()) + { + return NULL; + } + + RecentFileItem* item = new RecentFileItem(); + item->setFileName( + QString::fromStdString( + value["fileName"].asString())); + item->setAuthor( + QString::fromStdString( + value["author"].asString())); + item->setRecentOpenTime( + QString::fromStdString( + value["recentOpenTime"].asString())); + item->setRecentEditTime( + QString::fromStdString( + value["recentEditTime"].asString())); + item->setFilePath( + QString::fromStdString( + value["filePath"].asString())); + + return item; + +} + +void RecentFileList::deleteEmptyItem() +{ + // 检查,然后将那些项先输出后删除 + QVector::Iterator iter; + iter = this->fileList.begin(); + + qDebug() << "Empty item begin:"; + while(iter != this->fileList.end()) + { + RecentFileItem * item = *iter; + if(item->isExist() == false) + { + item->print(); + iter = this->fileList.erase(iter); + } + else + { + iter ++; + } + } + qDebug() << "Empty item end."; +} + +bool RecentFileList::isExisting(QString filePath) +{ + for(int i = 0; i < this->fileList.size(); i++) + { + if(this->fileList[i]->getFilePath() == filePath) + return true; + } + + return false; +} + +/// +/// \brief RecentFileList::item +/// 获得某一项 +/// \param filePath +/// \return +/// +RecentFileItem *RecentFileList::item(QString filePath) +{ + for(int i = 0; i < this->fileList.size(); i++) + { + if(this->fileList[i]->getFilePath() == filePath) + return this->fileList[i]; + } + + return NULL; +} + +/// +/// \brief RecentFileList::item +/// 获得某一项 +/// \param i +/// \return +/// +RecentFileItem *RecentFileList::item(int i) +{ + if(i < 0 || i > this->fileList.size()) + return NULL; + + return this->fileList[i]; +} + +RecentFileItem *RecentFileList::remove(RecentFileItem *item) +{ + RecentFileItem* oldItem = this->item(item->getFilePath()); + this->fileList.remove( + this->fileList.indexOf(oldItem)); + return oldItem; +} + +RecentFileItem *RecentFileList::remove(QString filePath) +{ + RecentFileItem *oldItem = this->item(filePath); + this->fileList.remove( + this->fileList.indexOf(oldItem)); + return oldItem; +} + +/// +/// \brief RecentFileList::addItem +/// 加入一项到队列中,加入后自动保存 +/// \param item +/// +void RecentFileList::addItem(RecentFileItem *item) +{ + + if(this->isExisting(item->getFilePath())) + { + // 如果已经存在同样的项,先删除,后更新再插入 + this->remove(item); + this->fileList.append(item); + + } + else + { + // 如果是新项,则直接插入 + this->fileList.append(item); + } + item->print(); + this->exportRecentFileList(this->filePath); // 自动保存 +} + +int RecentFileList::indexOf(RecentFileItem *item) +{ + for(int i = 0; i < this->fileList.size(); i++) + { + if(this->fileList[i]->getFilePath() == filePath) + return i; + } + + return -1; + +} + +/// +/// \brief RecentFileList::setDefault +/// 当没有文件时,可以用来生成默认文件 +/// +void RecentFileList::setDefault() +{ + this->filePath = "recent_log.json"; + this->fileList.clear(); + + // 以下部分为测试,实际使用时请删除 + RecentFileItem* item = new RecentFileItem( + "hhhhhh.ofd", + "chaoqun", + "2017-8-23", + "2017-8-23", + "E:/test.ofd"); + + RecentFileItem* item2 = new RecentFileItem( + "aaaaaa.ofd", + "chaoqun", + "2017-8-23", + "2017-8-23", + "E:/test2.ofd"); + + this->fileList.append(item); + this->fileList.append(item2); + + // 以上部分是测试,实际使用时请删除 +} diff --git a/ofdEditor/start/Settings/RecentFileList.h b/ofdEditor/start/Settings/RecentFileList.h new file mode 100644 index 0000000000000000000000000000000000000000..a42ffd9e4b32259b44ff9c9fa5d2ef45361027d2 --- /dev/null +++ b/ofdEditor/start/Settings/RecentFileList.h @@ -0,0 +1,59 @@ +#ifndef RECENTFILELIST_H +#define RECENTFILELIST_H + +#include +#include + +#include "json/json.h" +#include "json/json-forwards.h" +using Json::Reader; +using Json::Value; + +class RecentFileItem; + +class RecentFileList + : public QObject +{ + Q_OBJECT + +public: + static RecentFileList* getInstance(); // 获得实例 + static void destoryInstance(); // 销毁实例 + + QString getFilePath(){return this->filePath;} + void qDebugFileList(); // 输出文件列表 + void deleteEmptyItem(); // 检查是否有的最近打开文件已经被删除 + void clear(){this->fileList.clear();} // 嫌麻烦可以清除所有最近记录 + bool isExisting(QString filePath); // 检查某文件是否存在 + RecentFileItem *item(QString filePath); // 检查文件是否存在,返回该文件 + RecentFileItem *item(int i); // 根据位置获得 + RecentFileItem *remove(RecentFileItem* item); // 从队列中清除某一项 + RecentFileItem *remove(QString filePath); // 从队列中清除某一项 + void addItem(RecentFileItem* item); // 添加新的项 + int indexOf(RecentFileItem* item); // item的位置 + int size(){return this->fileList.size();} // 获取队列大小 + + void save(){this->exportRecentFileList(this->filePath);} // 保存到文件 + void load(){this->loadRecentFileList(this->filePath);} // 从文件中更新 + +private: + explicit RecentFileList(QObject *parent = 0); + static RecentFileList* m_instance; // 静态实例 + QString filePath; // 文件存储路径 + QVector fileList; // 最近的文档列表 + + void loadRecentFileList(QString filepath); // 读取文件 + void exportRecentFileList(QString filepath); // 导出文件 + + Value recentFileItemToJson(RecentFileItem* item); // 将元素转换为value + RecentFileItem* JsonToRecentFileItem(Value value); // 将value转换为item + + void setDefault(); // 设置默认值 + +signals: + +public slots: + +}; + +#endif // RECENTFILELIST_H diff --git a/ofdEditor/start/app/APPInfo.cpp b/ofdEditor/start/app/APPInfo.cpp deleted file mode 100644 index f0d377af555c46cc88491a1751816710da79689d..0000000000000000000000000000000000000000 --- a/ofdEditor/start/app/APPInfo.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "APPInfo.h" -#include -#include -#include -#include - -APPInfo::APPInfo(QObject *parent) : QObject(parent) -{ - -} - -QString APPInfo::GetAppName() -{ - return this->appName; -} - -QString APPInfo::GetAppVersion() -{ - return this->appVersion; -} - -void APPInfo::initFromFile() -{ - QFile file(":/appInfo/source/appInfo.json"); // 将文件存在resource内 - if(!file.open(QIODevice::ReadOnly)) - { - qDebug() << "open app information file failed"; - return; - } - - QTextStream txtInput(&file); // 设置文件流 - QString str = txtInput.readAll(); // 读全部文件 - qDebug() << str; - -} - -void APPInfo::setAppName(QString &name) -{ - this->appName = name; -} - -void APPInfo::setAppVersion(QString &version) -{ - this->appVersion = version; -} diff --git a/ofdEditor/start/app/APPInfo.h b/ofdEditor/start/app/APPInfo.h deleted file mode 100644 index 5fe183970db7bba326682092c989e870877ed47d..0000000000000000000000000000000000000000 --- a/ofdEditor/start/app/APPInfo.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef APPINFO_H -#define APPINFO_H - -#include -#include - -class APPInfo - : public QObject -{ - Q_OBJECT -public: - explicit APPInfo(QObject *parent = 0); - - QString GetAppName(); // 获得应用名称 - QString GetAppVersion(); // 获得应用版本号 - - void initFromFile(); // 从文件中获取版本信息 - -signals: - -public slots: - void setAppName(QString &name); // 设置名称 - void setAppVersion(QString &version); // 设置版本号 - -private: - QString appName; // 应用名称 - QString appVersion; // app版本 -}; - -#endif // APPINFO_H diff --git a/ofdEditor/start/cn_start.ts b/ofdEditor/start/cn_start.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ae1a3a5bc179573494d986d1fa37d8f447ed605 --- /dev/null +++ b/ofdEditor/start/cn_start.ts @@ -0,0 +1,746 @@ + + + + + PassageMainWindow + + + + Welcome! + 欢迎页! + + + + OFD Editor + OFD版式文档编辑器 + + + + New File + 新建文档 + + + + Create a new ofd file + 创建要给ofd文档 + + + + Template + 模板 + + + + Use a template to create a new document + 使用模板新建一个文档 + + + + Open File + 打开 + + + + Open an existing ofd file + 打开一个存在的ofd文件 + + + + Save + 保存 + + + + Save file + 保存文件 + + + + + Save as + 另存为 + + + + Print + 打印 + + + + Print your document + 打印你的文档 + + + + Attribute + 文档属性 + + + + Show you the attribute of the actived passage + 查看你当前编辑的文档的属性 + + + + Setting + 设置 + + + + Set the software's preference + 设置软件的首选项 + + + + EditMode + 编辑模式 + + + + + change current state to edit mode + 修改当前状态为编辑模式 + + + + ViewMode + 观察模式 + + + + ZoomIn + 放大 + + + + ZoomOut + 缩小 + + + + Undo + 撤销 + + + + Undo your last action + 插销你的上一步操作 + + + + Redo + 重做 + + + + Redo the action you undo + 重做你刚撤销的操作 + + + + Copy + 复制 + + + + Copy the content you selected + 复制你选择的内容 + + + + Cut + 剪切 + + + + Cut the content you selected + 剪切你选择的内容 + + + + Paste + 粘贴 + + + + Paste your pasteboard content + 粘贴你剪贴板里的内容 + + + + Find/Replace + 查找/替换 + + + + Find specific text or replace them + 查找给定文本,并可以替换 + + + + Insert New Page + 增加新页 + + + + Insert a new Page into document + 插入一个新页面到文档 + + + + Insert TextBlock + 插入文本框 + + + + Insert a new TextBlock + 插入一个新的文本框 + + + + Insert Image + 插入图片 + + + + Insert a image + 插入一个图片 + + + + Insert Table + 插入表格 + + + + Insert a table + 插入一个表格 + + + + Page Format + 页面格式 + + + + Set the page format + 设置页面格式 + + + + Text Format + 字体格式 + + + + Set the selected texts' format + 设置选择的文本的字体格式 + + + + Paragraph Format + 段落 + + + + Set this paragarph format + 设置选择的段落的格式 + + + + Image Format + 图片格式 + + + + Set the Selected image's format + 设置选择的图片的格式 + + + + Table Format + 表格格式 + + + + Set the selected table's format + 设置选择的表格的格式 + + + + about Qt + 关于Qt + + + + About App + 关于本应用 + + + + About this Application + 关于本应用 + + + + Help + 帮助 + + + + Show the help Window + 显示帮助页面 + + + + Files + 文件 + + + + + Edit + 编辑 + + + + + Format + 格式 + + + + + Insert + 插入 + + + + About + 关于 + + + + 72 + + + + + 48 + + + + + 36 + + + + + 28 + + + + + 26 + + + + + 24 + + + + + 22 + + + + + 20 + + + + + 18 + + + + + 16 + + + + + 14 + + + + + 12 + + + + + 11 + + + + + 10.5 + + + + + 10 + + + + + 9 + + + + + 8 + + + + + 7.5 + + + + + 6.5 + + + + + 5.5 + + + + + 5 + + + + + Size 8 + 八号 + + + + Size 7 + 七号 + + + + Size 6 Minor + 小六 + + + + Size 6 + 六号 + + + + Size 5 Minor + 小五 + + + + Size 5 + 五号 + + + + Size 4 Minor + 小四 + + + + Size 4 + 四号 + + + + Size 3 Minor + 小三 + + + + Size 3 + 三号 + + + + Size 2 Minor + 小二 + + + + Size 2 + 二号 + + + + Size 1 Minor + 小一 + + + + Size 1 + 一号 + + + + Prime Minor + 小初 + + + + Prime + 初号 + + + + JiMi 1Nian + 机密★1年 + + + + Te Ji + 特急 + + + + XXXXXWenJian + ×××××文件 + + + + XXX[2012]10Hao + ×××﹝2012﹞10号 + + + + XXXXXGuanYuXXXXXXDeTongZhi + ×××关于××××的通知 + + + + XXXXXXXX: + ×××××: + + + + OOOOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. +OOOOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. +OOOOXXXXXXXXXXXXXXXXXXXXXX. +OOOOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××。 + ×××××××××××××××××××××××××××××××××××。 + ××××××××××××××。 + ××××××××××××。×××××××××××××××××××××××××××××××××××××××××× + + + + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. +OOOOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. + ××××××××××××××××××××××××××××。 ×××××××××××××××××××××××××××××××××××××××××××。 + + + + XXXXXXXXXXXX + ×××××××××××× + + + + 2012Nian7Yue1Ri + 2012年7月1日 + + + + (XXXXXX) + (××××××) + + + + ChaoSong:XXXXXXX,XXXXX,XXXXXX + 抄送:×××××,××××××,××××××× + + + + XXXXXXXX + ×××××××××× + + + + 2012Nian7Yue1RiYinFa + 2012年7月1日印发 + + + 4.5 + 八号 + + + 5.25 + 七号 + + + + Bold + 加粗 + + + + Set selected text Bold or not bold + 将选择的文本加粗 + + + + Italic + 斜体 + + + + Set the selected text Italic + 设置选择的文本斜体 + + + + Underline + 下划线 + + + + Set the selected text underline + 设置选择的文本下划线 + + + + middle + 居中 + + + + Set the selected paragraph align middle + 设置选择的段落格式为居中 + + + + Left + 左对齐 + + + + Set the selected paragraph align by left + 设置选择的段落对齐样式为左对齐 + + + + Right + 右对齐 + + + + Set the selected paragraph align by right + 设置选中的段落的对齐样式为右对齐 + + + + jutify + 两端对齐 + + + + Set the selected paragraph align by left and right + 设置选择的文本的对齐样式为两端对齐 + + + + File + 文件 + + + + TextBlock + 文本框 + + + + JSON files(*.ofd) + OFD文件(*ofd) + + + + Choose an ofd document file! + 选择一个OFD文件! + + + + Save the passage content as a ofd file + 保存文件为一个ofd文件 + + + + OFD files(*.ofd) + + + + + RecentFiles + + + Form + + + + + 最近打开的文档 + + + + + New Row + + + + + 文件名 + + + + + 作者 + + + + + 最近打开时间 + + + + + 最近编辑时间 + + + + + 文件路径 + + + + + 清空最近文件记录 + + + + + 新建文档 + + + + diff --git a/ofdEditor/start/icons.qrc b/ofdEditor/start/icons.qrc index 75225fb79a6fecca693dcd22a801088e4a4d52c6..8cf40b4e5cb1a747fe87fcf6f19066bca6868869 100644 --- a/ofdEditor/start/icons.qrc +++ b/ofdEditor/start/icons.qrc @@ -20,5 +20,23 @@ source/icons/tableFormat.png source/icons/TextFormat.png source/icons/undo.png + source/icons/attribute.png + source/icons/bold.png + source/icons/italic.png + source/icons/justify.png + source/icons/left.png + source/icons/middle.png + source/icons/pageFormat.png + source/icons/right.png + source/icons/underline.png + source/icons/EditMode.png + source/icons/Setting.png + source/icons/ViewMode.png + source/icons/ZoomIn.png + source/icons/ZoomOut.png + source/icons/template.png + source/icons/Find.png + source/icons/ofdEditor2.png + source/red_line.png diff --git a/ofdEditor/start/main.cpp b/ofdEditor/start/main.cpp index a2ae2bafcd3943fb6c6235979ba142c2c153477a..622932d1b9b16cca53deee4e2fa6b3af60726c3d 100644 --- a/ofdEditor/start/main.cpp +++ b/ofdEditor/start/main.cpp @@ -3,11 +3,36 @@ #include "ui/PassageMainWindow.h" #include #include <../ofd/ofdexceptions.h> +#include + int main(int argc, char *argv[]) { QApplication a(argc, argv); + a.setWindowIcon(QIcon(":/icons/source/icons/ofdEditor2.png")); + + QTranslator model_translator; + if(model_translator.load("cn_model.qm")) + { + a.installTranslator(&model_translator); + } + QTranslator start_translator; + if(start_translator.load("cn_start.qm")) + { + a.installTranslator(&start_translator); + } + + QTranslator qt_translator; + if(qt_translator.load("qt_zh_CN.qm")) + { + a.installTranslator(&qt_translator); + } + PassageMainWindow w; + w.show(); +// PassageMainWindow* mainwindow = PassageMainWindow::getInstance(); +// mainwindow->show(); + return a.exec(); } diff --git a/ofdEditor/start/source/icons/EditMode.png b/ofdEditor/start/source/icons/EditMode.png new file mode 100644 index 0000000000000000000000000000000000000000..cf05ce214162788f560e0f39052e2213ad2330ab Binary files /dev/null and b/ofdEditor/start/source/icons/EditMode.png differ diff --git a/ofdEditor/start/source/icons/Find.png b/ofdEditor/start/source/icons/Find.png new file mode 100644 index 0000000000000000000000000000000000000000..a689a59d956bf72a4fa86cc8da0cfd4e7fb6d98b Binary files /dev/null and b/ofdEditor/start/source/icons/Find.png differ diff --git a/ofdEditor/start/source/icons/Setting.png b/ofdEditor/start/source/icons/Setting.png new file mode 100644 index 0000000000000000000000000000000000000000..1831744cf1e8fc12ee964f2724dcff4fecb88965 Binary files /dev/null and b/ofdEditor/start/source/icons/Setting.png differ diff --git a/ofdEditor/start/source/icons/ViewMode.png b/ofdEditor/start/source/icons/ViewMode.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a38eb98eccedb5894dec59938ef2a0891d2eda Binary files /dev/null and b/ofdEditor/start/source/icons/ViewMode.png differ diff --git a/ofdEditor/start/source/icons/ZoomIn.png b/ofdEditor/start/source/icons/ZoomIn.png new file mode 100644 index 0000000000000000000000000000000000000000..2de3f47a30cc6b8af3e2f2939c9dd80d3e6ab6c9 Binary files /dev/null and b/ofdEditor/start/source/icons/ZoomIn.png differ diff --git a/ofdEditor/start/source/icons/ZoomOut.png b/ofdEditor/start/source/icons/ZoomOut.png new file mode 100644 index 0000000000000000000000000000000000000000..6c0d590e7001be23643245c275f15c35920524ef Binary files /dev/null and b/ofdEditor/start/source/icons/ZoomOut.png differ diff --git a/ofdEditor/start/source/icons/attribute.png b/ofdEditor/start/source/icons/attribute.png new file mode 100644 index 0000000000000000000000000000000000000000..fcb10c5c50a247c587aeef22121ae4be07803cdf Binary files /dev/null and b/ofdEditor/start/source/icons/attribute.png differ diff --git a/ofdEditor/start/source/icons/bold.png b/ofdEditor/start/source/icons/bold.png new file mode 100644 index 0000000000000000000000000000000000000000..daa1049c4bf0c89cb0f3dfb520a8bc85ed7a51cb Binary files /dev/null and b/ofdEditor/start/source/icons/bold.png differ diff --git a/ofdEditor/start/source/icons/italic.png b/ofdEditor/start/source/icons/italic.png new file mode 100644 index 0000000000000000000000000000000000000000..5814dcbeab2d1a3e27b87f07e2a73a6d5d0ef1d7 Binary files /dev/null and b/ofdEditor/start/source/icons/italic.png differ diff --git a/ofdEditor/start/source/icons/justify.png b/ofdEditor/start/source/icons/justify.png new file mode 100644 index 0000000000000000000000000000000000000000..3bd70a0f743033892358758c83ad917383e70577 Binary files /dev/null and b/ofdEditor/start/source/icons/justify.png differ diff --git a/ofdEditor/start/source/icons/left.png b/ofdEditor/start/source/icons/left.png new file mode 100644 index 0000000000000000000000000000000000000000..af36917c385c21e4cbc478bd80b4f9af02dca8da Binary files /dev/null and b/ofdEditor/start/source/icons/left.png differ diff --git a/ofdEditor/start/source/icons/middle.png b/ofdEditor/start/source/icons/middle.png new file mode 100644 index 0000000000000000000000000000000000000000..3702908896773419626fdbcd0a52e261b18cb024 Binary files /dev/null and b/ofdEditor/start/source/icons/middle.png differ diff --git a/ofdEditor/start/source/icons/ofdEditor2.png b/ofdEditor/start/source/icons/ofdEditor2.png new file mode 100644 index 0000000000000000000000000000000000000000..ea3d118bae1dc74e8999512a34bb5ac9edffe46e Binary files /dev/null and b/ofdEditor/start/source/icons/ofdEditor2.png differ diff --git a/ofdEditor/start/source/icons/pageFormat.png b/ofdEditor/start/source/icons/pageFormat.png new file mode 100644 index 0000000000000000000000000000000000000000..ca21c418b03a2f8e158922d75f666b05970d759a Binary files /dev/null and b/ofdEditor/start/source/icons/pageFormat.png differ diff --git a/ofdEditor/start/source/icons/right.png b/ofdEditor/start/source/icons/right.png new file mode 100644 index 0000000000000000000000000000000000000000..02cdf95147955235f45fd858d7ea002d791d18eb Binary files /dev/null and b/ofdEditor/start/source/icons/right.png differ diff --git a/ofdEditor/start/source/icons/template.png b/ofdEditor/start/source/icons/template.png new file mode 100644 index 0000000000000000000000000000000000000000..835106e6f4003926aa634b9635a5012c597af60a Binary files /dev/null and b/ofdEditor/start/source/icons/template.png differ diff --git a/ofdEditor/start/source/icons/underline.png b/ofdEditor/start/source/icons/underline.png new file mode 100644 index 0000000000000000000000000000000000000000..fc00b6ee3492aca115292a03a246f342d6b83b3d Binary files /dev/null and b/ofdEditor/start/source/icons/underline.png differ diff --git a/ofdEditor/start/source/red_line.png b/ofdEditor/start/source/red_line.png new file mode 100644 index 0000000000000000000000000000000000000000..2166424e7d6b86eb9213ef390c9999dd8717aa62 Binary files /dev/null and b/ofdEditor/start/source/red_line.png differ diff --git a/ofdEditor/start/start.pro b/ofdEditor/start/start.pro index 153a8dc1807a3d4cc1fc25b0a91a20f8feec2492..36f4400e324d9a483a418596a6d42c2301df7e2b 100644 --- a/ofdEditor/start/start.pro +++ b/ofdEditor/start/start.pro @@ -29,12 +29,18 @@ SOURCES += main.cpp\ mainwindow.cpp \ ui/PassageMainWindow.cpp \ ActionConnector/ActionConnector.cpp \ - app/APPInfo.cpp + ui/RecentFiles.cpp \ + Settings/RecentFileList.cpp \ + Settings/RecentFileItem.cpp \ + ui/ProgramSettingDialog.cpp HEADERS += mainwindow.h \ ui/PassageMainWindow.h \ ActionConnector/ActionConnector.h \ - app/APPInfo.h + ui/RecentFiles.h \ + Settings/RecentFileList.h \ + Settings/RecentFileItem.h \ + ui/ProgramSettingDialog.h DESTDIR = ../bin # 生成文件在这 MOC_DIR = ./moc # Q_OBJECT 类转换后的文件 @@ -43,7 +49,8 @@ OBJECTS_DIR += ./tmp # .obj 文件存放路径 # 引用,可以直接使用 include<文件名> 方式引入头文件 INCLUDEPATH += ../model \ - ../ofd + ../ofd \ + $$PWD/../libs/jsoncpp unix{ @@ -55,7 +62,10 @@ win32{ } RESOURCES += \ - icons.qrc \ - appinfo.qrc + icons.qrc -FORMS += +FORMS += \ + ui/RecentFiles.ui \ + ui/ProgramSettingDialog.ui + +TRANSLATIONS = cn_start.ts diff --git a/ofdEditor/start/ui/PassageMainWindow.cpp b/ofdEditor/start/ui/PassageMainWindow.cpp index 0c17cf83b59ac4fd83bbca1870d5b6bd48470eed..e64ca7143d405c98146fc077bb1d701cc32f6a82 100644 --- a/ofdEditor/start/ui/PassageMainWindow.cpp +++ b/ofdEditor/start/ui/PassageMainWindow.cpp @@ -12,12 +12,15 @@ #include #include #include -#include -#include +#include +#include +#include +#include + #include #include #include - +#include #include "Doc/DocPassage.h" #include "ActionConnector/ActionConnector.h" @@ -28,10 +31,36 @@ #include "Doc/DocPage.h" #include "Doc/DocTextBlock.h" #include "Doc/DocImageBlock.h" +#include "Widget/FindAndReplaceDock.h" +#include "Convert/Doc_OFDConvertor.h" +#include "ofd_writer.h" +#include "Widget/SelectTemplateDialog.h" +#include "Tool/UnitTool.h" +#include "Core/GlobalSetting.h" +#include "DataTypes/document/CT_DocInfo.h" +#include "Doc/DocTable.h" + +#include "Settings/RecentFileList.h" +#include "Settings/RecentFileItem.h" +#include "ui/RecentFiles.h" + + +PassageMainWindow* PassageMainWindow::m_instance = NULL; + +PassageMainWindow *PassageMainWindow::getInstance() +{ + if(m_instance == NULL) + { + m_instance = new PassageMainWindow(); + } + + return m_instance; +} PassageMainWindow::PassageMainWindow(QWidget *parent) :QMainWindow(parent) { + m_instance = this; init(); } @@ -40,23 +69,39 @@ PassageMainWindow::~PassageMainWindow() } -/** - * @Author Chaoqun - * @brief 摘要 - * @param 参数 - * @return 返回值 - * @date 2017/05/13 - */ -DocPassage *PassageMainWindow::createMdiChild() +/// +/// \brief PassageMainWindow::activePassage +/// 获得当前被激活的文章 +/// \return +/// +DocPassage *PassageMainWindow::activedPassage() { - qDebug()<<"execute"; - - DocPassage * child = new DocPassage(this); - child->addPage(new DocPage()); // 添加一个空白页 + QWidget* widget = this->tabArea->currentWidget(); + if(widget == 0) + { + // 如果返回空指针 + return NULL; + } - this->addDocPassage(child); // 加入到本视区 + return qobject_cast(widget); +} - return child; +/// +/// \brief PassageMainWindow::activateFindAndReplaceDock +/// 激活查找替换窗口 +/// +void PassageMainWindow::activateFindAndReplaceDock() +{ + if (connector->getActivePassage()) + { + FindAndReplaceDock* find_and_replace_dock + = FindAndReplaceDock::getInstance(); // 获得单例 + find_and_replace_dock->setCurrentPassage( + this->activedPassage()); // 设置当前操作的文章 + find_and_replace_dock->show(); + find_and_replace_dock->update(); + find_and_replace_dock->setBackgroundRole(QPalette::Window); + } } /** @@ -68,22 +113,62 @@ DocPassage *PassageMainWindow::createMdiChild() */ void PassageMainWindow::init() { - this->area = new QMdiArea(); - this->setCentralWidget(this->area); + + this->isEditable = true; + + /// 标签页 + this->tabArea = new QTabWidget(); + this->setCentralWidget(this->tabArea); + this->tabArea->setTabsClosable(true); // 允许关闭标签页 + this->tabArea->setMovable(true); // 允许调整标签页的顺序 + + // 最近打开文件 + RecentFiles* recentWidget = RecentFiles::getInstance(); + + this->tabArea->addTab(recentWidget,tr("Welcome!")); this->connector = new ActionConnector(this); // 新建连接器 + // 初始化变量 + this->imageBlock = NULL; + this->textBlock = NULL; + this->tableBlock = NULL; + initAction(); connectAction(); QLabel * status = new QLabel(); this->statusBar()->addWidget(status); - - this->setMinimumSize(960,720); this->setBackgroundRole(QPalette::Text); + this->setWindowTitle(tr("OFD Editor")); + this->setWindowIcon(QIcon(":/icons/source/icons/ofdEditor2.png")); + + // 配置查找替换窗口 + FindAndReplaceDock* find_and_replace_dock + = FindAndReplaceDock::getInstance(); // 获得单例 + this->addDockWidget( + Qt::BottomDockWidgetArea, + find_and_replace_dock); // 设置容器 + + find_and_replace_dock->setWindowIcon( + QIcon(":/icons/source/icons/Find.png")); // 设置图标 + find_and_replace_dock->setMaximumHeight(60); + find_and_replace_dock->setMinimumHeight(60); + find_and_replace_dock->setVisible(false); + + // 选择模板页面 + this->select_template_dialog = new SelectTemplateDialog(NULL, this); + this->select_template_dialog->setFixedSize(select_template_dialog->size()); + connect(this->select_template_dialog, SIGNAL(createTemplate(int)), + this, SLOT(createTemplatePassage(int))); + + // 测试 + RecentFileList * recentfilelist = RecentFileList::getInstance(); + recentfilelist->qDebugFileList(); + recentfilelist->save(); } /** @@ -100,6 +185,11 @@ void PassageMainWindow::initAction() this->newFileAction->setShortcut(QKeySequence::New); this->newFileAction->setIcon(QIcon(":/icons/source/icons/newFile.png")); + // 模板 + this->templateAction = new QAction(tr("Template"), NULL); // 新建模板页 + this->templateAction->setStatusTip(tr("Use a template to create a new document")); + this->templateAction->setIcon(QIcon(":/icons/source/icons/template.png")); + this->openFileAtcion = new QAction(tr("Open File"),NULL); // 打开文件 this->openFileAtcion->setStatusTip(tr("Open an existing ofd file")); this->openFileAtcion->setShortcut(QKeySequence::Open); @@ -122,6 +212,32 @@ void PassageMainWindow::initAction() this->attributeAction = new QAction(tr("Attribute"),NULL); // 文档属性 this->attributeAction->setStatusTip(tr("Show you the attribute of the actived passage")); + // 程序首选项 + this->softwareSettingAction = new QAction(tr("Setting"),NULL); // setting + this->softwareSettingAction->setStatusTip(tr("Set the software's preference")); + this->softwareSettingAction->setIcon(QIcon(":/icons/source/icons/Setting.png")); + + // 编辑模式 + this->editModeAction = new QAction(tr("EditMode"), NULL); + this->editModeAction->setStatusTip(tr("change current state to edit mode")); + this->editModeAction->setIcon(QIcon(":/icons/source/icons/EditMode.png")); + this->editModeAction->setCheckable(true); + this->editModeAction->setChecked(true); + + // 阅读模式 + this->viewModeAction = new QAction(tr("ViewMode"),NULL); + this->viewModeAction->setStatusTip(tr("change current state to edit mode")); + this->viewModeAction->setIcon(QIcon(":/icons/source/icons/ViewMode.png")); + this->viewModeAction->setCheckable(true); + + // 放大 + this->zoomInAction = new QAction(tr("ZoomIn"),NULL); + this->zoomInAction->setIcon(QIcon(":/icons/source/icons/ZoomIn.png")); + + // 缩小 + this->zoomOutAction = new QAction(tr("ZoomOut"), NULL); + this->zoomOutAction->setIcon(QIcon(":/icons/source/icons/ZoomOut.png")); + this->undoAction = new QAction(tr("Undo"),NULL); // 撤销操作 this->undoAction->setStatusTip(tr("Undo your last action")); this->undoAction->setShortcut(QKeySequence::Undo); @@ -147,6 +263,13 @@ void PassageMainWindow::initAction() this->pasteAction->setShortcut(QKeySequence::Paste); this->pasteAction->setIcon(QIcon(":/icons/source/icons/paste.png")); + // 查找 + this->find_and_replace = new QAction(tr("Find/Replace"), NULL); //查找和替换 + this->find_and_replace->setStatusTip(tr("Find specific text or replace them")); + this->find_and_replace->setShortcut(QKeySequence::Find); + this->find_and_replace->setIcon(QIcon(":/icons/source/icons/Find.png")); + //缺少Icon + this->insertNewPageAction = new QAction(tr("Insert New Page"),NULL); // 插入新页面 this->insertNewPageAction->setStatusTip(tr("Insert a new Page into document")); this->insertNewPageAction->setIcon(QIcon(":/icons/source/icons/insertNewPage.png")); @@ -163,8 +286,12 @@ void PassageMainWindow::initAction() this->insertTableAction->setStatusTip(tr("Insert a table")); this->insertTableAction->setIcon(QIcon(":/icons/source/icons/insertTable.png")); + this->pageFormat = new QAction(tr("Page Format"), NULL); // 页面格式 + this->pageFormat->setStatusTip(tr("Set the page format")); + this->pageFormat->setIcon(QIcon(":/icons/source/icons/pageFormat.png")); + this->textFormat = new QAction(tr("Text Format"),NULL); // 文字格式 - this->textFormat->setStatusTip(tr("Set the selected texts' Format")); + this->textFormat->setStatusTip(tr("Set the selected texts' format")); this->textFormat->setIcon(QIcon(":/icons/source/icons/TextFormat.png")); this->paragraphFormat = new QAction(tr("Paragraph Format"),NULL); // 段落格式 @@ -196,23 +323,36 @@ void PassageMainWindow::initAction() this->aboutMenu = this->menuBar()->addMenu(tr("About")); this->filesMenu->addAction(this->newFileAction); + this->filesMenu->addAction(this->templateAction); // 模板 this->filesMenu->addAction(this->openFileAtcion); this->filesMenu->addAction(this->saveAction); this->filesMenu->addAction(this->saveAsAction); this->filesMenu->addAction(this->printAction); this->filesMenu->addAction(this->attributeAction); - + this->filesMenu->addSeparator(); + this->filesMenu->addAction(this->softwareSettingAction); // 软件设置 + + this->editMenu->addAction(this->editModeAction); // 编辑状态 + this->editMenu->addAction(this->viewModeAction); // 阅读状态 + this->editMenu->addSeparator(); + this->editMenu->addAction(this->zoomInAction); // 放大 + this->editMenu->addAction(this->zoomOutAction); // 缩小 + this->editMenu->addSeparator(); this->editMenu->addAction(this->undoAction); this->editMenu->addAction(this->redoAction); this->editMenu->addSeparator(); // 分割线 this->editMenu->addAction(this->copyAction); this->editMenu->addAction(this->cutAction); this->editMenu->addAction(this->pasteAction); + this->editMenu->addAction(this->find_and_replace); + this->editMenu->addSeparator(); + this->formatMenu->addAction(this->textFormat); this->formatMenu->addAction(this->paragraphFormat); this->formatMenu->addAction(this->imageFormat); this->formatMenu->addAction(this->tableFormat); + this->formatMenu->addAction(this->pageFormat); this->insertMenu->addAction(this->insertNewPageAction); this->insertMenu->addAction(this->insertTextBlockAction); @@ -223,18 +363,129 @@ void PassageMainWindow::initAction() this->aboutMenu->addAction(this->aboutAppAction); this->aboutMenu->addAction(this->helpAciton); + // 文本操作工具栏部分/ + this->fontCombox = new QFontComboBox(); + this->fontCombox->setEditable(false); + this->fontSizeCombox = new QComboBox(); + this->fontSizeCombox->insertItem(0,tr("72")); + this->fontSizeCombox->insertItem(0,tr("48")); + this->fontSizeCombox->insertItem(0,tr("36")); + this->fontSizeCombox->insertItem(0,tr("28")); + this->fontSizeCombox->insertItem(0,tr("26")); + this->fontSizeCombox->insertItem(0,tr("24")); + this->fontSizeCombox->insertItem(0,tr("22")); + this->fontSizeCombox->insertItem(0,tr("20")); + this->fontSizeCombox->insertItem(0,tr("18")); + this->fontSizeCombox->insertItem(0,tr("16")); + this->fontSizeCombox->insertItem(0,tr("14")); + this->fontSizeCombox->insertItem(0,tr("12")); + this->fontSizeCombox->insertItem(0,tr("11")); + this->fontSizeCombox->insertItem(0,tr("10.5")); + this->fontSizeCombox->insertItem(0,tr("10")); + this->fontSizeCombox->insertItem(0,tr("9")); + this->fontSizeCombox->insertItem(0,tr("8")); + this->fontSizeCombox->insertItem(0,tr("7.5")); + this->fontSizeCombox->insertItem(0,tr("6.5")); + this->fontSizeCombox->insertItem(0,tr("5.5")); + this->fontSizeCombox->insertItem(0,tr("5")); + this->fontSizeCombox->insertItem(0,tr("Size 8")); + this->fontSizeCombox->insertItem(0,tr("Size 7")); + this->fontSizeCombox->insertItem(0,tr("Size 6 Minor")); + this->fontSizeCombox->insertItem(0,tr("Size 6")); + this->fontSizeCombox->insertItem(0,tr("Size 5 Minor")); + this->fontSizeCombox->insertItem(0,tr("Size 5")); + this->fontSizeCombox->insertItem(0,tr("Size 4 Minor")); + this->fontSizeCombox->insertItem(0,tr("Size 4")); + this->fontSizeCombox->insertItem(0,tr("Size 3 Minor")); + this->fontSizeCombox->insertItem(0,tr("Size 3")); + this->fontSizeCombox->insertItem(0,tr("Size 2 Minor")); + this->fontSizeCombox->insertItem(0,tr("Size 2")); + this->fontSizeCombox->insertItem(0,tr("Size 1 Minor")); + this->fontSizeCombox->insertItem(0,tr("Size 1")); + this->fontSizeCombox->insertItem(0,tr("Prime Minor")); + this->fontSizeCombox->insertItem(0,tr("Prime")); + + + + // 加粗 + this->boldAction = new QAction(tr("Bold"), NULL); + this->boldAction->setStatusTip(tr("Set selected text Bold or not bold")); + this->boldAction->setIcon(QIcon(":/icons/source/icons/bold.png")); + this->boldAction->setCheckable(true); + + // 倾斜 + this->italicAction = new QAction(tr("Italic"), NULL); + this->italicAction->setStatusTip(tr("Set the selected text Italic")); + this->italicAction->setIcon(QIcon(":/icons/source/icons/italic.png")); + this->italicAction->setCheckable(true); + + // 下划线 + this->underlineAction = new QAction(tr("Underline" ),NULL); + this->underlineAction->setStatusTip( + tr("Set the selected text underline")); + this->underlineAction->setIcon(QIcon(":/icons/source/icons/underline.png")); + this->underlineAction->setCheckable(true); + + // 居中 + this->middleAction = new QAction(tr("middle"),NULL); + this->middleAction->setStatusTip( + tr("Set the selected paragraph align middle")); + this->middleAction->setIcon(QIcon(":/icons/source/icons/middle.png")); + this->middleAction->setCheckable(true); + + // 左对齐 + this->leftAction = new QAction(tr("Left"),NULL); + this->leftAction->setStatusTip( + tr("Set the selected paragraph align by left")); + this->leftAction->setIcon(QIcon(":/icons/source/icons/left.png")); + this->leftAction->setCheckable(true); + + + // 右对齐 + this->rightAction = new QAction(tr("Right"),NULL); + this->rightAction->setStatusTip( + tr("Set the selected paragraph align by right")); + this->rightAction->setIcon(QIcon(":/icons/source/icons/right.png")); + this->rightAction->setCheckable(true); + + // 两端对齐 + this->justifyAction = new QAction(tr("jutify"),NULL); + this->justifyAction->setStatusTip( + tr("Set the selected paragraph align by left and right")); + this->justifyAction->setIcon(QIcon(":/icons/source/icons/justify.png")); + this->justifyAction->setCheckable(true); + + // 添加成组 + this->alignGroup = new QActionGroup(0); + this->alignGroup->addAction(this->middleAction); + this->alignGroup->addAction(this->leftAction); + this->alignGroup->addAction(this->rightAction); + this->alignGroup->addAction(this->justifyAction); + /*---------------------------------------------------------------------*/ this->file_toolBar = this->addToolBar(tr("File")); + this->file_toolBar->setMovable(false); this->edit_toolBar = this->addToolBar(tr("Edit")); + this->edit_toolBar->setMovable(false); this->format_toolBar = this->addToolBar(tr("Format")); + this->format_toolBar->setMovable(false); this->insert_toolBar = this->addToolBar(tr("Insert")); + this->insert_toolBar->setMovable(false); this->file_toolBar->addAction(this->newFileAction); this->file_toolBar->addAction(this->openFileAtcion); this->file_toolBar->addAction(this->saveAction); + this->edit_toolBar->addAction(this->editModeAction); + this->edit_toolBar->addAction(this->viewModeAction); + this->edit_toolBar->addSeparator(); this->edit_toolBar->addAction(this->undoAction); this->edit_toolBar->addAction(this->redoAction); + this->edit_toolBar->addSeparator(); + this->edit_toolBar->addAction(this->zoomInAction); + this->edit_toolBar->addAction(this->zoomOutAction); + this->edit_toolBar->addSeparator(); + this->edit_toolBar->addAction(this->find_and_replace); this->format_toolBar->addAction(this->textFormat); this->format_toolBar->addAction(this->paragraphFormat); @@ -246,6 +497,22 @@ void PassageMainWindow::initAction() this->insert_toolBar->addAction(this->insertImageAction); this->insert_toolBar->addAction(this->insertTableAction); + + // 添加工具栏 + this->textBlock_toolBar = this->addToolBar(tr("TextBlock")); + this->textBlock_toolBar->setMovable(false); + this->textBlock_toolBar->addWidget(this->fontCombox); // 字体选择 +// this->textBlock_toolBar->addWidget(this->fontSizeCombox); // 字体大小设置 + this->textBlock_toolBar->addSeparator(); // 分隔符 + this->textBlock_toolBar->addAction(this->boldAction); // 字体加粗 + this->textBlock_toolBar->addAction(this->italicAction); // 斜体 + this->textBlock_toolBar->addAction(this->underlineAction); // 下划线 + this->textBlock_toolBar->addSeparator(); // 分隔符 + this->textBlock_toolBar->addAction(this->leftAction); // 左对齐 + this->textBlock_toolBar->addAction(this->middleAction); // 居中 + this->textBlock_toolBar->addAction(this->rightAction); // 居右 + this->textBlock_toolBar->addAction(this->justifyAction); // 两端对齐 + } /** @@ -258,11 +525,21 @@ void PassageMainWindow::initAction() void PassageMainWindow::connectAction() { connect(this->newFileAction, SIGNAL(triggered(bool)), - this,SLOT(createMdiChild())); // 新建窗口 + this,SLOT(createEmptyPassage())); // 新建窗口 connect(this->openFileAtcion, SIGNAL(triggered(bool)), this, SLOT(openFile())); //打开文件 + connect(this->saveAction,SIGNAL(triggered(bool)), + this,SLOT(saveFile())); // 保存文件 + + connect(this->saveAsAction, SIGNAL(triggered(bool)), + this,SLOT(saveFileAs())); + + // 打印文章 + connect(this->printAction, SIGNAL(triggered(bool)), + this, SLOT(printPassage())); + connect(this->attributeAction, SIGNAL(triggered(bool)), this->connector, SLOT(showAttribute())); // 显示文档属性 @@ -273,10 +550,26 @@ void PassageMainWindow::connectAction() // this->connector, &ActionConnector::addNewBlock); // 插入新块 //undo operation - connect(this->undoAction,SIGNAL(triggered(bool)),this->connector,SLOT(undo())); + connect(this->undoAction,SIGNAL(triggered(bool)), + this,SLOT(undo())); //redo operation - connect(this->redoAction,SIGNAL(triggered(bool)),this->connector,SLOT(redo())); + connect(this->redoAction,SIGNAL(triggered(bool)), + this,SLOT(redo())); + + // 放大 + connect(this->zoomInAction, SIGNAL(triggered(bool)), + this, SLOT(zoomIn())); + + // 缩小 + connect(this->zoomOutAction, SIGNAL(triggered(bool)), + this, SLOT(zooomOut())); + + connect(this->find_and_replace, SIGNAL(triggered(bool)), + this->connector, SLOT(startFindAndReplace()));//查找/替换 + + connect(this->templateAction, SIGNAL(triggered(bool)), + this, SLOT(templateDialog())); //模板选择 connect(this->insertTextBlockAction, SIGNAL(triggered()), this->connector, SLOT(addTextBlock())); // 插入文本框 @@ -289,6 +582,8 @@ void PassageMainWindow::connectAction() connect(this->textFormat,SIGNAL(triggered(bool)), this,SLOT(fontDialog())); // 修改字体 + connect(this->pageFormat, SIGNAL(triggered(bool)), + this, SLOT(pageDialog())); connect(this->paragraphFormat,SIGNAL(triggered(bool)), this,SLOT(paragraphDialog())); // 修改段落 @@ -296,8 +591,44 @@ void PassageMainWindow::connectAction() connect(this->imageFormat, SIGNAL(triggered(bool)), this, SLOT(imageDialog())); //修改图片 - connect(this->area, SIGNAL(subWindowActivated(QMdiSubWindow*)), - this->connector, SLOT(updateActivePassage(QMdiSubWindow*))); // 检测ActivePassage更新 + // 设置表格 + connect(this->tableFormat, SIGNAL(triggered(bool)), + this, SLOT(tableSetting())); + + connect(this->boldAction, SIGNAL(triggered(bool)), + this,SLOT(Bold())); // 加粗 + + connect(this->italicAction, SIGNAL(triggered(bool)), + this,SLOT(Italic())); // 斜体 + + connect(this->underlineAction, SIGNAL(triggered(bool)), + this,SLOT(underline())); // 下划线 + + // 切换文章 + connect(this->tabArea, SIGNAL(currentChanged(int)), + this, SLOT(changeCurrentPassage(int))); + + connect(this, SIGNAL(updateActivedPassage(DocPassage*)), + this->connector, SLOT(updateActivePassage(DocPassage*))); + + // 关闭文章 + connect(this->tabArea, SIGNAL(tabCloseRequested(int)), + this, SLOT(closePassageRequest(int))); + + // 切换为编辑模式 + connect(this->editModeAction, SIGNAL(triggered(bool)), + this, SLOT(switchToEditMode())); + + // 切换为阅读模式 + connect(this->viewModeAction, SIGNAL(triggered(bool)), + this, SLOT(switchToViewMode())); + + // 字体选择 + connect(this->fontCombox, SIGNAL(currentFontChanged(QFont)), + this, SLOT(slots_setFont(QFont))); + // 对其样式 + connect(this->alignGroup, SIGNAL(triggered(QAction*)), + this, SLOT(slots_selectAlign(QAction*))); } /** @@ -312,6 +643,192 @@ void PassageMainWindow::disconnectAction() } +void PassageMainWindow::slots_selectAlign(QAction *action) +{ + Qt::Alignment alignment; + if(action == this->leftAction) + { + alignment = Qt::AlignLeft; + } + else if(action == this->rightAction) + { + alignment = Qt::AlignRight; + } + else if(action == this->middleAction) + { + alignment = Qt::AlignHCenter; + } + else if(action == this->justifyAction) + { + alignment = Qt::AlignJustify; + } + + if(this->textBlock) + { + QTextBlockFormat blockFormat; + blockFormat.setAlignment(alignment); + this->textBlock->mergeBlockFormatOnBlock(blockFormat); + } + else if(this->tableBlock) + { + QTextBlockFormat blockFormat; + blockFormat.setAlignment(alignment); + this->tableBlock->mergeBlockFormatOnBlock(blockFormat); + } +} + +/// +/// \brief PassageMainWindow::slots_setFont +/// 快速设定字体 +/// \param font +/// +void PassageMainWindow::slots_setFont(const QFont &font) +{ + if(this->textBlock != NULL) + { + this->textBlock->setFont(font.family()); + } + else if(this->tableBlock != NULL) + { + this->tableBlock->setFont(font.family()); + } +} + +/** + * @Author Chaoqun + * @brief 找到当前活跃的textblock,加粗 + * @param void + * @return void + * @date 2017/06/27 + */ +void PassageMainWindow::Bold() +{ + if(this->textBlock !=NULL) + { + this->textBlock->textBold(); // 加粗 + } +} + +void PassageMainWindow::Italic() +{ + if(this->textBlock != NULL) + { + this->textBlock->textItalic(); // 斜体 + } +} + +void PassageMainWindow::underline() +{ + if(this->textBlock != NULL) + { + this->textBlock->textUnderline(); // 下划线 + } +} + +/// +/// \brief PassageMainWindow::printPassage +/// 弹出打印机设置 +/// +void PassageMainWindow::printPassage() +{ + QPrinter printer(QPrinter::HighResolution); + QPrintDialog printDialog(&printer, this); + + printDialog.setOptions(QAbstractPrintDialog::PrintToFile + | QAbstractPrintDialog::PrintSelection + | QAbstractPrintDialog::PrintPageRange + | QAbstractPrintDialog::PrintShowPageSize + | QAbstractPrintDialog::PrintCollateCopies + | QAbstractPrintDialog::PrintCurrentPage); + + DocPassage* passage = this->activedPassage(); + printDialog.setMinMax(1,passage->pageCount()); + + if(printDialog.exec() == QDialog::Accepted) + { + // 接受打印机设置 -- 全部打印 + printer.setPageSize(QPrinter::A4); + QPainter painterPixmap; + painterPixmap.begin(&printer); + + for(int i =0; i < passage->pageCount(); i++) + { + QPixmap pixmap = QPixmap::grabWidget( + passage->getPage(i)); + + // 调整比例 + QRect rect = painterPixmap.viewport(); + QSize size = passage->getPage(i)->size(); + size.scale(rect.size(), Qt::KeepAspectRatio); //此处保证图片显示完整 + painterPixmap.setViewport(rect.x(), rect.y(), + size.width(), size.height()); + painterPixmap.setWindow(passage->getPage(i)->rect()); + painterPixmap.drawPixmap(0,0,pixmap); + + // 防止多增加一页 + if(i != passage->pageCount() - 1) + printer.newPage(); + + } + + painterPixmap.end(); + + } +} + +void PassageMainWindow::undo() +{ + if(this->textBlock != NULL) + { + this->textBlock->undo(); + } + else if(this->tableBlock != NULL) + { + this->tableBlock->undo(); + } +} + +void PassageMainWindow::redo() +{ + + if(this->textBlock != NULL) + { + this->textBlock->redo(); + } + else if(this->tableBlock != NULL) + { + this->tableBlock->redo(); + } +} + +/** + * @Author Chaoqun + * @brief 放大函数 + * @param void + * @return void + * @date 2017/06/27 + */ +void PassageMainWindow::zoomIn() +{ + DocPassage* passage = this->activedPassage(); + passage->zoomIn(); +} + +/** + * @Author Chaoqun + * @brief 缩小函数/ + * @param void + * @return void + * @date 2017/06/27 + */ +void PassageMainWindow::zooomOut() +{ +// DocPage* page = this->connector->getActivePage(); +// page->scale(0.5,0.5); + DocPassage* passage = this->activedPassage(); + passage->zoomOut(); +} + /** * @Author Chaoqun * @brief 打开 *.ofd 文件 @@ -334,24 +851,126 @@ void PassageMainWindow::openFile() QString path = fileDialog->selectedFiles()[0]; // 用户选择文件名 qDebug() << path; - ZipTool zipTool; - QString tempPath = zipTool.FilePathToFloderPath(path); - qDebug() << "Temp path is :" << tempPath; + this->openFile(path); // 调用打开文件 - ZipTool::extractDir(path,tempPath); // 解压到临时文件夹 + } +} - // 解读文件 -// OFDParser ofdParser("C:\\Users\\User\\AppData\\Local\\Temp\\%表格.ofd%\\OFD.xml"); - OFDParser ofdParser(tempPath + "/OFD.xml"); // 新建临时路径 -// OFDParser ofdParser("C:/Users/User/Desktop/表格/OFD.xml"); - OFD* data = ofdParser.getData(); // 读取出OFD文件 - qDebug()<< "ofd file open"; - OFD_DocConvertor convert; - DocPassage* passage = convert.ofd_to_doc(data); +/** + * @Author Chaoqun + * @brief 文件保存测试 + * @param void + * @return void + * @date 2017/06/25 + */ +void PassageMainWindow::saveFile() +{ + + DocPassage* passage = this->activedPassage(); + if(passage == NULL) + { + qDebug() << "Select NULL Passage"; + return; + } + QString filePath = passage->getFilePath(); // 获得文件路径 + if(filePath.size() == 0) + { + qDebug() << "passage filePath == 0"; + this->saveFileAs(); // 如果文件名不存在则使用另存为 + + return; + } + + passage->updateEditTime(); // 更新文件修改日期 + this->addRecentFile(passage); // 添加到最近打开的文件列表 + + Doc_OFDConvertor docToOfd; + OFD* ofdFile = docToOfd.doc_to_ofd(passage); - this->addDocPassage(passage); // 添加文章 + QString tempPath = passage->getTempStorePath(); + QDir dir; + if(dir.exists(tempPath)) + { + qDebug() << "the file is existing"; + // 如果文件夹已存在则要删除该文件夹 + ZipTool::deleteFolder(tempPath); // 删除文件夹 + } + dir.mkdir(tempPath); // 生成文件夹 + OFDWriter writer(ofdFile, tempPath+"/"); // 写出文件 + writer.setTempPath(passage->getTempSavePath()); // 保存着图片的临时路径 + writer.writeOFD(); + + ZipTool::compressDir(filePath, + tempPath); // 将文件夹压缩为指定文件 + +} + +/// +/// \brief PassageMainWindow::saveFileAs +/// 另存为文件 +/// 先判断文件是否可以 +/// 弹出文件对话框 +/// 保存文件 +/// +void PassageMainWindow::saveFileAs() +{ + // 检查文档 + DocPassage* passage = this->connector->getActivePassage(); + if(passage == NULL) + { + qDebug() << "Select NULL Passage"; + return; } + passage->updateEditTime(); + + // 弹出保存文件对话框 + QFileDialog * fileDialog = new QFileDialog(this); // 新建一个QFileDialog + + fileDialog->setAcceptMode(QFileDialog::AcceptSave); // 设置对话框为保存文件类型 + fileDialog->setFileMode(QFileDialog::AnyFile); // 设置文件对话框能够显示任何文件 + fileDialog->setViewMode(QFileDialog::Detail); // 文件以细节形式显示出来 + fileDialog->setWindowTitle(tr("Save the passage content as a ofd file")); + + fileDialog->setNameFilter(tr("OFD files(*.ofd)")); // 设置文件过滤器 + if(fileDialog->exec() == QDialog::Accepted) + { + QString path = fileDialog->selectedFiles()[0]; // 用户选择文件名 + + Doc_OFDConvertor docToOfd; + OFD* ofdFile = docToOfd.doc_to_ofd(passage); + + QString tempPath = passage->getTempStorePath(); + QDir dir; + if(dir.exists(tempPath)) + { + qDebug() << "the file is existing"; + // 如果文件夹已存在则要删除该文件夹 + ZipTool::deleteFolder(tempPath); // 删除文件夹 + } + + dir.mkdir(tempPath); // 生成文件夹 + OFDWriter writer(ofdFile, tempPath + "/"); // 写出文件 + writer.setTempPath(passage->getTempSavePath()); + writer.writeOFD(); + + qDebug() << "temp Files Path:" << tempPath; + qDebug() << "selected ofd"<< path; + + bool flag = ZipTool::compressDir(path, + tempPath, false); // 将文件夹压缩为指定文件 + + if(flag == true) + { + passage->setFilePath(path); // 设置文件路径 + this->addRecentFile(passage); // 添加到最近文件 + } + else + { + qDebug() << "Save File Failed"; + } + } + } /** @@ -365,6 +984,8 @@ void PassageMainWindow::fontDialog() { if (textBlock) this->textBlock->customFontDialog(); // 用自定义窗口修改字体 + else if(this->tableBlock) + this->tableBlock->customFontDialog(); } /** @@ -378,6 +999,8 @@ void PassageMainWindow::paragraphDialog() { if (textBlock) this->textBlock->textParagraph(); // 用自定义段落窗口修改段落 + else if(this->tableBlock) + this->tableBlock->customFontDialog(); } void PassageMainWindow::imageDialog() @@ -386,6 +1009,32 @@ void PassageMainWindow::imageDialog() this->imageBlock->setImageProperties(); } +void PassageMainWindow::pageDialog() +{ + DocPassage * passage = activedPassage(); + if (passage) + { + passage->activatePageDialog(); + } + else + { + qDebug() << "No active DocPassage."; + } +} + +void PassageMainWindow::templateDialog() +{ + this->select_template_dialog->exec(); +} + +void PassageMainWindow::tableSetting() +{ + if(this->tableBlock != NULL) + { + this->tableBlock->tableSetting(); + } +} + /** * @Author Chaoqun * @brief 接受当前处理的文字块的更新 @@ -397,6 +1046,7 @@ void PassageMainWindow::acceptTextBlock(DocTextBlock *textBlock) { this->textBlock = textBlock; // 修改引用 this->imageBlock = NULL; + this->tableBlock = NULL; } /** @@ -406,11 +1056,44 @@ void PassageMainWindow::acceptTextBlock(DocTextBlock *textBlock) * @return void * @date 2017/06/23 */ -void PassageMainWindow::acceptTextBlockFormat(QTextBlockFormat &blockFormat) +void PassageMainWindow::acceptTextBlockFormat(QTextBlockFormat blockFormat) { - this->_currentBlockFormat = &blockFormat; // 留下引用 + this->_currentBlockFormat = blockFormat; // 留下引用 + qDebug() << "PassageMainWindow::acceptTextBlockFormat(QTextBlockFormat blockFormat)"; // 更新界面显示 + Qt::Alignment align = blockFormat.alignment() & Qt::AlignHorizontal_Mask; + switch (align) + { + case Qt::AlignHCenter: + this->middleAction->setChecked(true); + this->leftAction->setChecked(false); + this->rightAction->setChecked(false); + this->justifyAction->setChecked(false); + break; + case Qt::AlignLeft: + this->middleAction->setChecked(false); + this->leftAction->setChecked(true); + this->rightAction->setChecked(false); + this->justifyAction->setChecked(false); + break; + case Qt::AlignRight: + this->middleAction->setChecked(false); + this->leftAction->setChecked(false); + this->rightAction->setChecked(true); + this->justifyAction->setChecked(false); + break; + case Qt::AlignJustify: + this->middleAction->setChecked(false); + this->leftAction->setChecked(false); + this->rightAction->setChecked(false); + this->justifyAction->setChecked(true); + break; + default: + break; + } + + } /** @@ -420,30 +1103,414 @@ void PassageMainWindow::acceptTextBlockFormat(QTextBlockFormat &blockFormat) * @return void * @date 2017/06/23 */ -void PassageMainWindow::acceptTextCharFormat(QTextCharFormat &charFormat) +void PassageMainWindow::acceptTextCharFormat(QTextCharFormat charFormat) { - this->_currentCharFormat = &charFormat; // 留下引用 + this->_currentCharFormat = charFormat; // 留下引用 // 更新界面显示 + + // 字体 + this->fontCombox->setCurrentFont(charFormat.font()); + + // 粗体 + if(charFormat.fontWeight() >= 75) + { + this->boldAction->setChecked(true); + } + else + { + this->boldAction->setChecked(false); + } + + // 斜体 + if(charFormat.fontItalic()) + { + this->italicAction->setChecked(true); + } + else + { + this->italicAction->setChecked(false); + } + + // 下划线 + if(charFormat.fontUnderline()) + { + this->underlineAction->setChecked(true); + } + else + { + this->underlineAction->setChecked(false); + } + + // 字号 } void PassageMainWindow::acceptImageBlock(DocImageBlock *imageBlock) { this->imageBlock = imageBlock; this->textBlock = NULL; + this->tableBlock = NULL; } -/** - * @Author Chaoqun - * @brief 获取激活的窗口 - * @param void - * @return DocPassage * - * @date 2017/05/13 - */ -DocPassage *PassageMainWindow::activeMdiChild() +void PassageMainWindow::acceptTableBlock(DocTable *table) +{ + this->tableBlock = table; + this->textBlock = NULL; + this->imageBlock = NULL; +} + +void PassageMainWindow::switchToEditMode() +{ + this->viewModeAction->setChecked(false); + this->editModeAction->setChecked(true); + + this->isEditable = true; + emit this->setEditable(this->isEditable); +} + +void PassageMainWindow::switchToViewMode() +{ + this->editModeAction->setChecked(false); + this->viewModeAction->setChecked(true); + + this->isEditable = false; + emit this->setEditable(this->isEditable); +} + +/// +/// \brief PassageMainWindow::changeCurrentPassage +/// 切换当前操作文档 +/// \param index +/// +void PassageMainWindow::changeCurrentPassage(int index) +{ + qDebug() << "index " << index; + if(index == -1) + { + // 如果没有则返回 NULL + emit updateActivedPassage(NULL); + return; + } + + emit updateActivedPassage( + qobject_cast( + this->tabArea->widget(index))); + + qobject_cast( + this->tabArea->widget(index))->testMessage(); +} + +/// +/// \brief PassageMainWindow::closePassageRequest +/// 关闭文件时需要处理的事情: +/// 1. 是否需要提示(保存文件) +/// 2. 是否需要更新最近打开文档 +/// 3. 只有全部处理好的,才可以关闭该选项 +/// \param index +/// +void PassageMainWindow::closePassageRequest(int index) { - if (QMdiSubWindow *activeSubWindow = this->area->activeSubWindow()) - return qobject_cast(activeSubWindow->widget()); - return 0; + + + this->tabArea->removeTab(index); + + if(this->tabArea->count() == 0) + { + RecentFiles* recentWidget = RecentFiles::getInstance(); + recentWidget->init(); + this->tabArea->addTab(recentWidget,tr("Welcome!")); + } +} + +/// +/// \brief PassageMainWindow::setStatusMessage +/// \param msg +/// 在状态栏中显示信息 +/// +void PassageMainWindow::setStatusMessage(QString msg) +{ + +} + +void PassageMainWindow::createTemplatePassage(int index) +{ + qDebug() << "???"; + DocPassage * new_passage = new DocPassage(); + //********************************************** + DocPage * new_page_1 = new DocPage(); + + new_passage->addPage(new_page_1); + //*********************************************** + QFont font1("SimHei", 15); + font1.setBold(false); + DocTextBlock * headtext_1 = new DocTextBlock(); + DocBlock * head_1 = new DocBlock(); + head_1->setWidget(headtext_1); + headtext_1->setContent("000001"); + head_1->setPos(UnitTool::mmToPixel(28), UnitTool::mmToPixel(37)); + head_1->resize(80, 30); + headtext_1->setFont(font1); + new_page_1->addBlock(head_1, DocPage::Body); + + DocTextBlock * headtext_2 = new DocTextBlock(); + DocBlock * head_2 = new DocBlock(); + head_2->setWidget(headtext_2); + headtext_2->setContent(tr("JiMi 1Nian")); + head_2->setPos(UnitTool::mmToPixel(28), UnitTool::mmToPixel(47)); + head_2->resize(120, 30); + headtext_2->setFont(font1); + new_page_1->addBlock(head_2, DocPage::Body); + + DocTextBlock * headtext_3 = new DocTextBlock(); + DocBlock * head_3 = new DocBlock(); + head_3->setWidget(headtext_3); + headtext_3->setContent(tr("Te Ji")); + head_3->setPos(UnitTool::mmToPixel(28), UnitTool::mmToPixel(57)); + head_3->resize(50, 30); + headtext_3->setFont(font1); + new_page_1->addBlock(head_3, DocPage::Body); + + QFont font2("SimSun", 43); + font2.setBold(true); + DocTextBlock * titletext_1 = new DocTextBlock(); + DocBlock * title_1 = new DocBlock(); + title_1->setWidget(titletext_1); + + titletext_1->setAlignment(Qt::AlignCenter); + title_1->setPos(UnitTool::mmToPixel(41), UnitTool::mmToPixel(73)); + title_1->resize(500, 80); + titletext_1->setFont(font2); + QTextCharFormat fmt; + fmt.setForeground(Qt::red); + titletext_1->mergeCurrentCharFormat(fmt); + titletext_1->setContent(tr("XXXXXWenJian")); + new_page_1->addBlock(title_1, DocPage::Body); + + QFont font3("FangSong", 15); + font3.setBold(false); + DocTextBlock * titletext_2 = new DocTextBlock(); + DocBlock * title_2 = new DocBlock(); + title_2->setWidget(titletext_2); + + titletext_2->setAlignment(Qt::AlignCenter); + title_2->setPos(UnitTool::mmToPixel(75), UnitTool::mmToPixel(104)); + title_2->resize(220, 35); + titletext_2->setFont(font3); + + titletext_2->setContent(tr("XXX[2012]10Hao")); + new_page_1->addBlock(title_2, DocPage::Body); + + QFont font4("SimSun", 27); + font4.setBold(false); + DocTextBlock * bodytext_1 = new DocTextBlock(); + DocBlock * body_1 = new DocBlock(); + body_1->setWidget(bodytext_1); + + bodytext_1->setAlignment(Qt::AlignCenter); + body_1->setPos(UnitTool::mmToPixel(40), UnitTool::mmToPixel(128)); + body_1->resize(500, 50); + bodytext_1->setFont(font4); + + bodytext_1->setContent(tr("XXXXXGuanYuXXXXXXDeTongZhi")); + new_page_1->addBlock(body_1, DocPage::Body); + + QFont font5("FangSong", 22); + font5.setBold(false); + DocTextBlock * bodytext_2 = new DocTextBlock(); + DocBlock * body_2 = new DocBlock(); + body_2->setWidget(bodytext_2); + + bodytext_2->setAlignment(Qt::AlignLeft); + body_2->setPos(UnitTool::mmToPixel(28), UnitTool::mmToPixel(150)); + body_2->resize(250, 35); + bodytext_2->setFont(font5); + + bodytext_2->setContent(tr("XXXXXXXX:")); + new_page_1->addBlock(body_2, DocPage::Body); + + DocTextBlock * bodytext_3 = new DocTextBlock(); + DocBlock * body_3 = new DocBlock(); + body_3->setWidget(bodytext_3); + + bodytext_3->setAlignment(Qt::AlignLeft); + body_3->setPos(UnitTool::mmToPixel(28), UnitTool::mmToPixel(160)); + body_3->resize(600, 400); + bodytext_3->setFont(font5); + + bodytext_3->setContent(tr("OOOOXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX." + "\nOOOOXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXX.\nOOOOXXXXXXXXX" + "XXXXXXXXXXXXX.\nOOOOXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")); + new_page_1->addBlock(body_3, DocPage::Body); + //*********************************************** + DocPage * new_page_2 = new DocPage(); + + new_passage->addPage(new_page_2); + //*********************************************** + DocTextBlock * bodytext_4 = new DocTextBlock(); + DocBlock * body_4 = new DocBlock(); + body_4->setWidget(bodytext_4); + + bodytext_4->setAlignment(Qt::AlignLeft); + body_4->setPos(UnitTool::mmToPixel(28), UnitTool::mmToPixel(37)); + body_4->resize(600, 200); + bodytext_4->setFont(font5); + + bodytext_4->setContent(tr("XXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX." + "\nOOOOXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXX.")); + new_page_2->addBlock(body_4, DocPage::Body); + + DocTextBlock * bodytext_5 = new DocTextBlock(); + DocBlock * body_5 = new DocBlock(); + body_5->setWidget(bodytext_5); + + bodytext_5->setAlignment(Qt::AlignCenter); + body_5->setPos(UnitTool::mmToPixel(120), UnitTool::mmToPixel(85)); + body_5->resize(200, 35); + bodytext_5->setFont(font5); + + bodytext_5->setContent(tr("XXXXXXXXXXXX")); + new_page_2->addBlock(body_5, DocPage::Body); + + QFont font6("FangSong", 16); + DocTextBlock * bodytext_6 = new DocTextBlock(); + DocBlock * body_6 = new DocBlock(); + body_6->setWidget(bodytext_6); + + bodytext_6->setAlignment(Qt::AlignCenter); + body_6->setPos(UnitTool::mmToPixel(120), UnitTool::mmToPixel(108)); + body_6->resize(200, 35); + bodytext_6->setFont(font6); + + bodytext_6->setContent(tr("2012Nian7Yue1Ri")); + new_page_2->addBlock(body_6, DocPage::Body); + + DocTextBlock * bodytext_7 = new DocTextBlock(); + DocBlock * body_7 = new DocBlock(); + body_7->setWidget(bodytext_7); + + bodytext_7->setAlignment(Qt::AlignCenter); + body_7->setPos(UnitTool::mmToPixel(34), UnitTool::mmToPixel(108)); + body_7->resize(250, 35); + bodytext_7->setFont(font5); + + bodytext_7->setContent(tr("(XXXXXX)")); + new_page_2->addBlock(body_7, DocPage::Body); + + DocTextBlock * endtext_1 = new DocTextBlock(); + DocBlock * end_1 = new DocBlock(); + end_1->setWidget(endtext_1); + + endtext_1->setAlignment(Qt::AlignLeft); + end_1->setPos(UnitTool::mmToPixel(30), UnitTool::mmToPixel(230)); + end_1->resize(600, 35); + endtext_1->setFont(font6); + + endtext_1->setContent(tr("ChaoSong:XXXXXXX,XXXXX,XXXXXX")); + new_page_2->addBlock(end_1, DocPage::Body); + + DocTextBlock * endtext_2 = new DocTextBlock(); + DocBlock * end_2 = new DocBlock(); + end_2->setWidget(endtext_2); + + endtext_2->setAlignment(Qt::AlignLeft); + end_2->setPos(UnitTool::mmToPixel(30), UnitTool::mmToPixel(240)); + end_2->resize(250, 35); + endtext_2->setFont(font6); + + endtext_2->setContent(tr("XXXXXXXX")); + new_page_2->addBlock(end_2, DocPage::Body); + + DocTextBlock * endtext_3 = new DocTextBlock(); + DocBlock * end_3 = new DocBlock(); + end_3->setWidget(endtext_3); + + endtext_3->setAlignment(Qt::AlignCenter); + end_3->setPos(UnitTool::mmToPixel(110), UnitTool::mmToPixel(240)); + end_3->resize(300, 35); + endtext_3->setFont(font6); + + endtext_3->setContent(tr("2012Nian7Yue1RiYinFa")); + new_page_2->addBlock(end_3, DocPage::Body); + + DocImageBlock * line = new DocImageBlock(); + DocBlock * line_block = new DocBlock(); + line_block->setWidget(line); + line->setPixmap(QPixmap(":/icons/source/red_line.png")); + line_block->setPos(UnitTool::mmToPixel(28), UnitTool::mmToPixel(114)); + line_block->resize(580, 3); + new_page_1->addBlock(line_block, DocPage::Body); + + addDocPassage(new_passage); + +} + +/// +/// \brief PassageMainWindow::openFile +/// 打开文件 +/// \param filePath +/// +void PassageMainWindow::openFile(QString filePath) +{ + + QFile qfile; + qfile.setFileName(filePath); + if(!qfile.exists()) + { + // 如果文件不存在,则中断程序 + return; + } + + ZipTool zipTool; + QString tempPath = zipTool.FilePathToFloderPath(filePath); + qDebug() << "Temp path is :" << tempPath; + + ZipTool::extractDir(filePath,tempPath); // 解压到临时文件夹 + + // 解读文件 +// OFDParser ofdParser("C:\\Users\\User\\AppData\\Local\\Temp\\%表格.ofd%\\OFD.xml"); + OFDParser ofdParser(tempPath + "/OFD.xml"); // 新建临时路径 +// OFDParser ofdParser("C:/Users/User/Desktop/表格/OFD.xml"); + OFD* data = ofdParser.getData(); // 读取出OFD文件 + qDebug()<< "ofd file open" << tempPath + "/OFD.xml"; + OFD_DocConvertor convert; + DocPassage* passage = convert.ofd_to_doc(data); + passage->setFilePath(filePath); // 设置文件路径 + + this->addRecentFile(passage); // 添加到最近文件 + this->addDocPassage(passage); // 添加文章 +} + +/// +/// \brief PassageMainWindow::closeEvent +/// 关闭时要检查是否有文档需要保存,有需要保存的时候,要终止关闭窗口 +/// 1.关闭可以关闭的文档 +/// 2.一个一个提醒还没有保存的文档 +/// 3.全部完成后才可以关闭窗口 +/// \param event +/// +void PassageMainWindow::closeEvent(QCloseEvent *event) +{ + +} + +/// +/// \brief PassageMainWindow::createEmptyPassage +/// 创建一个空的文章 +/// \return +/// +DocPassage *PassageMainWindow::createEmptyPassage() +{ + DocPassage* child = new DocPassage(); // 新建文章 + child->addPage(new DocPage()); // 增加空白页面 + + this->addDocPassage(child); // 添加页面 + return child; } /** @@ -461,24 +1528,80 @@ DocPassage *PassageMainWindow::addDocPassage(DocPassage *passage) return NULL; } - this->area->addSubWindow(passage); // 插入子窗口 + this->tabArea->addTab( + passage, + passage->getFilePath().section('/',-1)); + this->tabArea->setCurrentIndex( + this->tabArea->count() - 1); this->connector->setDocPassage(passage); // 设置引用 passage->setVisible(true); // 设置可见 passage->showMaximized(); // 处理变更的blockFormat - this->connect(passage,SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat&)), - this,SLOT(acceptTextBlockFormat(QTextBlockFormat&))); + this->connect(passage,SIGNAL(signals_currentBlockFormatChanged(QTextBlockFormat)), + this,SLOT(acceptTextBlockFormat(QTextBlockFormat))); // 处理变更的charFormat - this->connect(passage,SIGNAL(signals_currentCharFormatChanged(QTextCharFormat&)), - this,SLOT(acceptTextCharFormat(QTextCharFormat&))); + this->connect(passage,SIGNAL(signals_currentCharFormatChanged(QTextCharFormat)), + this,SLOT(acceptTextCharFormat(QTextCharFormat))); // 处理变更的textBlock this->connect(passage,SIGNAL(signals_currentTextBlock(DocTextBlock*)), this,SLOT(acceptTextBlock(DocTextBlock*))); //处理变更的imageBlock this->connect(passage, SIGNAL(signals_currentImageBlock(DocImageBlock*)), this, SLOT(acceptImageBlock(DocImageBlock*))); + + // 转发tableBlock + this->connect(passage, SIGNAL(signals_currentTableBlock(DocTable*)), + this, SLOT(acceptTableBlock(DocTable*))); + + this->connect(this, SIGNAL(setEditable(bool)), + passage, SIGNAL(signals_setEditable(bool))); // 转发设置可以编辑 + + emit this->setEditable(this->isEditable); + return passage; } +/// +/// \brief PassageMainWindow::disableButtons +/// 禁用掉无关按钮,适用于尚未打开文件的状态 +/// +void PassageMainWindow::disableButtons() +{ + +} + +/// +/// \brief PassageMainWindow::enableButtons +/// 开启所有按钮,适用于已经打开文件的状态 +void PassageMainWindow::enableButtons() +{ + +} + +/// +/// \brief PassageMainWindow::addRecentFile +/// 增加最近文件记录 +/// 打开文件、保存文件时调用 +/// \param passages +/// +void PassageMainWindow::addRecentFile(DocPassage *passages) +{ + + CT_DocInfo * info = passages->getDocInfo(); + QDateTime date = QDateTime::currentDateTime(); + + RecentFileList* list = RecentFileList::getInstance(); + RecentFileItem* item = new RecentFileItem( + passages->getFilePath().section('/',-1), + info->getAuthor(), + info->getModDate(), + date.toString("yyyy-MM-dd HH:mm:ss"), + passages->getFilePath() + ); + + list->addItem(item); + list->save(); // 保存到文件 +} + diff --git a/ofdEditor/start/ui/PassageMainWindow.h b/ofdEditor/start/ui/PassageMainWindow.h index 63c032e22aaacc162e32464896edcfb9cc12eb70..8a67f57d6e94d3fc60df2af535991bb3f4d6eae8 100644 --- a/ofdEditor/start/ui/PassageMainWindow.h +++ b/ofdEditor/start/ui/PassageMainWindow.h @@ -6,16 +6,19 @@ #include #include // 字体框 #include // 选择框 +#include +#include +#include // 标签页 +#include class QAction; class QMenu; -class QMdiArea; class DocPassage; class DocTextBlock; -class QTextCharFormat; -class QTextBlockFormat; class ActionConnector; // 函数功能的中间件 class DocImageBlock; +class SelectTemplateDialog; +class DocTable; // 编辑窗口的主界面 class PassageMainWindow @@ -23,14 +26,65 @@ class PassageMainWindow { Q_OBJECT public: + static PassageMainWindow* getInstance(); // 获得单例 + explicit PassageMainWindow(QWidget *parent = 0); ~PassageMainWindow(); + DocPassage * activedPassage(); // 获取获取当前激活的文档 + public slots: - DocPassage *createMdiChild(); // 创建一个新文档 - DocPassage *activeMdiChild(); // 获取活动的窗口 - DocPassage *addDocPassage(DocPassage * passage); + void activateFindAndReplaceDock(); // 激活查找替换窗口 + + DocPassage *createEmptyPassage(); // 创建一个空的文章 + DocPassage *addDocPassage(DocPassage * passage); // 加入一个文章标签页 + void disableButtons(); // 禁用掉无关的按钮 + void enableButtons(); // 开启所有按钮 + void addRecentFile(DocPassage* passages); // 增加最近文件记录 + + void createTemplatePassage(int index); + void openFile(QString filePath); // 打开文件 + void openFile(); // 打开新文件 + void saveFile(); // 保存文件测试 + void saveFileAs(); // 将文件另存为 + void fontDialog(); // 打开字体框 + void paragraphDialog(); // 打开段落框 + void imageDialog(); // 打开图片框 + void pageDialog(); // 打开页面框 + void templateDialog(); //打开模板选择 + void tableSetting(); // 打开表格设置 + + void Bold(); // 加粗事件 + void Italic(); // 斜体事件 + void underline(); // 下划线事件 + + void printPassage(); // 打印文章 + + void undo(); // 撤销 + void redo(); // 恢复 + + void zoomIn(); // 放大 + void zooomOut(); // 缩小 + + void acceptTextBlock(DocTextBlock* textBlock); // 接受当前处理的文字块的更新 + void acceptTextBlockFormat(QTextBlockFormat blockFormat); // 接受当前处理的块格式 + void acceptTextCharFormat(QTextCharFormat charFormat); // 接受当前处理的字符格式 + void acceptImageBlock(DocImageBlock * imageBlock); //接受当前处理的图片块 + void acceptTableBlock(DocTable* table); // 接受当前表格 + + void switchToEditMode(); //切换到编辑模式 + void switchToViewMode(); //切换到阅读模式 + + void changeCurrentPassage(int index); // 当活跃内容 切换为当前页面 + void closePassageRequest(int index); // 点击关闭时处理 + void setStatusMessage(QString msg); + +protected: + void closeEvent(QCloseEvent *event); // 关闭窗口时的响应事件 private: + static PassageMainWindow* m_instance; // 单例 + double scale; + bool isEditable; // 菜单栏 QMenu * filesMenu; // 文件 @@ -43,23 +97,30 @@ private: QToolBar* edit_toolBar; // 编辑 QToolBar* format_toolBar; // 格式 QToolBar* insert_toolBar; // 插入 - + QToolBar* textBlock_toolBar; // 文本工具栏 // QAction // 文件 QAction * newFileAction; // 新建文件 + QAction * templateAction; // 新建模板项目 QAction * openFileAtcion; // 打开文件 QAction * saveAction; // 保存 QAction * saveAsAction; // 另存为 QAction * printAction; // 打印 QAction * attributeAction; // 文档属性 + QAction * softwareSettingAction; // 软件设置 // 编辑 QAction * undoAction; // 撤销 QAction * redoAction; // 恢复操作 QAction * copyAction; // 复制 - QAction * cutAction; // 剪切 + QAction * cutAction; // 剪切 QAction * pasteAction; // 粘贴 + QAction * viewModeAction; // 阅读模式 + QAction * editModeAction; // 编辑模式 + QAction * zoomInAction; // 放大 + QAction * zoomOutAction; // 缩小 + QAction * find_and_replace; //查找和替换 // 插入 QAction * insertNewPageAction; // 插入新页面 @@ -79,11 +140,25 @@ private: QAction * aboutAppAction; // 关于本工程的介绍 QAction * helpAciton; // 帮助文档,如何使用本软件 - QMdiArea * area; // 多窗口区域 + + // 文本操作工具栏部分 + QFontComboBox* fontCombox; // 字体选择框 + QComboBox* fontSizeCombox; // 字体大小设置框 + QAction* boldAction; // 字体粗细 + QAction* italicAction; // 斜体 + QAction* underlineAction; // 下划线 + + QAction* middleAction; // 居中 + QAction* leftAction; // 居左 + QAction* rightAction; // 居右 + QAction* justifyAction; // 两端对齐 + QActionGroup *alignGroup; // 对齐选项组 + QVectorpassages; // 存储所有的passage - ActionConnector* connector; // 功能连接中间件 + QTabWidget* tabArea; // 使用标签页来表示多个文章 + ActionConnector* connector; // 功能连接中间件 void init(); // 初始化 void initAction(); // 初始化QAction @@ -91,22 +166,24 @@ private: void disconnectAction(); // 断开事件响应 DocTextBlock *textBlock; // 文字块 - QTextCharFormat* _currentCharFormat; // 当前字符格式 - QTextBlockFormat* _currentBlockFormat; // 当前块格式 + QTextCharFormat _currentCharFormat; // 当前字符格式 + QTextBlockFormat _currentBlockFormat; // 当前块格式 DocImageBlock *imageBlock; //图片块 + DocTable *tableBlock; // 表格块 + + SelectTemplateDialog * select_template_dialog; //选择模板对话框 + private slots: - void openFile(); // 打开新文件 - void fontDialog(); // 打开字体框 - void paragraphDialog(); // 打开段落框 - void imageDialog(); // 打开图片框 + void slots_selectAlign(QAction *action); + void slots_setFont( const QFont & font ); + +signals: + void updateActivedPassage(DocPassage * passage); // 更新当前操作的文档对象 + void setEditable(bool flag); // 设置是否可以编辑 - void acceptTextBlock(DocTextBlock* textBlock); // 接受当前处理的文字块的更新 - void acceptTextBlockFormat(QTextBlockFormat& blockFormat); // 接受当前处理的块格式 - void acceptTextCharFormat(QTextCharFormat& charFormat); // 接受当前处理的字符格式 - void acceptImageBlock(DocImageBlock * imageBlock); //接受当前处理的图片块 }; #endif // PASSAGEMAINWINDOW_H diff --git a/ofdEditor/start/ui/ProgramSettingDialog.cpp b/ofdEditor/start/ui/ProgramSettingDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..144f0a22e12a02bdba57d4da2f9cfbca40791aaf --- /dev/null +++ b/ofdEditor/start/ui/ProgramSettingDialog.cpp @@ -0,0 +1,14 @@ +#include "ProgramSettingDialog.h" +#include "ui_ProgramSettingDialog.h" + +ProgramSettingDialog::ProgramSettingDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ProgramSettingDialog) +{ + ui->setupUi(this); +} + +ProgramSettingDialog::~ProgramSettingDialog() +{ + delete ui; +} diff --git a/ofdEditor/start/ui/ProgramSettingDialog.h b/ofdEditor/start/ui/ProgramSettingDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..a12d3f86fa4e36ed79648b2a0c3e428d5f5689cd --- /dev/null +++ b/ofdEditor/start/ui/ProgramSettingDialog.h @@ -0,0 +1,22 @@ +#ifndef PROGRAMSETTINGDIALOG_H +#define PROGRAMSETTINGDIALOG_H + +#include + +namespace Ui { +class ProgramSettingDialog; +} + +class ProgramSettingDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ProgramSettingDialog(QWidget *parent = 0); + ~ProgramSettingDialog(); + +private: + Ui::ProgramSettingDialog *ui; +}; + +#endif // PROGRAMSETTINGDIALOG_H diff --git a/ofdEditor/start/ui/ProgramSettingDialog.ui b/ofdEditor/start/ui/ProgramSettingDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..c6ebb8c48abcc20e1cd9e5dc710e61ede7a12638 --- /dev/null +++ b/ofdEditor/start/ui/ProgramSettingDialog.ui @@ -0,0 +1,81 @@ + + + ProgramSettingDialog + + + + 0 + 0 + 537 + 504 + + + + 程序设置 + + + + + + 0 + + + + 程序设置 + + + + + 默认页面设置 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ProgramSettingDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ProgramSettingDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ofdEditor/start/ui/RecentFiles.cpp b/ofdEditor/start/ui/RecentFiles.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fda7236029a327e789e247d844fca4c9551cd578 --- /dev/null +++ b/ofdEditor/start/ui/RecentFiles.cpp @@ -0,0 +1,167 @@ +#include "RecentFiles.h" +#include "ui_RecentFiles.h" +#include "Settings/RecentFileList.h" +#include "Settings/RecentFileItem.h" +#include "ui/PassageMainWindow.h" + +#include + +RecentFiles* RecentFiles::m_instance = NULL; // 初始化静态变量 + +/// +/// \brief RecentFiles::getInstance +/// \return +/// +RecentFiles *RecentFiles::getInstance() +{ + if(m_instance == NULL) + { + m_instance = new RecentFiles(); + } + + m_instance->init(); + return m_instance; +} + +/// +/// \brief RecentFiles::destroyInstance +/// +void RecentFiles::destroyInstance() +{ + m_instance = NULL; +} + +/// +/// \brief RecentFiles::init +/// 每次使用时的初始化函数,用来重新初始化界面 +/// +void RecentFiles::init() +{ + RecentFileList* recentlist = RecentFileList::getInstance(); // 获得最近文件 + recentlist->load(); // 更新最近文件列表 + + this->clear(); + + ui->recent_table->horizontalHeader()->setVisible(true); + + int length = recentlist->size(); // 获得有效的列表长度 + for(int i = length-1; i >= 0; i--) + { + this->appendItem(recentlist->item(i)); + } + +} + +RecentFiles::RecentFiles(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecentFiles) +{ + ui->setupUi(this); + // 最后一行自动适应宽度 + ui->recent_table->horizontalHeader()->setStretchLastSection(true); + ui->recent_table->horizontalHeader()->setResizeMode( + 0, QHeaderView::ResizeToContents); + ui->recent_table->horizontalHeader()->setResizeMode( + 1, QHeaderView::ResizeToContents); + ui->recent_table->horizontalHeader()->setResizeMode( + 2, QHeaderView::ResizeToContents); + ui->recent_table->horizontalHeader()->setResizeMode( + 3, QHeaderView::ResizeToContents); + ui->recent_table->horizontalHeader()->setResizeMode( + 4, QHeaderView::Stretch); + // 设置每次可以选取一行 + ui->recent_table->setSelectionBehavior(QAbstractItemView::SelectRows); + // 设置只可以单选 + ui->recent_table->setSelectionMode(QAbstractItemView::SingleSelection); + ui->recent_table->horizontalHeader()->setVisible(true); + + // 双击打开文件 + this->connect(ui->recent_table, SIGNAL(cellDoubleClicked(int,int)), + this, SLOT(selectOpenFile(int,int))); + + // 绑定打开文件信号 + PassageMainWindow* mainWindow = PassageMainWindow::getInstance(); + this->connect(this, SIGNAL(openFile(QString)), + mainWindow, SLOT(openFile(QString))); + + // 清空最近记录 + connect(ui->btn_cleanRecent, SIGNAL(released()), + this, SLOT(cleanRecentRecord())); + +} + +RecentFiles::~RecentFiles() +{ + delete ui; +} + +/// +/// \brief RecentFiles::appendItem +/// 追加一项 +/// \param item +/// +void RecentFiles::appendItem(RecentFileItem *item) +{ + int rows = ui->recent_table->rowCount(); // 共有多少行 + ui->recent_table->insertRow(rows); + + QTableWidgetItem* fileName = new QTableWidgetItem(); + QTableWidgetItem* author = new QTableWidgetItem(); + QTableWidgetItem* recentOpenTime = new QTableWidgetItem(); + QTableWidgetItem* recentEditTime = new QTableWidgetItem(); + QTableWidgetItem* filePath = new QTableWidgetItem(); + + fileName->setText(item->getFileName()); + author->setText(item->getAuthor()); + recentOpenTime->setText(item->getRecentOpenTime_str()); + recentEditTime->setText(item->getRecentEditTime_str()); + filePath->setText(item->getFilePath()); + + ui->recent_table->setItem(rows,0,fileName); + ui->recent_table->setItem(rows,1,author); + ui->recent_table->setItem(rows,2,recentOpenTime); + ui->recent_table->setItem(rows,3,recentEditTime); + ui->recent_table->setItem(rows,4,filePath); + +} + +/// +/// \brief RecentFiles::clear +/// 清空内容 +/// +void RecentFiles::clear() +{ +// ui->recent_table->clearContents(); // 清空内容 + int length = ui->recent_table->rowCount(); + for(int i = 0; i < length; i++) + { + ui->recent_table->removeRow(0); + } +} + +/// +/// \brief RecentFiles::selectOpenFile +/// 双击打开文件 +/// \param row +/// \param column +/// +void RecentFiles::selectOpenFile(int row, int column) +{ + QTableWidgetItem* filePath = ui->recent_table->item(row,4); + QString path = filePath->text(); // 获得路径信息 + + emit this->openFile(path); // 发出打开文件信号 + +} + + +/// +/// \brief RecentFiles::cleanRecentRecord +/// 与按钮绑定 +void RecentFiles::cleanRecentRecord() +{ + RecentFileList * list = RecentFileList::getInstance(); + list->clear(); + list->save(); + this->clear(); +} diff --git a/ofdEditor/start/ui/RecentFiles.h b/ofdEditor/start/ui/RecentFiles.h new file mode 100644 index 0000000000000000000000000000000000000000..56ae56e97f06e17f5ee10fa9dae5425861e6d677 --- /dev/null +++ b/ofdEditor/start/ui/RecentFiles.h @@ -0,0 +1,45 @@ +#ifndef RECENTFILES_H +#define RECENTFILES_H + +#include + +namespace Ui { +class RecentFiles; +} + +class RecentFileItem; // 最近文件项 + +/// +/// \brief The RecentFiles class +/// 程序初始打开后的关于最近文档的窗口 +/// +class RecentFiles + : public QWidget +{ + Q_OBJECT + +public: + static RecentFiles* getInstance(); // 获得单例 + static void destroyInstance(); // 销毁实例 + void init(); // 初始化 + +private: + explicit RecentFiles(QWidget *parent = 0); + ~RecentFiles(); + static RecentFiles* m_instance; // 单例 + + void appendItem(RecentFileItem* item); // 在显示界面上插入一项 + void clear(); // 清空列表 + +private: + Ui::RecentFiles *ui; // 界面文件 + +private slots: + void selectOpenFile(int row, int column); // 双击某行能够打开最近文件 + void cleanRecentRecord(); // 与按钮绑定,清空最近记录 + +signals: + void openFile(QString filePath); +}; + +#endif // RECENTFILES_H diff --git a/ofdEditor/start/ui/RecentFiles.ui b/ofdEditor/start/ui/RecentFiles.ui new file mode 100644 index 0000000000000000000000000000000000000000..a3b3f484a634f6656459808043c45e375a4fcd05 --- /dev/null +++ b/ofdEditor/start/ui/RecentFiles.ui @@ -0,0 +1,192 @@ + + + RecentFiles + + + + 0 + 0 + 650 + 521 + + + + Form + + + + + + 0 + + + + 最近打开的文档 + + + + + + + 0 + 0 + + + + + 宋体 + 14 + 50 + false + + + + Qt::LeftToRight + + + false + + + QFrame::Plain + + + 0 + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + false + + + Qt::DashLine + + + false + + + false + + + false + + + true + + + 150 + + + 50 + + + false + + + + New Row + + + + + 文件名 + + + + 14 + + + + + + 作者 + + + + 14 + + + + + + 最近打开时间 + + + + 14 + + + + + + 最近编辑时间 + + + + 14 + + + + + + 文件路径 + + + + 14 + + + + + + + + + + + + + + + + + 清空最近文件记录 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 新建文档 + + + + + + + + +