[ref]同步 public

This commit is contained in:
shi_jq 2025-03-12 16:06:06 +08:00
parent 2a20810d1a
commit 0305921c3e
67 changed files with 18122 additions and 51 deletions

View File

@ -0,0 +1,6 @@
#include "excellib.h"
ExcelLib::ExcelLib()
{
}

View File

@ -0,0 +1,51 @@
#-------------------------------------------------
#
# Project created by QtCreator 2018-02-09T13:26:54
#此处仅仅是简单将QtXlsx库封装
#-------------------------------------------------
QT -= gui
QT += core gui-private
TARGET = pub_excel
TEMPLATE = lib
DEFINES += QT_BUILD_XLSX_LIB
include($$PWD/xlsx/qtxlsx.pri)
exists($$PWD/../../common.pri) {
include($$PWD/../../common.pri)
}else {
error("FATAL error: connot find common.pri")
}
DEFINES += EXCELLIB_LIBRARY
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
INCLUDEPATH += $$PWD/../../include/public/pub_excel/xlsx \
$$PWD/../../include/public/pub_excel
SOURCES += \
excellib.cpp
HEADERS += \
$$PWD/../../include/public/pub_excel/excellib.h \
$$PWD/../../include/public/pub_excel/excellib_global.h
unix {
target.path = /usr/lib
INSTALLS += target
}

View File

@ -0,0 +1,75 @@
include($QT_INSTALL_DOCS/global/qt-html-templates-offline.qdocconf)
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtXlsx
description = Qt Xlsx Reference Documentation
url = http://qtxlsx.debao.me
version = $QT_VERSION
qhp.projects = QtXlsx
qhp.QtXlsx.file = qtxlsx.qhp
qhp.QtXlsx.namespace = me.debao.qtxlsx.$QT_VERSION_TAG
qhp.QtXlsx.virtualFolder = qtxlsx
qhp.QtXlsx.indexTitle = Qt Xlsx
qhp.QtXlsx.indexRoot =
qhp.QtXlsx.filterAttributes = qtxlsx $QT_VERSION qtrefdoc
qhp.QtXlsx.customFilters.Qt.name = QtXlsx $QT_VERSION
qhp.QtXlsx.customFilters.Qt.filterAttributes = qtxlsx $QT_VERSION
qhp.QtXlsx.subprojects = overviews classes qmltypes examples
qhp.QtXlsx.subprojects.overviews.title = Overview
qhp.QtXlsx.subprojects.overviews.indexTitle = Qt Xlsx
qhp.QtXlsx.subprojects.overviews.selectors = fake:page,group,module
qhp.QtXlsx.subprojects.classes.title = C++ Classes
qhp.QtXlsx.subprojects.classes.indexTitle = Qt Xlsx C++ Classes
qhp.QtXlsx.subprojects.classes.selectors = class fake:headerfile
qhp.QtXlsx.subprojects.classes.sortPages = true
qhp.QtXlsx.subprojects.examples.title = Examples
qhp.QtXlsx.subprojects.examples.indexTitle = Qt Xlsx Examples
qhp.QtXlsx.subprojects.examples.selectors = fake:example
tagfile = ../../../doc/qtxlsx/qtxlsx.tags
headerdirs += ..
sourcedirs += ..
exampledirs += ../../../examples/xlsx \
snippets/
# Specify the install path under QT_INSTALL_EXAMPLES
examplesinstallpath = xlsx
imagedirs += images
depends += qtcore qtdoc qtgui
HTML.footer = \
" </div>\n" \
" </div>\n" \
" </div>\n" \
" </div>\n" \
"</div>\n" \
"<div class=\"footer\">\n" \
" <div class=\"qt13a-copyright\" id=\"copyright\">\n" \
" <div class=\"qt13a-container\">\n" \
" <p>\n" \
" <acronym title=\"Copyright\">&copy;</acronym> 2013-2014 Debao Zhang. \n" \
" Documentation contributions included herein are the copyrights of\n" \
" their respective owners.</p>\n" \
" <p>\n" \
" The documentation provided herein is licensed under the terms of the\n" \
" <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU Free Documentation\n" \
" License version 1.3</a> as published by the Free Software Foundation.</p>\n" \
" <p>\n" \
" Documentation sources may be obtained from <a href=\"https://github.com/dbzhang800/QtXlsxWriter\">\n" \
" github.com/dbzhang800</a>.</p>\n" \
" <p>\n" \
" Qt and their respective logos are trademarks of Digia Plc \n" \
" in Finland and/or other countries worldwide. All other trademarks are property\n" \
" of their respective owners. <a title=\"Privacy Policy\"\n" \
" href=\"http://en.gitorious.org/privacy_policy/\">Privacy Policy</a></p>\n" \
" </div>\n" \
" </div>\n" \
"</div>\n" \

View File

@ -0,0 +1,8 @@
//! [0]
#include <QtXlsx>
//! [0]
//! [1]
#include <QtXlsx>
//! [1]

View File

@ -0,0 +1,3 @@
#! [1]
QT += xlsx
#! [1]

View File

@ -0,0 +1,8 @@
/*!
\group qtxlsx-examples
\title Qt Xlsx Examples
\brief Examples for the Qt Xlsx module
\ingroup all-examples
Qt Xlsx comes with the following examples:
*/

View File

@ -0,0 +1,72 @@
/****************************************************************************
** Copyright (c) 2013 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
/*!
\title Qt Xlsx
\page index.html
\brief Qt Xlsx provides functionality for handling .xlsx files.
The \l{Qt Xlsx C++ Classes}{Qt Xlsx Module} provides a set of classes to read and write Excel files. It doesn't require
Microsoft Excel and can be used in any platform that Qt5 supported. The library can be used to
\list
\li \l{Hello QtXlsx Example}{Generate a new .xlsx file from scratch}
\li \l{Extract Data Example}{Extract data from an existing .xlsx file}
\li Edit an existing .xlsx file
\endlist
\image xlsx_demo.gif
\table
\row
\li Source code: \li \l{https://github.com/dbzhang800/QtXlsxWriter}
\row
\li Issures: \li \l{https://github.com/dbzhang800/QtXlsxWriter/issues}
\row
\li License: \li MIT
\endtable
\section1 Getting Started
To include the definitions of the module's classes, using the following directive:
\code
#include <QtXlsx>
\endcode
To link against the module, add this line to your qmake .pro file:
\code
QT += xlsx
\endcode
More information can be found in \l{Qt Xlsx Build} page.
\section1 Related information
\list
\li \l{Qt Xlsx C++ Classes}
\li \l{Qt Xlsx Examples}
\endlist
*/

View File

@ -0,0 +1,36 @@
/****************************************************************************
** Copyright (c) 2013 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
/*!
\module QtXlsx
\title Qt Xlsx C++ Classes
\ingroup modules
\brief The Qt Xlsx module provides functionality for handling .xlsx files.
.xlsx is a zipped, XML-based file format developed by Microsoft for
representing spreadsheets.
*/

View File

@ -0,0 +1,83 @@
/*!
\page building
\title Qt Xlsx Build
\note QZipWriter and QZipReader which live in gui-private is used in
this library. For linux user, if your Qt is installed through package
manager tools such "apt-get", make sure that you have installed the Qt5
develop package *qtbase5-private-dev* ;
if you Qt is built from source by yourself,
or download from qt-project.org directly, nothing need to do.
\section1 Usage(1): Use Xlsx as Qt5's addon module
1. Download the source code from \l {https://github.com/dbzhang800/QtXlsxWriter/archive/master.zip} {github.com}.
2. Put the source code in any directory you like. At the toplevel directory run
\note Perl is needed in this step.
\code
qmake
make
make install
\endcode
The library, the header files, and others will be installed to your system.
3. Add following line to your qmake's project file:
\code
QT += xlsx
\endcode
4. Then, using Qt Xlsx in your code
\code
#include "xlsxdocument.h"
int main()
{
QXlsx::Document xlsx;
xlsx.write("A1", "Hello Qt!");
xlsx.saveAs("Test.xlsx");
return 0;
}
\endcode
\section1 Usage(2): Use source code directly
The package contains a qtxlsx.pri file that allows you to integrate
the component into applications that use qmake for the build step.
1. Download the source code from \l {https://github.com/dbzhang800/QtXlsxWriter/archive/master.zip} {github.com}
2. Put the source code in any directory you like. For example, 3rdparty:
\code
|-- project.pro
|-- ....
|-- 3rdparty\
| |-- qtxlsx\
| |
\endcode
3. Add following line to your qmake project file:
\code
include(3rdparty/qtxlsx/src/xlsx/qtxlsx.pri)
\endcode
\note If you like, you can copy all files from *src/xlsx* to your application's source path. Then add following line to your project file:
\code
include(qtxlsx.pri)
\endcode
\note If you do not use qmake, you need to define the following macro manually
\code
XLSX_NO_LIB
\endcode
4. Then, using Qt Xlsx in your code
*/

View File

@ -0,0 +1,86 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
QT += core gui gui-private
#!build_xlsx_lib:DEFINES += XLSX_NO_LIB
HEADERS += $$PWD/../../../include/public/pub_excel/xlsx/xlsxdocpropscore_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxdocpropsapp_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxrelationships_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxutility_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxsharedstrings_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcontenttypes_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxtheme_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxformat.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxworkbook.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxstyles_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxabstractsheet.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxabstractsheet_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxworksheet.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxworksheet_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxchartsheet.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxchartsheet_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxzipwriter_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxworkbook_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxformat_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxglobal.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxdrawing_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxzipreader_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxdocument.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxdocument_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcell.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcell_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxdatavalidation.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxdatavalidation_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcellreference.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcellrange.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxrichstring_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxrichstring.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxconditionalformatting.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxconditionalformatting_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcolor_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxnumformatparser_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxdrawinganchor_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxmediafile_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxabstractooxmlfile.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxabstractooxmlfile_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxchart.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxchart_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxsimpleooxmlfile_p.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcellformula.h \
$$PWD/../../../include/public/pub_excel/xlsx/xlsxcellformula_p.h
SOURCES += $$PWD/xlsxdocpropscore.cpp \
$$PWD/xlsxdocpropsapp.cpp \
$$PWD/xlsxrelationships.cpp \
$$PWD/xlsxutility.cpp \
$$PWD/xlsxsharedstrings.cpp \
$$PWD/xlsxcontenttypes.cpp \
$$PWD/xlsxtheme.cpp \
$$PWD/xlsxformat.cpp \
$$PWD/xlsxstyles.cpp \
$$PWD/xlsxworkbook.cpp \
$$PWD/xlsxabstractsheet.cpp \
$$PWD/xlsxworksheet.cpp \
$$PWD/xlsxchartsheet.cpp \
$$PWD/xlsxzipwriter.cpp \
$$PWD/xlsxdrawing.cpp \
$$PWD/xlsxzipreader.cpp \
$$PWD/xlsxdocument.cpp \
$$PWD/xlsxcell.cpp \
$$PWD/xlsxdatavalidation.cpp \
$$PWD/xlsxcellreference.cpp \
$$PWD/xlsxcellrange.cpp \
$$PWD/xlsxrichstring.cpp \
$$PWD/xlsxconditionalformatting.cpp \
$$PWD/xlsxcolor.cpp \
$$PWD/xlsxnumformatparser.cpp \
$$PWD/xlsxdrawinganchor.cpp \
$$PWD/xlsxmediafile.cpp \
$$PWD/xlsxabstractooxmlfile.cpp \
$$PWD/xlsxchart.cpp \
$$PWD/xlsxsimpleooxmlfile.cpp \
$$PWD/xlsxcellformula.cpp

View File

@ -0,0 +1,17 @@
TARGET = QtXlsx
TEMPLATE = lib
QMAKE_DOCS = $$PWD/doc/qtxlsx.qdocconf
load(qt_module)
CONFIG += build_xlsx_lib
include(qtxlsx.pri)
#Define this macro if you want to run tests, so more AIPs will get exported.
#DEFINES += XLSX_TEST
QMAKE_TARGET_COMPANY = "Debao Zhang"
QMAKE_TARGET_COPYRIGHT = "Copyright (C) 2013-2014 Debao Zhang <hello@debao.me>"
QMAKE_TARGET_DESCRIPTION = ".Xlsx file wirter for Qt5"

View File

@ -0,0 +1,119 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxabstractooxmlfile.h"
#include "xlsxabstractooxmlfile_p.h"
#include <QBuffer>
#include <QByteArray>
QT_BEGIN_NAMESPACE_XLSX
AbstractOOXmlFilePrivate::AbstractOOXmlFilePrivate(AbstractOOXmlFile *q, AbstractOOXmlFile::CreateFlag flag=AbstractOOXmlFile::F_NewFromScratch)
:relationships(new Relationships), flag(flag), q_ptr(q)
{
}
AbstractOOXmlFilePrivate::~AbstractOOXmlFilePrivate()
{
}
/*!
* \internal
*
* \class AbstractOOXmlFile
*
* Base class of all the ooxml part file.
*/
AbstractOOXmlFile::AbstractOOXmlFile(CreateFlag flag)
:d_ptr(new AbstractOOXmlFilePrivate(this, flag))
{
}
AbstractOOXmlFile::AbstractOOXmlFile(AbstractOOXmlFilePrivate *d)
:d_ptr(d)
{
}
AbstractOOXmlFile::~AbstractOOXmlFile()
{
if (d_ptr->relationships)
delete d_ptr->relationships;
delete d_ptr;
}
QByteArray AbstractOOXmlFile::saveToXmlData() const
{
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
saveToXmlFile(&buffer);
return data;
}
bool AbstractOOXmlFile::loadFromXmlData(const QByteArray &data)
{
QBuffer buffer;
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
return loadFromXmlFile(&buffer);
}
/*!
* \internal
*/
void AbstractOOXmlFile::setFilePath(const QString path)
{
Q_D(AbstractOOXmlFile);
d->filePathInPackage = path;
}
/*!
* \internal
*/
QString AbstractOOXmlFile::filePath() const
{
Q_D(const AbstractOOXmlFile);
return d->filePathInPackage;
}
/*!
* \internal
*/
Relationships *AbstractOOXmlFile::relationships() const
{
Q_D(const AbstractOOXmlFile);
return d->relationships;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,206 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxabstractsheet.h"
#include "xlsxabstractsheet_p.h"
#include "xlsxworkbook.h"
QT_BEGIN_NAMESPACE_XLSX
AbstractSheetPrivate::AbstractSheetPrivate(AbstractSheet *p, AbstractSheet::CreateFlag flag)
: AbstractOOXmlFilePrivate(p, flag)
{
type = AbstractSheet::ST_WorkSheet;
sheetState = AbstractSheet::SS_Visible;
}
AbstractSheetPrivate::~AbstractSheetPrivate()
{
}
/*!
\class AbstractSheet
\inmodule QtXlsx
\brief Base class for worksheet, chartsheet, etc.
*/
/*!
\enum AbstractSheet::SheetType
\value ST_WorkSheet
\value ST_ChartSheet
\omitvalue ST_DialogSheet
\omitvalue ST_MacroSheet
*/
/*!
\enum AbstractSheet::SheetState
\value SS_Visible
\value SS_Hidden
\value SS_VeryHidden User cann't make a veryHidden sheet visible in normal way.
*/
/*!
\fn AbstractSheet::copy(const QString &distName, int distId) const
Copies the current sheet to a sheet called \a distName with \a distId.
Returns the new sheet.
*/
/*!
* \internal
*/
AbstractSheet::AbstractSheet(const QString &name, int id, Workbook *workbook, AbstractSheetPrivate *d) :
AbstractOOXmlFile(d)
{
d_func()->name = name;
d_func()->id = id;
d_func()->workbook = workbook;
}
/*!
* Returns the name of the sheet.
*/
QString AbstractSheet::sheetName() const
{
Q_D(const AbstractSheet);
return d->name;
}
/*!
* \internal
*/
void AbstractSheet::setSheetName(const QString &sheetName)
{
Q_D(AbstractSheet);
d->name = sheetName;
}
/*!
* Returns the type of the sheet.
*/
AbstractSheet::SheetType AbstractSheet::sheetType() const
{
Q_D(const AbstractSheet);
return d->type;
}
/*!
* \internal
*/
void AbstractSheet::setSheetType(SheetType type)
{
Q_D(AbstractSheet);
d->type = type;
}
/*!
* Returns the state of the sheet.
*
* \sa isHidden(), isVisible(), setSheetState()
*/
AbstractSheet::SheetState AbstractSheet::sheetState() const
{
Q_D(const AbstractSheet);
return d->sheetState;
}
/*!
* Set the state of the sheet to \a state.
*/
void AbstractSheet::setSheetState(SheetState state)
{
Q_D(AbstractSheet);
d->sheetState = state;
}
/*!
* Returns true if the sheet is not visible, otherwise false will be returned.
*
* \sa sheetState(), setHidden()
*/
bool AbstractSheet::isHidden() const
{
Q_D(const AbstractSheet);
return d->sheetState != SS_Visible;
}
/*!
* Returns true if the sheet is visible.
*/
bool AbstractSheet::isVisible() const
{
return !isHidden();
}
/*!
* Make the sheet hiden or visible based on \a hidden.
*/
void AbstractSheet::setHidden(bool hidden)
{
Q_D(AbstractSheet);
if (hidden == isHidden())
return;
d->sheetState = hidden ? SS_Hidden : SS_Visible;
}
/*!
* Convenience function, equivalent to setHidden(! \a visible).
*/
void AbstractSheet::setVisible(bool visible)
{
setHidden(!visible);
}
/*!
* \internal
*/
int AbstractSheet::sheetId() const
{
Q_D(const AbstractSheet);
return d->id;
}
/*!
* \internal
*/
Drawing *AbstractSheet::drawing() const
{
Q_D(const AbstractSheet);
return d->drawing.data();
}
/*!
* Return the workbook
*/
Workbook *AbstractSheet::workbook() const
{
Q_D(const AbstractSheet);
return d->workbook;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,178 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxcell.h"
#include "xlsxcell_p.h"
#include "xlsxformat.h"
#include "xlsxformat_p.h"
#include "xlsxutility_p.h"
#include "xlsxworksheet.h"
#include "xlsxworkbook.h"
#include <QDateTime>
QT_BEGIN_NAMESPACE_XLSX
CellPrivate::CellPrivate(Cell *p) :
q_ptr(p)
{
}
CellPrivate::CellPrivate(const CellPrivate * const cp)
: value(cp->value), formula(cp->formula), cellType(cp->cellType)
, format(cp->format), richString(cp->richString), parent(cp->parent)
{
}
/*!
\class Cell
\inmodule QtXlsx
\brief The Cell class provides a API that is used to handle the worksheet cell.
*/
/*!
\enum Cell::CellType
\value BooleanType Boolean type
\value NumberType Number type, can be blank or used with forumula
\value ErrorType Error type
\value SharedStringType Shared string type
\value StringType String type, can be used with forumula
\value InlineStringType Inline string type
*/
/*!
* \internal
* Created by Worksheet only.
*/
Cell::Cell(const QVariant &data, CellType type, const Format &format, Worksheet *parent) :
d_ptr(new CellPrivate(this))
{
d_ptr->value = data;
d_ptr->cellType = type;
d_ptr->format = format;
d_ptr->parent = parent;
}
/*!
* \internal
*/
Cell::Cell(const Cell * const cell):
d_ptr(new CellPrivate(cell->d_ptr))
{
d_ptr->q_ptr = this;
}
/*!
* Destroys the Cell and cleans up.
*/
Cell::~Cell()
{
delete d_ptr;
}
/*!
* Return the dataType of this Cell
*/
Cell::CellType Cell::cellType() const
{
Q_D(const Cell);
return d->cellType;
}
/*!
* Return the data content of this Cell
*/
QVariant Cell::value() const
{
Q_D(const Cell);
return d->value;
}
/*!
* Return the style used by this Cell. If no style used, 0 will be returned.
*/
Format Cell::format() const
{
Q_D(const Cell);
return d->format;
}
/*!
* Returns true if the cell has one formula.
*/
bool Cell::hasFormula() const
{
Q_D(const Cell);
return d->formula.isValid();
}
/*!
* Return the formula contents if the dataType is Formula
*/
CellFormula Cell::formula() const
{
Q_D(const Cell);
return d->formula;
}
/*!
* Returns whether the value is probably a dateTime or not
*/
bool Cell::isDateTime() const
{
Q_D(const Cell);
if (d->cellType == NumberType && d->value.toDouble() >=0
&& d->format.isValid() && d->format.isDateTimeFormat()) {
return true;
}
return false;
}
/*!
* Return the data time value.
*/
QDateTime Cell::dateTime() const
{
Q_D(const Cell);
if (!isDateTime())
return QDateTime();
return datetimeFromNumber(d->value.toDouble(), d->parent->workbook()->isDate1904());
}
/*!
* Returns whether the cell is probably a rich string or not
*/
bool Cell::isRichString() const
{
Q_D(const Cell);
if (d->cellType != SharedStringType && d->cellType != InlineStringType
&& d->cellType != StringType)
return false;
return d->richString.isRichString();
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,259 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxcellformula.h"
#include "xlsxcellformula_p.h"
#include "xlsxutility_p.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
QT_BEGIN_NAMESPACE_XLSX
CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_)
:formula(formula_), type(type_), reference(ref_), ca(false), si(0)
{
//Remove the formula '=' sign if exists
if (formula.startsWith(QLatin1String("=")))
formula.remove(0,1);
else if (formula.startsWith(QLatin1String("{=")) && formula.endsWith(QLatin1String("}")))
formula = formula.mid(2, formula.length()-3);
}
CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other)
: QSharedData(other)
, formula(other.formula), type(other.type), reference(other.reference)
, ca(other.ca), si(other.si)
{
}
CellFormulaPrivate::~CellFormulaPrivate()
{
}
/*!
\class CellFormula
\inmodule QtXlsx
\brief The CellFormula class provides a API that is used to handle the cell formula.
*/
/*!
\enum CellFormula::FormulaType
\value NormalType
\value ArrayType
\value DataTableType
\value SharedType
*/
/*!
* Creates a new formula.
*/
CellFormula::CellFormula()
{
//The d pointer is initialized with a null pointer
}
/*!
* Creates a new formula with the given \a formula and \a type.
*/
CellFormula::CellFormula(const char *formula, FormulaType type)
:d(new CellFormulaPrivate(QString::fromLatin1(formula), CellRange(), type))
{
}
/*!
* Creates a new formula with the given \a formula and \a type.
*/
CellFormula::CellFormula(const QString &formula, FormulaType type)
:d(new CellFormulaPrivate(formula, CellRange(), type))
{
}
/*!
* Creates a new formula with the given \a formula, \a ref and \a type.
*/
CellFormula::CellFormula(const QString &formula, const CellRange &ref, FormulaType type)
:d(new CellFormulaPrivate(formula, ref, type))
{
}
/*!
Creates a new formula with the same attributes as the \a other formula.
*/
CellFormula::CellFormula(const CellFormula &other)
:d(other.d)
{
}
/*!
Assigns the \a other formula to this formula, and returns a
reference to this formula.
*/
CellFormula &CellFormula::operator =(const CellFormula &other)
{
d = other.d;
return *this;
}
/*!
* Destroys this formula.
*/
CellFormula::~CellFormula()
{
}
/*!
* Returns the type of the formula.
*/
CellFormula::FormulaType CellFormula::formulaType() const
{
return d ? d->type : NormalType;
}
/*!
* Returns the contents of the formula.
*/
QString CellFormula::formulaText() const
{
return d ? d->formula : QString();
}
/*!
* Returns the reference cells of the formula. For normal formula,
* this will return an invalid CellRange object.
*/
CellRange CellFormula::reference() const
{
return d ? d->reference : CellRange();
}
/*!
* Returns whether the formula is valid.
*/
bool CellFormula::isValid() const
{
return d;
}
/*!
* Returns the shared index for shared formula.
*/
int CellFormula::sharedIndex() const
{
return d && d->type == SharedType ? d->si : -1;
}
/*!
* \internal
*/
bool CellFormula::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("f"));
QString t;
switch (d->type) {
case CellFormula::ArrayType:
t = QStringLiteral("array");
break;
case CellFormula::SharedType:
t = QStringLiteral("shared");
break;
default:
break;
}
if (!t.isEmpty())
writer.writeAttribute(QStringLiteral("t"), t);
if (d->reference.isValid())
writer.writeAttribute(QStringLiteral("ref"), d->reference.toString());
if (d->ca)
writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1"));
if (d->type == CellFormula::SharedType)
writer.writeAttribute(QStringLiteral("si"), QString::number(d->si));
if (!d->formula.isEmpty())
writer.writeCharacters(d->formula);
writer.writeEndElement(); //f
return true;
}
/*!
* \internal
*/
bool CellFormula::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("f"));
if (!d)
d = new CellFormulaPrivate(QString(), CellRange(), NormalType);
QXmlStreamAttributes attributes = reader.attributes();
QString typeString = attributes.value(QLatin1String("t")).toString();
if (typeString == QLatin1String("array"))
d->type = ArrayType;
else if (typeString == QLatin1String("shared"))
d->type = SharedType;
else
d->type = NormalType;
if (attributes.hasAttribute(QLatin1String("ref"))) {
QString refString = attributes.value(QLatin1String("ref")).toString();
d->reference = CellRange(refString);
}
QString ca = attributes.value(QLatin1String("si")).toString();
d->ca = parseXsdBoolean(ca, false);
if (attributes.hasAttribute(QLatin1String("si")))
d->si = attributes.value(QLatin1String("si")).toString().toInt();
d->formula = reader.readElementText();
return true;
}
/*!
* \internal
*/
bool CellFormula::operator ==(const CellFormula &formula) const
{
return d->formula == formula.d->formula && d->type == formula.d->type
&& d->si ==formula.d->si;
}
/*!
* \internal
*/
bool CellFormula::operator !=(const CellFormula &formula) const
{
return d->formula != formula.d->formula || d->type != formula.d->type
|| d->si !=formula.d->si;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,147 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxcellrange.h"
#include "xlsxcellreference.h"
#include <QString>
#include <QPoint>
#include <QStringList>
QT_BEGIN_NAMESPACE_XLSX
/*!
\class CellRange
\brief For a range "A1:B2" or single cell "A1"
\inmodule QtXlsx
The CellRange class stores the top left and bottom
right rows and columns of a range in a worksheet.
*/
/*!
Constructs an range, i.e. a range
whose rowCount() and columnCount() are 0.
*/
CellRange::CellRange()
: top(-1), left(-1), bottom(-2), right(-2)
{
}
/*!
Constructs the range from the given \a top, \a
left, \a bottom and \a right rows and columns.
\sa topRow(), leftColumn(), bottomRow(), rightColumn()
*/
CellRange::CellRange(int top, int left, int bottom, int right)
: top(top), left(left), bottom(bottom), right(right)
{
}
CellRange::CellRange(const CellReference &topLeft, const CellReference &bottomRight)
: top(topLeft.row()), left(topLeft.column())
, bottom(bottomRight.row()), right(bottomRight.column())
{
}
/*!
\overload
Constructs the range form the given \a range string.
*/
CellRange::CellRange(const QString &range)
{
init(range);
}
/*!
\overload
Constructs the range form the given \a range string.
*/
CellRange::CellRange(const char *range)
{
init(QString::fromLatin1(range));
}
void CellRange::init(const QString &range)
{
QStringList rs = range.split(QLatin1Char(':'));
if (rs.size() == 2) {
CellReference start(rs[0]);
CellReference end(rs[1]);
top = start.row();
left = start.column();
bottom = end.row();
right = end.column();
} else {
CellReference p(rs[0]);
top = p.row();
left = p.column();
bottom = p.row();
right = p.column();
}
}
/*!
Constructs a the range by copying the given \a
other range.
*/
CellRange::CellRange(const CellRange &other)
: top(other.top), left(other.left), bottom(other.bottom), right(other.right)
{
}
/*!
Destroys the range.
*/
CellRange::~CellRange()
{
}
/*!
Convert the range to string notation, such as "A1:B5".
*/
QString CellRange::toString(bool row_abs, bool col_abs) const
{
if (!isValid())
return QString();
if (left == right && top == bottom) {
//Single cell
return CellReference(top, left).toString(row_abs, col_abs);
}
QString cell_1 = CellReference(top, left).toString(row_abs, col_abs);
QString cell_2 = CellReference(bottom, right).toString(row_abs, col_abs);
return cell_1 + QLatin1String(":") + cell_2;
}
/*!
* Returns true if the Range is valid.
*/
bool CellRange::isValid() const
{
return left <= right && top <= bottom;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,174 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxcellreference.h"
#include <QStringList>
#include <QMap>
#include <QRegularExpression>
QT_BEGIN_NAMESPACE_XLSX
namespace {
int intPow(int x, int p)
{
if (p == 0) return 1;
if (p == 1) return x;
int tmp = intPow(x, p/2);
if (p%2 == 0) return tmp * tmp;
else return x * tmp * tmp;
}
QString col_to_name(int col_num)
{
static QMap<int, QString> col_cache;
if (!col_cache.contains(col_num)) {
QString col_str;
int remainder;
while (col_num) {
remainder = col_num % 26;
if (remainder == 0)
remainder = 26;
col_str.prepend(QChar('A'+remainder-1));
col_num = (col_num - 1) / 26;
}
col_cache.insert(col_num, col_str);
}
return col_cache[col_num];
}
int col_from_name(const QString &col_str)
{
int col = 0;
int expn = 0;
for (int i=col_str.size()-1; i>-1; --i) {
col += (col_str[i].unicode() - 'A' + 1) * intPow(26, expn);
expn++;
}
return col;
}
} //namespace
/*!
\class CellReference
\brief For one single cell such as "A1"
\inmodule QtXlsx
The CellReference class stores the cell location in a worksheet.
*/
/*!
Constructs an invalid Cell Reference
*/
CellReference::CellReference()
: _row(-1), _column(-1)
{
}
/*!
Constructs the Reference from the given \a row, and \a column.
*/
CellReference::CellReference(int row, int column)
: _row(row), _column(column)
{
}
/*!
\overload
Constructs the Reference form the given \a cell string.
*/
CellReference::CellReference(const QString &cell)
{
init(cell);
}
/*!
\overload
Constructs the Reference form the given \a cell string.
*/
CellReference::CellReference(const char *cell)
{
init(QString::fromLatin1(cell));
}
void CellReference::init(const QString &cell_str)
{
static QRegularExpression re(QStringLiteral("^\\$?([A-Z]{1,3})\\$?(\\d+)$"));
QRegularExpressionMatch match = re.match(cell_str);
if (match.hasMatch()) {
const QString col_str = match.captured(1);
const QString row_str = match.captured(2);
_row = row_str.toInt();
_column = col_from_name(col_str);
}
}
/*!
Constructs a Reference by copying the given \a
other Reference.
*/
CellReference::CellReference(const CellReference &other)
: _row(other._row), _column(other._column)
{
}
/*!
Destroys the Reference.
*/
CellReference::~CellReference()
{
}
/*!
Convert the Reference to string notation, such as "A1" or "$A$1".
If current object is invalid, an empty string will be returned.
*/
QString CellReference::toString(bool row_abs, bool col_abs) const
{
if (!isValid())
return QString();
QString cell_str;
if (col_abs)
cell_str.append(QLatin1Char('$'));
cell_str.append(col_to_name(_column));
if (row_abs)
cell_str.append(QLatin1Char('$'));
cell_str.append(QString::number(_row));
return cell_str;
}
/*!
* Returns true if the Reference is valid.
*/
bool CellReference::isValid() const
{
return _row > 0 && _column > 0;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,645 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxchart_p.h"
#include "xlsxworksheet.h"
#include "xlsxcellrange.h"
#include "xlsxutility_p.h"
#include <QIODevice>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
QT_BEGIN_NAMESPACE_XLSX
ChartPrivate::ChartPrivate(Chart *q, Chart::CreateFlag flag)
:AbstractOOXmlFilePrivate(q, flag), chartType(static_cast<Chart::ChartType>(0))
{
}
ChartPrivate::~ChartPrivate()
{
}
/*!
* \class Chart
* \inmodule QtXlsx
* \brief Main class for the charts.
*/
/*!
\enum Chart::ChartType
\value CT_Area
\value CT_Area3D,
\value CT_Line,
\value CT_Line3D,
\value CT_Scatter,
\value CT_Pie,
\value CT_Pie3D,
\value CT_Doughnut,
\value CT_Bar,
\value CT_Bar3D,
\omitvalue CT_Stock,
\omitvalue CT_Radar,
\omitvalue CT_OfPie,
\omitvalue CT_Surface,
\omitvalue CT_Surface3D,
\omitvalue CT_Bubble
*/
/*!
* \internal
*/
Chart::Chart(AbstractSheet *parent, CreateFlag flag)
:AbstractOOXmlFile(new ChartPrivate(this, flag))
{
d_func()->sheet = parent;
}
/*!
* Destroys the chart.
*/
Chart::~Chart()
{
}
/*!
* Add the data series which is in the range \a range of the \a sheet.
*/
void Chart::addSeries(const CellRange &range, AbstractSheet *sheet)
{
Q_D(Chart);
if (!range.isValid())
return;
if (sheet && sheet->sheetType() != AbstractSheet::ST_WorkSheet)
return;
if (!sheet && d->sheet->sheetType() != AbstractSheet::ST_WorkSheet)
return;
QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName();
//In case sheetName contains space or '
sheetName = escapeSheetName(sheetName);
if (range.columnCount() == 1 || range.rowCount() == 1) {
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
series->numberDataSource_numRef = sheetName + QLatin1String("!") + range.toString(true, true);
d->seriesList.append(series);
} else if (range.columnCount() < range.rowCount()) {
//Column based series
int firstDataColumn = range.firstColumn();
QString axDataSouruce_numRef;
if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) {
firstDataColumn += 1;
CellRange subRange(range.firstRow(), range.firstColumn(), range.lastRow(), range.firstColumn());
axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
}
for (int col=firstDataColumn; col<=range.lastColumn(); ++col) {
CellRange subRange(range.firstRow(), col, range.lastRow(), col);
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
series->axDataSource_numRef = axDataSouruce_numRef;
series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
d->seriesList.append(series);
}
} else {
//Row based series
int firstDataRow = range.firstRow();
QString axDataSouruce_numRef;
if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) {
firstDataRow += 1;
CellRange subRange(range.firstRow(), range.firstColumn(), range.firstRow(), range.lastColumn());
axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
}
for (int row=firstDataRow; row<=range.lastRow(); ++row) {
CellRange subRange(row, range.firstColumn(), row, range.lastColumn());
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
series->axDataSource_numRef = axDataSouruce_numRef;
series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
d->seriesList.append(series);
}
}
}
/*!
* Set the type of the chart to \a type
*/
void Chart::setChartType(ChartType type)
{
Q_D(Chart);
d->chartType = type;
}
/*!
* \internal
*
*/
void Chart::setChartStyle(int id)
{
Q_UNUSED(id)
//!Todo
}
/*!
* \internal
*/
void Chart::saveToXmlFile(QIODevice *device) const
{
Q_D(const Chart);
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("c:chartSpace"));
writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
d->saveXmlChart(writer);
writer.writeEndElement();//c:chartSpace
writer.writeEndDocument();
}
/*!
* \internal
*/
bool Chart::loadFromXmlFile(QIODevice *device)
{
Q_D(Chart);
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("chart")) {
if (!d->loadXmlChart(reader))
return false;
}
}
}
return true;
}
bool ChartPrivate::loadXmlChart(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("chart"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("plotArea")) {
if (!loadXmlPlotArea(reader))
return false;
} else if (reader.name() == QLatin1String("legend")) {
//!Todo
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QLatin1String("chart")) {
break;
}
}
return true;
}
bool ChartPrivate::loadXmlPlotArea(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("plotArea"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("layout")) {
//!ToDo
} else if (reader.name().endsWith(QLatin1String("Chart"))) {
//For pieChart, barChart, ...
loadXmlXxxChart(reader);
} else if (reader.name().endsWith(QLatin1String("Ax"))) {
//For valAx, catAx, serAx, dateAx
loadXmlAxis(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QLatin1String("plotArea")) {
break;
}
}
return true;
}
bool ChartPrivate::loadXmlXxxChart(QXmlStreamReader &reader)
{
QStringRef name = reader.name();
if (name == QLatin1String("pieChart")) chartType = Chart::CT_Pie;
else if (name == QLatin1String("pie3DChart")) chartType = Chart::CT_Pie3D;
else if (name == QLatin1String("barChart")) chartType = Chart::CT_Bar;
else if (name == QLatin1String("bar3DChart")) chartType = Chart::CT_Bar3D;
else if (name == QLatin1String("lineChart")) chartType = Chart::CT_Line;
else if (name == QLatin1String("line3DChart")) chartType = Chart::CT_Line3D;
else if (name == QLatin1String("scatterChart")) chartType = Chart::CT_Scatter;
else if (name == QLatin1String("areaChart")) chartType = Chart::CT_Area;
else if (name == QLatin1String("area3DChart")) chartType = Chart::CT_Area3D;
else if (name == QLatin1String("doughnutChart")) chartType = Chart::CT_Doughnut;
else qDebug()<<"Cann't load chart: "<<name;
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("ser")) {
loadXmlSer(reader);
} else if (reader.name() == QLatin1String("axId")) {
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name) {
break;
}
}
return true;
}
bool ChartPrivate::loadXmlSer(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("ser"));
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
seriesList.append(series);
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("ser"))) {
if (reader.readNextStartElement()) {
QStringRef name = reader.name();
if (name == QLatin1String("cat") || name == QLatin1String("xVal")) {
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name)) {
if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("numRef"))
series->axDataSource_numRef = loadXmlNumRef(reader);
}
}
} else if (name == QLatin1String("val") || name == QLatin1String("yVal")) {
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name)) {
if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("numRef"))
series->numberDataSource_numRef = loadXmlNumRef(reader);
}
}
} else if (name == QLatin1String("extLst")) {
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name)) {
reader.readNextStartElement();
}
}
}
}
return true;
}
QString ChartPrivate::loadXmlNumRef(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("numRef"));
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("numRef"))) {
if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("f"))
return reader.readElementText();
}
}
return QString();
}
void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("c:chart"));
writer.writeStartElement(QStringLiteral("c:plotArea"));
switch (chartType) {
case Chart::CT_Pie:
case Chart::CT_Pie3D:
saveXmlPieChart(writer);
break;
case Chart::CT_Bar:
case Chart::CT_Bar3D:
saveXmlBarChart(writer);
break;
case Chart::CT_Line:
case Chart::CT_Line3D:
saveXmlLineChart(writer);
break;
case Chart::CT_Scatter:
saveXmlScatterChart(writer);
break;
case Chart::CT_Area:
case Chart::CT_Area3D:
saveXmlAreaChart(writer);
break;
case Chart::CT_Doughnut:
saveXmlDoughnutChart(writer);
break;
default:
break;
}
saveXmlAxes(writer);
writer.writeEndElement(); //plotArea
// saveXmlLegend(writer);
writer.writeEndElement(); //chart
}
void ChartPrivate::saveXmlPieChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Pie ? QStringLiteral("c:pieChart") : QStringLiteral("c:pie3DChart");
writer.writeStartElement(name);
//Do the same behavior as Excel, Pie prefer varyColors
writer.writeEmptyElement(QStringLiteral("c:varyColors"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
writer.writeEndElement(); //pieChart, pie3DChart
}
void ChartPrivate::saveXmlBarChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Bar ? QStringLiteral("c:barChart") : QStringLiteral("c:bar3DChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:barDir"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("col"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
//The order the axes??
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
}
//Note: Bar3D have 2~3 axes
Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Bar3D));
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //barChart, bar3DChart
}
void ChartPrivate::saveXmlLineChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Line ? QStringLiteral("c:lineChart") : QStringLiteral("c:line3DChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("grouping"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
if (chartType==Chart::CT_Line3D)
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Ser, XlsxAxis::Bottom, 2, 0)));
}
Q_ASSERT((axisList.size()==2||chartType==Chart::CT_Line)|| (axisList.size()==3 && chartType==Chart::CT_Line3D));
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //lineChart, line3DChart
}
void ChartPrivate::saveXmlScatterChart(QXmlStreamWriter &writer) const
{
const QString name = QStringLiteral("c:scatterChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:scatterStyle"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
}
Q_ASSERT(axisList.size()==2);
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //c:scatterChart
}
void ChartPrivate::saveXmlAreaChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Area ? QStringLiteral("c:areaChart") : QStringLiteral("c:area3DChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("grouping"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
}
//Note: Area3D have 2~3 axes
Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Area3D));
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //lineChart, line3DChart
}
void ChartPrivate::saveXmlDoughnutChart(QXmlStreamWriter &writer) const
{
QString name = QStringLiteral("c:doughnutChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:varyColors"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
writer.writeStartElement(QStringLiteral("c:holeSize"));
writer.writeAttribute(QStringLiteral("val"), QString::number(50));
writer.writeEndElement();
}
void ChartPrivate::saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) const
{
writer.writeStartElement(QStringLiteral("c:ser"));
writer.writeEmptyElement(QStringLiteral("c:idx"));
writer.writeAttribute(QStringLiteral("val"), QString::number(id));
writer.writeEmptyElement(QStringLiteral("c:order"));
writer.writeAttribute(QStringLiteral("val"), QString::number(id));
if (!ser->axDataSource_numRef.isEmpty()) {
if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble)
writer.writeStartElement(QStringLiteral("c:xVal"));
else
writer.writeStartElement(QStringLiteral("c:cat"));
writer.writeStartElement(QStringLiteral("c:numRef"));
writer.writeTextElement(QStringLiteral("c:f"), ser->axDataSource_numRef);
writer.writeEndElement();//c:numRef
writer.writeEndElement();//c:cat or c:xVal
}
if (!ser->numberDataSource_numRef.isEmpty()) {
if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble)
writer.writeStartElement(QStringLiteral("c:yVal"));
else
writer.writeStartElement(QStringLiteral("c:val"));
writer.writeStartElement(QStringLiteral("c:numRef"));
writer.writeTextElement(QStringLiteral("c:f"), ser->numberDataSource_numRef);
writer.writeEndElement();//c:numRef
writer.writeEndElement();//c:val or c:yVal
}
writer.writeEndElement();//c:ser
}
bool ChartPrivate::loadXmlAxis(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name().endsWith(QLatin1String("Ax")));
QString name = reader.name().toString();
XlsxAxis *axis = new XlsxAxis;
if (name == QLatin1String("valAx"))
axis->type = XlsxAxis::T_Val;
else if (name == QLatin1String("catAx"))
axis->type = XlsxAxis::T_Cat;
else if (name == QLatin1String("serAx"))
axis->type = XlsxAxis::T_Ser;
else
axis->type = XlsxAxis::T_Date;
axisList.append(QSharedPointer<XlsxAxis>(axis));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("axPos")) {
QXmlStreamAttributes attrs = reader.attributes();
QStringRef pos = attrs.value(QLatin1String("val"));
if (pos==QLatin1String("l"))
axis->axisPos = XlsxAxis::Left;
else if (pos==QLatin1String("r"))
axis->axisPos = XlsxAxis::Right;
else if (pos==QLatin1String("b"))
axis->axisPos = XlsxAxis::Bottom;
else
axis->axisPos = XlsxAxis::Top;
} else if (reader.name() == QLatin1String("axId")) {
axis->axisId = reader.attributes().value(QLatin1String("val")).toString().toInt();
} else if (reader.name() == QLatin1String("crossAx")) {
axis->crossAx = reader.attributes().value(QLatin1String("val")).toString().toInt();
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name) {
break;
}
}
return true;
}
void ChartPrivate::saveXmlAxes(QXmlStreamWriter &writer) const
{
for (int i=0; i<axisList.size(); ++i) {
XlsxAxis *axis = axisList[i].data();
QString name;
switch (axis->type) {
case XlsxAxis::T_Cat: name = QStringLiteral("c:catAx"); break;
case XlsxAxis::T_Val: name = QStringLiteral("c:valAx"); break;
case XlsxAxis::T_Ser: name = QStringLiteral("c:serAx"); break;
case XlsxAxis::T_Date: name = QStringLiteral("c:dateAx"); break;
default: break;
}
QString pos;
switch (axis->axisPos) {
case XlsxAxis::Top: pos = QStringLiteral("t"); break;
case XlsxAxis::Bottom: pos = QStringLiteral("b"); break;
case XlsxAxis::Left: pos = QStringLiteral("l"); break;
case XlsxAxis::Right: pos = QStringLiteral("r"); break;
default: break;
}
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axis->axisId));
writer.writeStartElement(QStringLiteral("c:scaling"));
writer.writeEmptyElement(QStringLiteral("c:orientation"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("minMax"));
writer.writeEndElement();//c:scaling
writer.writeEmptyElement(QStringLiteral("c:axPos"));
writer.writeAttribute(QStringLiteral("val"), pos);
writer.writeEmptyElement(QStringLiteral("c:crossAx"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axis->crossAx));
writer.writeEndElement();//name
}
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,159 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxchartsheet.h"
#include "xlsxchartsheet_p.h"
#include "xlsxworkbook.h"
#include "xlsxutility_p.h"
#include "xlsxdrawing_p.h"
#include "xlsxdrawinganchor_p.h"
#include "xlsxchart.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDir>
QT_BEGIN_NAMESPACE_XLSX
ChartsheetPrivate::ChartsheetPrivate(Chartsheet *p, Chartsheet::CreateFlag flag)
: AbstractSheetPrivate(p, flag), chart(0)
{
}
ChartsheetPrivate::~ChartsheetPrivate()
{
}
/*!
\class Chartsheet
\inmodule QtXlsx
\brief Represent one chartsheet in the workbook.
*/
/*!
* \internal
*/
Chartsheet::Chartsheet(const QString &name, int id, Workbook *workbook, CreateFlag flag)
:AbstractSheet(name, id, workbook, new ChartsheetPrivate(this, flag))
{
setSheetType(ST_ChartSheet);
if (flag == Chartsheet::F_NewFromScratch) {
d_func()->drawing = QSharedPointer<Drawing>(new Drawing(this, flag));
DrawingAbsoluteAnchor *anchor = new DrawingAbsoluteAnchor(drawing(), DrawingAnchor::Picture);
anchor->pos = QPoint(0, 0);
anchor->ext = QSize(9293679, 6068786);
QSharedPointer<Chart> chart = QSharedPointer<Chart>(new Chart(this, flag));
chart->setChartType(Chart::CT_Bar);
anchor->setObjectGraphicFrame(chart);
d_func()->chart = chart.data();
}
}
/*!
* \internal
*
* Make a copy of this sheet.
*/
Chartsheet *Chartsheet::copy(const QString &distName, int distId) const
{
//:Todo
Q_UNUSED(distName)
Q_UNUSED(distId)
return 0;
}
/*!
* Destroys this workssheet.
*/
Chartsheet::~Chartsheet()
{
}
/*!
* Returns the chart object of the sheet.
*/
Chart *Chartsheet::chart()
{
Q_D(Chartsheet);
return d->chart;
}
void Chartsheet::saveToXmlFile(QIODevice *device) const
{
Q_D(const Chartsheet);
d->relationships->clear();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), QStringLiteral("r"));
writer.writeStartElement(QStringLiteral("chartsheet"));
writer.writeStartElement(QStringLiteral("sheetViews"));
writer.writeEmptyElement(QStringLiteral("sheetView"));
writer.writeAttribute(QStringLiteral("workbookViewId"), QString::number(0));
writer.writeAttribute(QStringLiteral("zoomToFit"), QStringLiteral("1"));
writer.writeEndElement(); //sheetViews
int idx = d->workbook->drawings().indexOf(d->drawing.data());
d->relationships->addWorksheetRelationship(QStringLiteral("/drawing"), QStringLiteral("../drawings/drawing%1.xml").arg(idx+1));
writer.writeEmptyElement(QStringLiteral("drawing"));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
writer.writeEndElement();//chartsheet
writer.writeEndDocument();
}
bool Chartsheet::loadFromXmlFile(QIODevice *device)
{
Q_D(Chartsheet);
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("drawing")) {
QString rId = reader.attributes().value(QStringLiteral("r:id")).toString();
QString name = d->relationships->getRelationshipById(rId).target;
QString path = QDir::cleanPath(splitPath(filePath())[0] + QLatin1String("/") + name);
d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_LoadFromExists));
d->drawing->setFilePath(path);
}
}
}
return true;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,198 @@
#include "xlsxcolor_p.h"
#include "xlsxstyles_p.h"
#include "xlsxutility_p.h"
#include <QDataStream>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
namespace QXlsx {
XlsxColor::XlsxColor(const QColor &color)
{
if (color.isValid())
val.setValue(color);
}
XlsxColor::XlsxColor(const QString &theme, const QString &tint)
:val(QStringList()<<theme<<tint)
{
}
XlsxColor::XlsxColor(int index)
:val(index)
{
}
bool XlsxColor::isRgbColor() const
{
if (val.userType() == qMetaTypeId<QColor>() && val.value<QColor>().isValid())
return true;
return false;
}
bool XlsxColor::isIndexedColor() const
{
return val.userType() == QMetaType::Int;
}
bool XlsxColor::isThemeColor() const
{
return val.userType() == QMetaType::QStringList;
}
bool XlsxColor::isInvalid() const
{
return !val.isValid();
}
QColor XlsxColor::rgbColor() const
{
if (isRgbColor())
return val.value<QColor>();
return QColor();
}
int XlsxColor::indexedColor() const
{
if (isIndexedColor())
return val.toInt();
return -1;
}
QStringList XlsxColor::themeColor() const
{
if (isThemeColor())
return val.toStringList();
return QStringList();
}
bool XlsxColor::saveToXml(QXmlStreamWriter &writer, const QString &node) const
{
if (!node.isEmpty())
writer.writeEmptyElement(node); //color, bgColor, fgColor
else
writer.writeEmptyElement(QStringLiteral("color"));
if (val.userType() == qMetaTypeId<QColor>()) {
writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(val.value<QColor>()));
} else if (val.userType() == QMetaType::QStringList) {
QStringList themes = val.toStringList();
writer.writeAttribute(QStringLiteral("theme"), themes[0]);
if (!themes[1].isEmpty())
writer.writeAttribute(QStringLiteral("tint"), themes[1]);
} else if (val.userType() == QMetaType::Int) {
writer.writeAttribute(QStringLiteral("indexed"), val.toString());
} else {
writer.writeAttribute(QStringLiteral("auto"), QStringLiteral("1"));
}
return true;
}
bool XlsxColor::loadFromXml(QXmlStreamReader &reader)
{
QXmlStreamAttributes attributes = reader.attributes();
if (attributes.hasAttribute(QLatin1String("rgb"))) {
QString colorString = attributes.value(QLatin1String("rgb")).toString();
val.setValue(fromARGBString(colorString));
} else if (attributes.hasAttribute(QLatin1String("indexed"))) {
int index = attributes.value(QLatin1String("indexed")).toString().toInt();
val.setValue(index);
} else if (attributes.hasAttribute(QLatin1String("theme"))) {
QString theme = attributes.value(QLatin1String("theme")).toString();
QString tint = attributes.value(QLatin1String("tint")).toString();
val.setValue(QStringList()<<theme<<tint);
}
return true;
}
XlsxColor::operator QVariant() const
{
return QVariant(qMetaTypeId<XlsxColor>(), this);
}
QColor XlsxColor::fromARGBString(const QString &c)
{
Q_ASSERT(c.length() == 8);
QColor color;
color.setAlpha(c.mid(0, 2).toInt(0, 16));
color.setRed(c.mid(2, 2).toInt(0, 16));
color.setGreen(c.mid(4, 2).toInt(0, 16));
color.setBlue(c.mid(6, 2).toInt(0, 16));
return color;
}
QString XlsxColor::toARGBString(const QColor &c)
{
QString color;
color.sprintf("%02X%02X%02X%02X", c.alpha(), c.red(), c.green(), c.blue());
return color;
}
#if !defined(QT_NO_DATASTREAM)
QDataStream &operator<<(QDataStream &s, const XlsxColor &color)
{
if (color.isInvalid())
s<<0;
else if (color.isRgbColor())
s<<1<<color.rgbColor();
else if (color.isIndexedColor())
s<<2<<color.indexedColor();
else if (color.isThemeColor())
s<<3<<color.themeColor();
else
s<<4;
return s;
}
QDataStream &operator>>(QDataStream &s, XlsxColor &color)
{
int marker(4);
s>>marker;
if (marker == 0) {
color = XlsxColor();
} else if (marker == 1) {
QColor c;
s>>c;
color = XlsxColor(c);
} else if (marker == 2) {
int indexed;
s>>indexed;
color = XlsxColor(indexed);
} else if (marker == 3) {
QStringList list;
s>>list;
color = XlsxColor(list[0], list[1]);
}
return s;
}
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const XlsxColor &c)
{
if (c.isInvalid())
dbg.nospace() << "XlsxColor(invalid)";
else if (c.isRgbColor())
dbg.nospace() << c.rgbColor();
else if (c.isIndexedColor())
dbg.nospace() << "XlsxColor(indexed," << c.indexedColor() << ")";
else if (c.isThemeColor())
dbg.nospace() << "XlsxColor(theme," << c.themeColor().join(QLatin1Char(':')) << ")";
return dbg.space();
}
#endif
} // namespace QXlsx

View File

@ -0,0 +1,735 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxconditionalformatting.h"
#include "xlsxconditionalformatting_p.h"
#include "xlsxworksheet.h"
#include "xlsxcellrange.h"
#include "xlsxstyles_p.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
QT_BEGIN_NAMESPACE_XLSX
ConditionalFormattingPrivate::ConditionalFormattingPrivate()
{
}
ConditionalFormattingPrivate::ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other)
:QSharedData(other)
{
}
ConditionalFormattingPrivate::~ConditionalFormattingPrivate()
{
}
void ConditionalFormattingPrivate::writeCfVo(QXmlStreamWriter &writer, const XlsxCfVoData &cfvo) const
{
writer.writeEmptyElement(QStringLiteral("cfvo"));
QString type;
switch(cfvo.type) {
case ConditionalFormatting::VOT_Formula: type=QStringLiteral("formula"); break;
case ConditionalFormatting::VOT_Max: type=QStringLiteral("max"); break;
case ConditionalFormatting::VOT_Min: type=QStringLiteral("min"); break;
case ConditionalFormatting::VOT_Num: type=QStringLiteral("num"); break;
case ConditionalFormatting::VOT_Percent: type=QStringLiteral("percent"); break;
case ConditionalFormatting::VOT_Percentile: type=QStringLiteral("percentile"); break;
default: break;
}
writer.writeAttribute(QStringLiteral("type"), type);
writer.writeAttribute(QStringLiteral("val"), cfvo.value);
if (!cfvo.gte)
writer.writeAttribute(QStringLiteral("gte"), QStringLiteral("0"));
}
/*!
* \class ConditionalFormatting
* \brief Conditional formatting for single cell or ranges
* \inmodule QtXlsx
*
* The conditional formatting can be applied to a single cell or ranges of cells.
*/
/*!
\enum ConditionalFormatting::HighlightRuleType
\value Highlight_LessThan
\value Highlight_LessThanOrEqual
\value Highlight_Equal
\value Highlight_NotEqual
\value Highlight_GreaterThanOrEqual
\value Highlight_GreaterThan
\value Highlight_Between
\value Highlight_NotBetween
\value Highlight_ContainsText
\value Highlight_NotContainsText
\value Highlight_BeginsWith
\value Highlight_EndsWith
\value Highlight_TimePeriod
\value Highlight_Duplicate
\value Highlight_Unique
\value Highlight_Blanks
\value Highlight_NoBlanks
\value Highlight_Errors
\value Highlight_NoErrors
\value Highlight_Top
\value Highlight_TopPercent
\value Highlight_Bottom
\value Highlight_BottomPercent
\value Highlight_AboveAverage
\value Highlight_AboveOrEqualAverage
\value Highlight_BelowAverage
\value Highlight_BelowOrEqualAverage
\value Highlight_AboveStdDev1
\value Highlight_AboveStdDev2
\value Highlight_AboveStdDev3
\value Highlight_BelowStdDev1
\value Highlight_BelowStdDev2
\value Highlight_BelowStdDev3
\value Highlight_Expression
*/
/*!
\enum ConditionalFormatting::ValueObjectType
\value VOT_Formula
\value VOT_Max
\value VOT_Min
\value VOT_Num
\value VOT_Percent
\value VOT_Percentile
*/
/*!
Construct a conditional formatting object
*/
ConditionalFormatting::ConditionalFormatting()
:d(new ConditionalFormattingPrivate())
{
}
/*!
Constructs a copy of \a other.
*/
ConditionalFormatting::ConditionalFormatting(const ConditionalFormatting &other)
:d(other.d)
{
}
/*!
Assigns \a other to this conditional formatting and returns a reference to
this conditional formatting.
*/
ConditionalFormatting &ConditionalFormatting::operator=(const ConditionalFormatting &other)
{
this->d = other.d;
return *this;
}
/*!
* Destroy the object.
*/
ConditionalFormatting::~ConditionalFormatting()
{
}
/*!
* Add a hightlight rule with the given \a type, \a formula1, \a formula2,
* \a format and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue)
{
if (format.isEmpty())
return false;
bool skipFormula = false;
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
if (type >= Highlight_LessThan && type <= Highlight_NotBetween) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("cellIs");
QString op;
switch (type) {
case Highlight_Between: op = QStringLiteral("between"); break;
case Highlight_Equal: op = QStringLiteral("equal"); break;
case Highlight_GreaterThan: op = QStringLiteral("greaterThan"); break;
case Highlight_GreaterThanOrEqual: op = QStringLiteral("greaterThanOrEqual"); break;
case Highlight_LessThan: op = QStringLiteral("lessThan"); break;
case Highlight_LessThanOrEqual: op = QStringLiteral("lessThanOrEqual"); break;
case Highlight_NotBetween: op = QStringLiteral("notBetween"); break;
case Highlight_NotEqual: op = QStringLiteral("notEqual"); break;
default: break;
}
cfRule->attrs[XlsxCfRuleData::A_operator] = op;
} else if (type >= Highlight_ContainsText && type <= Highlight_EndsWith) {
if (type == Highlight_ContainsText) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsText");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("containsText");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(SEARCH(\"%1\",%2)))").arg(formula1);
} else if (type == Highlight_NotContainsText) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsText");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("notContains");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(SEARCH(\"%2\",%1))").arg(formula1);
} else if (type == Highlight_BeginsWith) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("beginsWith");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("beginsWith");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEFT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
} else {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("endsWith");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("endsWith");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("RIGHT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
}
cfRule->attrs[XlsxCfRuleData::A_text] = formula1;
skipFormula = true;
} else if (type == Highlight_TimePeriod) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("timePeriod");
//:Todo
return false;
} else if (type == Highlight_Duplicate) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("duplicateValues");
} else if (type == Highlight_Unique) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("uniqueValues");
} else if (type == Highlight_Errors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(%1)");
skipFormula = true;
} else if (type == Highlight_NoErrors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(%1))");
skipFormula = true;
} else if (type == Highlight_Blanks) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsBlanks");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))=0");
skipFormula = true;
} else if (type == Highlight_NoBlanks) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsBlanks");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))>0");
skipFormula = true;
} else if (type >= Highlight_Top && type <= Highlight_BottomPercent) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("top10");
if (type == Highlight_Bottom || type == Highlight_BottomPercent)
cfRule->attrs[XlsxCfRuleData::A_bottom] = QStringLiteral("1");
if (type == Highlight_TopPercent || type == Highlight_BottomPercent)
cfRule->attrs[XlsxCfRuleData::A_percent] = QStringLiteral("1");
cfRule->attrs[XlsxCfRuleData::A_rank] = !formula1.isEmpty() ? formula1 : QStringLiteral("10");
skipFormula = true;
} else if (type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("aboveAverage");
if (type >= Highlight_BelowAverage && type <= Highlight_BelowStdDev3)
cfRule->attrs[XlsxCfRuleData::A_aboveAverage] = QStringLiteral("0");
if (type == Highlight_AboveOrEqualAverage || type == Highlight_BelowOrEqualAverage)
cfRule->attrs[XlsxCfRuleData::A_equalAverage] = QStringLiteral("1");
if (type == Highlight_AboveStdDev1 || type == Highlight_BelowStdDev1)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("1");
else if (type == Highlight_AboveStdDev2 || type == Highlight_BelowStdDev2)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("2");
else if (type == Highlight_AboveStdDev3 || type == Highlight_BelowStdDev3)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("3");
} else if (type == Highlight_Expression){
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("expression");
} else {
return false;
}
cfRule->dxfFormat = format;
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
if (!skipFormula) {
if (!formula1.isEmpty())
cfRule->attrs[XlsxCfRuleData::A_formula1] = formula1.startsWith(QLatin1String("=")) ? formula1.mid(1) : formula1;
if (!formula2.isEmpty())
cfRule->attrs[XlsxCfRuleData::A_formula2] = formula2.startsWith(QLatin1String("=")) ? formula2.mid(1) : formula2;
}
d->cfRules.append(cfRule);
return true;
}
/*!
* \overload
*
* Add a hightlight rule with the given \a type \a format and \a stopIfTrue.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue)
{
if ((type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3)
|| (type >= Highlight_Duplicate && type <= Highlight_NoErrors)) {
return addHighlightCellsRule(type, QString(), QString(), format, stopIfTrue);
}
return false;
}
/*!
* \overload
*
* Add a hightlight rule with the given \a type, \a formula, \a format and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula, const Format &format, bool stopIfTrue)
{
if (type == Highlight_Between || type == Highlight_NotBetween)
return false;
return addHighlightCellsRule(type, formula, QString(), format, stopIfTrue);
}
/*!
* Add a dataBar rule with the given \a color, \a type1, \a val1
* , \a type2, \a val2, \a showData and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData, bool stopIfTrue)
{
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("dataBar");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(color);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
if (!showData)
cfRule->attrs[XlsxCfRuleData::A_hideData] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
d->cfRules.append(cfRule);
return true;
}
/*!
* \overload
* Add a dataBar rule with the given \a color, \a showData and \a stopIfTrue.
*/
bool ConditionalFormatting::addDataBarRule(const QColor &color, bool showData, bool stopIfTrue)
{
return addDataBarRule(color, VOT_Min, QStringLiteral("0"), VOT_Max, QStringLiteral("0"), showData, stopIfTrue);
}
/*!
* Add a colorScale rule with the given \a minColor, \a maxColor and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue)
{
ValueObjectType type1 = VOT_Min;
ValueObjectType type2 = VOT_Max;
QString val1 = QStringLiteral("0");
QString val2 = QStringLiteral("0");
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(maxColor);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
d->cfRules.append(cfRule);
return true;
}
/*!
* Add a colorScale rule with the given \a minColor, \a midColor, \a maxColor and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue)
{
ValueObjectType type1 = VOT_Min;
ValueObjectType type2 = VOT_Percent;
ValueObjectType type3 = VOT_Max;
QString val1 = QStringLiteral("0");
QString val2 = QStringLiteral("50");
QString val3 = QStringLiteral("0");
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(midColor);
cfRule->attrs[XlsxCfRuleData::A_color3] = XlsxColor(maxColor);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
XlsxCfVoData cfvo3(type3, val3);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
cfRule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(cfvo3);
d->cfRules.append(cfRule);
return true;
}
/*!
Returns the ranges on which the validation will be applied.
*/
QList<CellRange> ConditionalFormatting::ranges() const
{
return d->ranges;
}
/*!
Add the \a cell on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addCell(const CellReference &cell)
{
d->ranges.append(CellRange(cell, cell));
}
/*!
\overload
Add the cell(\a row, \a col) on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addCell(int row, int col)
{
d->ranges.append(CellRange(row, col, row, col));
}
/*!
\overload
Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on
which the conditional formatting will apply to.
*/
void ConditionalFormatting::addRange(int firstRow, int firstCol, int lastRow, int lastCol)
{
d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol));
}
/*!
Add the \a range on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addRange(const CellRange &range)
{
d->ranges.append(range);
}
bool ConditionalFormattingPrivate::readCfRule(QXmlStreamReader &reader, XlsxCfRuleData *rule, Styles *styles)
{
Q_ASSERT(reader.name() == QLatin1String("cfRule"));
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("type")))
rule->attrs[XlsxCfRuleData::A_type] = attrs.value(QLatin1String("type")).toString();
if (attrs.hasAttribute(QLatin1String("dxfId"))) {
int id = attrs.value(QLatin1String("dxfId")).toString().toInt();
if (styles)
rule->dxfFormat = styles->dxfFormat(id);
else
rule->dxfFormat.setDxfIndex(id);
}
rule->priority = attrs.value(QLatin1String("priority")).toString().toInt();
if (attrs.value(QLatin1String("stopIfTrue")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_stopIfTrue] = QLatin1String("1");
}
if (attrs.value(QLatin1String("aboveAverage")) == QLatin1String("0")) {
//default is true
rule->attrs[XlsxCfRuleData::A_aboveAverage] = QLatin1String("0");
}
if (attrs.value(QLatin1String("percent")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_percent] = QLatin1String("1");
}
if (attrs.value(QLatin1String("bottom")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_bottom] = QLatin1String("1");
}
if (attrs.hasAttribute(QLatin1String("operator")))
rule->attrs[XlsxCfRuleData::A_operator] = attrs.value(QLatin1String("operator")).toString();
if (attrs.hasAttribute(QLatin1String("text")))
rule->attrs[XlsxCfRuleData::A_text] = attrs.value(QLatin1String("text")).toString();
if (attrs.hasAttribute(QLatin1String("timePeriod")))
rule->attrs[XlsxCfRuleData::A_timePeriod] = attrs.value(QLatin1String("timePeriod")).toString();
if (attrs.hasAttribute(QLatin1String("rank")))
rule->attrs[XlsxCfRuleData::A_rank] = attrs.value(QLatin1String("rank")).toString();
if (attrs.hasAttribute(QLatin1String("stdDev")))
rule->attrs[XlsxCfRuleData::A_stdDev] = attrs.value(QLatin1String("stdDev")).toString();
if (attrs.value(QLatin1String("equalAverage")) == QLatin1String("1")) {
//default is false
rule->attrs[XlsxCfRuleData::A_equalAverage] = QLatin1String("1");
}
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("formula")) {
QString f = reader.readElementText();
if (!rule->attrs.contains(XlsxCfRuleData::A_formula1))
rule->attrs[XlsxCfRuleData::A_formula1] = f;
else if (!rule->attrs.contains(XlsxCfRuleData::A_formula2))
rule->attrs[XlsxCfRuleData::A_formula2] = f;
else if (!rule->attrs.contains(XlsxCfRuleData::A_formula3))
rule->attrs[XlsxCfRuleData::A_formula3] = f;
} else if (reader.name() == QLatin1String("dataBar")) {
readCfDataBar(reader, rule);
} else if (reader.name() == QLatin1String("colorScale")) {
readCfColorScale(reader, rule);
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("conditionalFormatting")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *rule)
{
Q_ASSERT(reader.name() == QLatin1String("dataBar"));
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.value(QLatin1String("showValue")) == QLatin1String("0"))
rule->attrs[XlsxCfRuleData::A_hideData] = QStringLiteral("1");
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfvo")) {
XlsxCfVoData data;
readCfVo(reader, data);
if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
else
rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
rule->attrs[XlsxCfRuleData::A_color1] = color;
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("dataBar")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *rule)
{
Q_ASSERT(reader.name() == QLatin1String("colorScale"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfvo")) {
XlsxCfVoData data;
readCfVo(reader, data);
if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
else if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo2))
rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
else
rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
if (!rule->attrs.contains(XlsxCfRuleData::A_color1))
rule->attrs[XlsxCfRuleData::A_color1] = color;
else if (!rule->attrs.contains(XlsxCfRuleData::A_color2))
rule->attrs[XlsxCfRuleData::A_color2] = color;
else
rule->attrs[XlsxCfRuleData::A_color3] = color;
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("colorScale")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfVo(QXmlStreamReader &reader, XlsxCfVoData &cfvo)
{
Q_ASSERT(reader.name() == QStringLiteral("cfvo"));
QXmlStreamAttributes attrs = reader.attributes();
QString type = attrs.value(QLatin1String("type")).toString();
ConditionalFormatting::ValueObjectType t;
if (type == QLatin1String("formula"))
t = ConditionalFormatting::VOT_Formula;
else if (type == QLatin1String("max"))
t = ConditionalFormatting::VOT_Max;
else if (type == QLatin1String("min"))
t = ConditionalFormatting::VOT_Min;
else if (type == QLatin1String("num"))
t = ConditionalFormatting::VOT_Num;
else if (type == QLatin1String("percent"))
t = ConditionalFormatting::VOT_Percent;
else //if (type == QLatin1String("percentile"))
t = ConditionalFormatting::VOT_Percentile;
cfvo.type = t;
cfvo.value = attrs.value(QLatin1String("val")).toString();
if (attrs.value(QLatin1String("gte")) == QLatin1String("0")) {
//default is true
cfvo.gte = false;
}
return true;
}
bool ConditionalFormatting::loadFromXml(QXmlStreamReader &reader, Styles *styles)
{
Q_ASSERT(reader.name() == QStringLiteral("conditionalFormatting"));
d->ranges.clear();
d->cfRules.clear();
QXmlStreamAttributes attrs = reader.attributes();
QString sqref = attrs.value(QLatin1String("sqref")).toString();
foreach (QString range, sqref.split(QLatin1Char(' ')))
this->addRange(range);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfRule")) {
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
d->readCfRule(reader, cfRule.data(), styles);
d->cfRules.append(cfRule);
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QStringLiteral("conditionalFormatting")) {
break;
}
}
return true;
}
bool ConditionalFormatting::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("conditionalFormatting"));
QStringList sqref;
foreach (CellRange range, ranges())
sqref.append(range.toString());
writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1Char(' ')));
for (int i=0; i<d->cfRules.size(); ++i) {
const QSharedPointer<XlsxCfRuleData> &rule = d->cfRules[i];
writer.writeStartElement(QStringLiteral("cfRule"));
writer.writeAttribute(QStringLiteral("type"), rule->attrs[XlsxCfRuleData::A_type].toString());
if (rule->dxfFormat.dxfIndexValid())
writer.writeAttribute(QStringLiteral("dxfId"), QString::number(rule->dxfFormat.dxfIndex()));
writer.writeAttribute(QStringLiteral("priority"), QString::number(rule->priority));
if (rule->attrs.contains(XlsxCfRuleData::A_stopIfTrue))
writer.writeAttribute(QStringLiteral("stopIfTrue"), rule->attrs[XlsxCfRuleData::A_stopIfTrue].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_aboveAverage))
writer.writeAttribute(QStringLiteral("aboveAverage"), rule->attrs[XlsxCfRuleData::A_aboveAverage].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_percent))
writer.writeAttribute(QStringLiteral("percent"), rule->attrs[XlsxCfRuleData::A_percent].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_bottom))
writer.writeAttribute(QStringLiteral("bottom"), rule->attrs[XlsxCfRuleData::A_bottom].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_operator))
writer.writeAttribute(QStringLiteral("operator"), rule->attrs[XlsxCfRuleData::A_operator].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_text))
writer.writeAttribute(QStringLiteral("text"), rule->attrs[XlsxCfRuleData::A_text].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_timePeriod))
writer.writeAttribute(QStringLiteral("timePeriod"), rule->attrs[XlsxCfRuleData::A_timePeriod].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_rank))
writer.writeAttribute(QStringLiteral("rank"), rule->attrs[XlsxCfRuleData::A_rank].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_stdDev))
writer.writeAttribute(QStringLiteral("stdDev"), rule->attrs[XlsxCfRuleData::A_stdDev].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_equalAverage))
writer.writeAttribute(QStringLiteral("equalAverage"), rule->attrs[XlsxCfRuleData::A_equalAverage].toString());
if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("dataBar")) {
writer.writeStartElement(QStringLiteral("dataBar"));
if (rule->attrs.contains(XlsxCfRuleData::A_hideData))
writer.writeAttribute(QStringLiteral("showValue"), QStringLiteral("0"));
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
writer.writeEndElement();//dataBar
} else if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("colorScale")) {
writer.writeStartElement(QStringLiteral("colorScale"));
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
if (rule->attrs.contains(XlsxCfRuleData::A_cfvo3))
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo3].value<XlsxCfVoData>());
rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
rule->attrs[XlsxCfRuleData::A_color2].value<XlsxColor>().saveToXml(writer);
if (rule->attrs.contains(XlsxCfRuleData::A_color3))
rule->attrs[XlsxCfRuleData::A_color3].value<XlsxColor>().saveToXml(writer);
writer.writeEndElement();//colorScale
}
if (rule->attrs.contains(XlsxCfRuleData::A_formula1_temp)) {
QString startCell = ranges()[0].toString().split(QLatin1Char(':'))[0];
writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula1_temp].toString().arg(startCell));
} else if (rule->attrs.contains(XlsxCfRuleData::A_formula1)) {
writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula1].toString());
}
if (rule->attrs.contains(XlsxCfRuleData::A_formula2))
writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula2].toString());
if (rule->attrs.contains(XlsxCfRuleData::A_formula3))
writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula3].toString());
writer.writeEndElement(); //cfRule
}
writer.writeEndElement(); //conditionalFormatting
return true;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,205 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxcontenttypes_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QFile>
#include <QMapIterator>
#include <QBuffer>
#include <QDebug>
namespace QXlsx {
ContentTypes::ContentTypes(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
m_package_prefix = QStringLiteral("application/vnd.openxmlformats-package.");
m_document_prefix = QStringLiteral("application/vnd.openxmlformats-officedocument.");
m_defaults.insert(QStringLiteral("rels"), m_package_prefix + QStringLiteral("relationships+xml"));
m_defaults.insert(QStringLiteral("xml"), QStringLiteral("application/xml"));
}
void ContentTypes::addDefault(const QString &key, const QString &value)
{
m_defaults.insert(key, value);
}
void ContentTypes::addOverride(const QString &key, const QString &value)
{
m_overrides.insert(key, value);
}
void ContentTypes::addDocPropApp()
{
addOverride(QStringLiteral("/docProps/app.xml"), m_document_prefix + QStringLiteral("extended-properties+xml"));
}
void ContentTypes::addDocPropCore()
{
addOverride(QStringLiteral("/docProps/core.xml"), m_package_prefix + QStringLiteral("core-properties+xml"));
}
void ContentTypes::addStyles()
{
addOverride(QStringLiteral("/xl/styles.xml"), m_document_prefix + QStringLiteral("spreadsheetml.styles+xml"));
}
void ContentTypes::addTheme()
{
addOverride(QStringLiteral("/xl/theme/theme1.xml"), m_document_prefix + QStringLiteral("theme+xml"));
}
void ContentTypes::addWorkbook()
{
addOverride(QStringLiteral("/xl/workbook.xml"), m_document_prefix + QStringLiteral("spreadsheetml.sheet.main+xml"));
}
void ContentTypes::addWorksheetName(const QString &name)
{
addOverride(QStringLiteral("/xl/worksheets/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.worksheet+xml"));
}
void ContentTypes::addChartsheetName(const QString &name)
{
addOverride(QStringLiteral("/xl/chartsheets/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.chartsheet+xml"));
}
void ContentTypes::addDrawingName(const QString &name)
{
addOverride(QStringLiteral("/xl/drawings/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawing+xml"));
}
void ContentTypes::addChartName(const QString &name)
{
addOverride(QStringLiteral("/xl/charts/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawingml.chart+xml"));
}
void ContentTypes::addCommentName(const QString &name)
{
addOverride(QStringLiteral("/xl/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.comments+xml"));
}
void ContentTypes::addTableName(const QString &name)
{
addOverride(QStringLiteral("/xl/tables/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.table+xml"));
}
void ContentTypes::addExternalLinkName(const QString &name)
{
addOverride(QStringLiteral("/xl/externalLinks/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.externalLink+xml"));
}
void ContentTypes::addSharedString()
{
addOverride(QStringLiteral("/xl/sharedStrings.xml"), m_document_prefix + QStringLiteral("spreadsheetml.sharedStrings+xml"));
}
void ContentTypes::addVmlName()
{
addOverride(QStringLiteral("vml"), m_document_prefix + QStringLiteral("vmlDrawing"));
}
void ContentTypes::addCalcChain()
{
addOverride(QStringLiteral("/xl/calcChain.xml"), m_document_prefix + QStringLiteral("spreadsheetml.calcChain+xml"));
}
void ContentTypes::addVbaProject()
{
//:TODO
addOverride(QStringLiteral("bin"), QStringLiteral("application/vnd.ms-office.vbaProject"));
}
void ContentTypes::clearOverrides()
{
m_overrides.clear();
}
void ContentTypes::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Types"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/package/2006/content-types"));
{
QMapIterator<QString, QString> it(m_defaults);
while (it.hasNext()) {
it.next();
writer.writeStartElement(QStringLiteral("Default"));
writer.writeAttribute(QStringLiteral("Extension"), it.key());
writer.writeAttribute(QStringLiteral("ContentType"), it.value());
writer.writeEndElement();//Default
}
}
{
QMapIterator<QString, QString> it(m_overrides);
while (it.hasNext()) {
it.next();
writer.writeStartElement(QStringLiteral("Override"));
writer.writeAttribute(QStringLiteral("PartName"), it.key());
writer.writeAttribute(QStringLiteral("ContentType"), it.value());
writer.writeEndElement(); //Override
}
}
writer.writeEndElement();//Types
writer.writeEndDocument();
}
bool ContentTypes::loadFromXmlFile(QIODevice *device)
{
m_defaults.clear();
m_overrides.clear();
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("Default")) {
QXmlStreamAttributes attrs = reader.attributes();
QString extension = attrs.value(QLatin1String("Extension")).toString();
QString type = attrs.value(QLatin1String("ContentType")).toString();
m_defaults.insert(extension, type);
} else if (reader.name() == QLatin1String("Override")) {
QXmlStreamAttributes attrs = reader.attributes();
QString partName = attrs.value(QLatin1String("PartName")).toString();
QString type = attrs.value(QLatin1String("ContentType")).toString();
m_overrides.insert(partName, type);
}
}
if (reader.hasError()) {
qDebug()<<reader.errorString();
}
}
return true;
}
} //namespace QXlsx

View File

@ -0,0 +1,552 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxdatavalidation.h"
#include "xlsxdatavalidation_p.h"
#include "xlsxworksheet.h"
#include "xlsxcellrange.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
QT_BEGIN_NAMESPACE_XLSX
DataValidationPrivate::DataValidationPrivate()
:validationType(DataValidation::None), validationOperator(DataValidation::Between)
, errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true)
, isErrorMessageVisible(true)
{
}
DataValidationPrivate::DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank)
:validationType(type), validationOperator(op)
, errorStyle(DataValidation::Stop), allowBlank(allowBlank), isPromptMessageVisible(true)
, isErrorMessageVisible(true), formula1(formula1), formula2(formula2)
{
}
DataValidationPrivate::DataValidationPrivate(const DataValidationPrivate &other)
:QSharedData(other)
, validationType(DataValidation::None), validationOperator(DataValidation::Between)
, errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true)
, isErrorMessageVisible(true)
{
}
DataValidationPrivate::~DataValidationPrivate()
{
}
/*!
* \class DataValidation
* \brief Data validation for single cell or a range
* \inmodule QtXlsx
*
* The data validation can be applied to a single cell or a range of cells.
*/
/*!
* \enum DataValidation::ValidationType
*
* The enum type defines the type of data that you wish to validate.
*
* \value None the type of data is unrestricted. This is the same as not applying a data validation.
* \value Whole restricts the cell to integer values. Means "Whole number"?
* \value Decimal restricts the cell to decimal values.
* \value List restricts the cell to a set of user specified values.
* \value Date restricts the cell to date values.
* \value Time restricts the cell to time values.
* \value TextLength restricts the cell data based on an integer string length.
* \value Custom restricts the cell based on an external Excel formula that returns a true/false value.
*/
/*!
* \enum DataValidation::ValidationOperator
*
* The enum type defines the criteria by which the data in the
* cell is validated
*
* \value Between
* \value NotBetween
* \value Equal
* \value NotEqual
* \value LessThan
* \value LessThanOrEqual
* \value GreaterThan
* \value GreaterThanOrEqual
*/
/*!
* \enum DataValidation::ErrorStyle
*
* The enum type defines the type of error dialog that
* is displayed.
*
* \value Stop
* \value Warning
* \value Information
*/
/*!
* Construct a data validation object with the given \a type, \a op, \a formula1
* \a formula2, and \a allowBlank.
*/
DataValidation::DataValidation(ValidationType type, ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank)
:d(new DataValidationPrivate(type, op, formula1, formula2, allowBlank))
{
}
/*!
Construct a data validation object
*/
DataValidation::DataValidation()
:d(new DataValidationPrivate())
{
}
/*!
Constructs a copy of \a other.
*/
DataValidation::DataValidation(const DataValidation &other)
:d(other.d)
{
}
/*!
Assigns \a other to this validation and returns a reference to this validation.
*/
DataValidation &DataValidation::operator=(const DataValidation &other)
{
this->d = other.d;
return *this;
}
/*!
* Destroy the object.
*/
DataValidation::~DataValidation()
{
}
/*!
Returns the validation type.
*/
DataValidation::ValidationType DataValidation::validationType() const
{
return d->validationType;
}
/*!
Returns the validation operator.
*/
DataValidation::ValidationOperator DataValidation::validationOperator() const
{
return d->validationOperator;
}
/*!
Returns the validation error style.
*/
DataValidation::ErrorStyle DataValidation::errorStyle() const
{
return d->errorStyle;
}
/*!
Returns the formula1.
*/
QString DataValidation::formula1() const
{
return d->formula1;
}
/*!
Returns the formula2.
*/
QString DataValidation::formula2() const
{
return d->formula2;
}
/*!
Returns whether blank is allowed.
*/
bool DataValidation::allowBlank() const
{
return d->allowBlank;
}
/*!
Returns the error message.
*/
QString DataValidation::errorMessage() const
{
return d->errorMessage;
}
/*!
Returns the error message title.
*/
QString DataValidation::errorMessageTitle() const
{
return d->errorMessageTitle;
}
/*!
Returns the prompt message.
*/
QString DataValidation::promptMessage() const
{
return d->promptMessage;
}
/*!
Returns the prompt message title.
*/
QString DataValidation::promptMessageTitle() const
{
return d->promptMessageTitle;
}
/*!
Returns the whether prompt message is shown.
*/
bool DataValidation::isPromptMessageVisible() const
{
return d->isPromptMessageVisible;
}
/*!
Returns the whether error message is shown.
*/
bool DataValidation::isErrorMessageVisible() const
{
return d->isErrorMessageVisible;
}
/*!
Returns the ranges on which the validation will be applied.
*/
QList<CellRange> DataValidation::ranges() const
{
return d->ranges;
}
/*!
Sets the validation type to \a type.
*/
void DataValidation::setValidationType(DataValidation::ValidationType type)
{
d->validationType = type;
}
/*!
Sets the validation operator to \a op.
*/
void DataValidation::setValidationOperator(DataValidation::ValidationOperator op)
{
d->validationOperator = op;
}
/*!
Sets the error style to \a es.
*/
void DataValidation::setErrorStyle(DataValidation::ErrorStyle es)
{
d->errorStyle = es;
}
/*!
Sets the formula1 to \a formula.
*/
void DataValidation::setFormula1(const QString &formula)
{
if (formula.startsWith(QLatin1Char('=')))
d->formula1 = formula.mid(1);
else
d->formula1 = formula;
}
/*!
Sets the formulas to \a formula.
*/
void DataValidation::setFormula2(const QString &formula)
{
if (formula.startsWith(QLatin1Char('=')))
d->formula2 = formula.mid(1);
else
d->formula2 = formula;
}
/*!
Sets the error message to \a error with title \a title.
*/
void DataValidation::setErrorMessage(const QString &error, const QString &title)
{
d->errorMessage = error;
d->errorMessageTitle = title;
}
/*!
Sets the prompt message to \a prompt with title \a title.
*/
void DataValidation::setPromptMessage(const QString &prompt, const QString &title)
{
d->promptMessage = prompt;
d->promptMessageTitle = title;
}
/*!
Enable/disabe blank allow based on \a enable.
*/
void DataValidation::setAllowBlank(bool enable)
{
d->allowBlank = enable;
}
/*!
Enable/disabe prompt message visible based on \a visible.
*/
void DataValidation::setPromptMessageVisible(bool visible)
{
d->isPromptMessageVisible = visible;
}
/*!
Enable/disabe error message visible based on \a visible.
*/
void DataValidation::setErrorMessageVisible(bool visible)
{
d->isErrorMessageVisible = visible;
}
/*!
Add the \a cell on which the DataValidation will apply to.
*/
void DataValidation::addCell(const CellReference &cell)
{
d->ranges.append(CellRange(cell, cell));
}
/*!
\overload
Add the cell(\a row, \a col) on which the DataValidation will apply to.
*/
void DataValidation::addCell(int row, int col)
{
d->ranges.append(CellRange(row, col, row, col));
}
/*!
\overload
Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on
which the DataValidation will apply to.
*/
void DataValidation::addRange(int firstRow, int firstCol, int lastRow, int lastCol)
{
d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol));
}
/*!
Add the \a range on which the DataValidation will apply to.
*/
void DataValidation::addRange(const CellRange &range)
{
d->ranges.append(range);
}
/*!
* \internal
*/
bool DataValidation::saveToXml(QXmlStreamWriter &writer) const
{
static QMap<DataValidation::ValidationType, QString> typeMap;
static QMap<DataValidation::ValidationOperator, QString> opMap;
static QMap<DataValidation::ErrorStyle, QString> esMap;
if (typeMap.isEmpty()) {
typeMap.insert(DataValidation::None, QStringLiteral("none"));
typeMap.insert(DataValidation::Whole, QStringLiteral("whole"));
typeMap.insert(DataValidation::Decimal, QStringLiteral("decimal"));
typeMap.insert(DataValidation::List, QStringLiteral("list"));
typeMap.insert(DataValidation::Date, QStringLiteral("date"));
typeMap.insert(DataValidation::Time, QStringLiteral("time"));
typeMap.insert(DataValidation::TextLength, QStringLiteral("textLength"));
typeMap.insert(DataValidation::Custom, QStringLiteral("custom"));
opMap.insert(DataValidation::Between, QStringLiteral("between"));
opMap.insert(DataValidation::NotBetween, QStringLiteral("notBetween"));
opMap.insert(DataValidation::Equal, QStringLiteral("equal"));
opMap.insert(DataValidation::NotEqual, QStringLiteral("notEqual"));
opMap.insert(DataValidation::LessThan, QStringLiteral("lessThan"));
opMap.insert(DataValidation::LessThanOrEqual, QStringLiteral("lessThanOrEqual"));
opMap.insert(DataValidation::GreaterThan, QStringLiteral("greaterThan"));
opMap.insert(DataValidation::GreaterThanOrEqual, QStringLiteral("greaterThanOrEqual"));
esMap.insert(DataValidation::Stop, QStringLiteral("stop"));
esMap.insert(DataValidation::Warning, QStringLiteral("warning"));
esMap.insert(DataValidation::Information, QStringLiteral("information"));
}
writer.writeStartElement(QStringLiteral("dataValidation"));
if (validationType() != DataValidation::None)
writer.writeAttribute(QStringLiteral("type"), typeMap[validationType()]);
if (errorStyle() != DataValidation::Stop)
writer.writeAttribute(QStringLiteral("errorStyle"), esMap[errorStyle()]);
if (validationOperator() != DataValidation::Between)
writer.writeAttribute(QStringLiteral("operator"), opMap[validationOperator()]);
if (allowBlank())
writer.writeAttribute(QStringLiteral("allowBlank"), QStringLiteral("1"));
// if (dropDownVisible())
// writer.writeAttribute(QStringLiteral("showDropDown"), QStringLiteral("1"));
if (isPromptMessageVisible())
writer.writeAttribute(QStringLiteral("showInputMessage"), QStringLiteral("1"));
if (isErrorMessageVisible())
writer.writeAttribute(QStringLiteral("showErrorMessage"), QStringLiteral("1"));
if (!errorMessageTitle().isEmpty())
writer.writeAttribute(QStringLiteral("errorTitle"), errorMessageTitle());
if (!errorMessage().isEmpty())
writer.writeAttribute(QStringLiteral("error"), errorMessage());
if (!promptMessageTitle().isEmpty())
writer.writeAttribute(QStringLiteral("promptTitle"), promptMessageTitle());
if (!promptMessage().isEmpty())
writer.writeAttribute(QStringLiteral("prompt"), promptMessage());
QStringList sqref;
foreach (CellRange range, ranges())
sqref.append(range.toString());
writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1Char(' ')));
if (!formula1().isEmpty())
writer.writeTextElement(QStringLiteral("formula1"), formula1());
if (!formula2().isEmpty())
writer.writeTextElement(QStringLiteral("formula2"), formula2());
writer.writeEndElement(); //dataValidation
return true;
}
/*!
* \internal
*/
DataValidation DataValidation::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("dataValidation"));
static QMap<QString, DataValidation::ValidationType> typeMap;
static QMap<QString, DataValidation::ValidationOperator> opMap;
static QMap<QString, DataValidation::ErrorStyle> esMap;
if (typeMap.isEmpty()) {
typeMap.insert(QStringLiteral("none"), DataValidation::None);
typeMap.insert(QStringLiteral("whole"), DataValidation::Whole);
typeMap.insert(QStringLiteral("decimal"), DataValidation::Decimal);
typeMap.insert(QStringLiteral("list"), DataValidation::List);
typeMap.insert(QStringLiteral("date"), DataValidation::Date);
typeMap.insert(QStringLiteral("time"), DataValidation::Time);
typeMap.insert(QStringLiteral("textLength"), DataValidation::TextLength);
typeMap.insert(QStringLiteral("custom"), DataValidation::Custom);
opMap.insert(QStringLiteral("between"), DataValidation::Between);
opMap.insert(QStringLiteral("notBetween"), DataValidation::NotBetween);
opMap.insert(QStringLiteral("equal"), DataValidation::Equal);
opMap.insert(QStringLiteral("notEqual"), DataValidation::NotEqual);
opMap.insert(QStringLiteral("lessThan"), DataValidation::LessThan);
opMap.insert(QStringLiteral("lessThanOrEqual"), DataValidation::LessThanOrEqual);
opMap.insert(QStringLiteral("greaterThan"), DataValidation::GreaterThan);
opMap.insert(QStringLiteral("greaterThanOrEqual"), DataValidation::GreaterThanOrEqual);
esMap.insert(QStringLiteral("stop"), DataValidation::Stop);
esMap.insert(QStringLiteral("warning"), DataValidation::Warning);
esMap.insert(QStringLiteral("information"), DataValidation::Information);
}
DataValidation validation;
QXmlStreamAttributes attrs = reader.attributes();
QString sqref = attrs.value(QLatin1String("sqref")).toString();
foreach (QString range, sqref.split(QLatin1Char(' ')))
validation.addRange(range);
if (attrs.hasAttribute(QLatin1String("type"))) {
QString t = attrs.value(QLatin1String("type")).toString();
validation.setValidationType(typeMap.contains(t) ? typeMap[t] : DataValidation::None);
}
if (attrs.hasAttribute(QLatin1String("errorStyle"))) {
QString es = attrs.value(QLatin1String("errorStyle")).toString();
validation.setErrorStyle(esMap.contains(es) ? esMap[es] : DataValidation::Stop);
}
if (attrs.hasAttribute(QLatin1String("operator"))) {
QString op = attrs.value(QLatin1String("operator")).toString();
validation.setValidationOperator(opMap.contains(op) ? opMap[op] : DataValidation::Between);
}
if (attrs.hasAttribute(QLatin1String("allowBlank"))) {
validation.setAllowBlank(true);
} else {
validation.setAllowBlank(false);
}
if (attrs.hasAttribute(QLatin1String("showInputMessage"))) {
validation.setPromptMessageVisible(true);
} else {
validation.setPromptMessageVisible(false);
}
if (attrs.hasAttribute(QLatin1String("showErrorMessage"))) {
validation.setErrorMessageVisible(true);
} else {
validation.setErrorMessageVisible(false);
}
QString et = attrs.value(QLatin1String("errorTitle")).toString();
QString e = attrs.value(QLatin1String("error")).toString();
if (!e.isEmpty() || !et.isEmpty())
validation.setErrorMessage(e, et);
QString pt = attrs.value(QLatin1String("promptTitle")).toString();
QString p = attrs.value(QLatin1String("prompt")).toString();
if (!p.isEmpty() || !pt.isEmpty())
validation.setPromptMessage(p, pt);
//find the end
while(!(reader.name() == QLatin1String("dataValidation") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("formula1")) {
validation.setFormula1(reader.readElementText());
} else if (reader.name() == QLatin1String("formula2")) {
validation.setFormula2(reader.readElementText());
}
}
}
return validation;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,157 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxdocpropsapp_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QVariant>
#include <QBuffer>
namespace QXlsx {
DocPropsApp::DocPropsApp(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void DocPropsApp::addPartTitle(const QString &title)
{
m_titlesOfPartsList.append(title);
}
void DocPropsApp::addHeadingPair(const QString &name, int value)
{
m_headingPairsList.append(qMakePair(name, value));
}
bool DocPropsApp::setProperty(const QString &name, const QString &value)
{
static QStringList validKeys;
if (validKeys.isEmpty()) {
validKeys << QStringLiteral("manager") << QStringLiteral("company");
}
if (!validKeys.contains(name))
return false;
if (value.isEmpty())
m_properties.remove(name);
else
m_properties[name] = value;
return true;
}
QString DocPropsApp::property(const QString &name) const
{
if (m_properties.contains(name))
return m_properties[name];
return QString();
}
QStringList DocPropsApp::propertyNames() const
{
return m_properties.keys();
}
void DocPropsApp::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
QString vt = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Properties"));
writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"));
writer.writeNamespace(vt, QStringLiteral("vt"));
writer.writeTextElement(QStringLiteral("Application"), QStringLiteral("Microsoft Excel"));
writer.writeTextElement(QStringLiteral("DocSecurity"), QStringLiteral("0"));
writer.writeTextElement(QStringLiteral("ScaleCrop"), QStringLiteral("false"));
writer.writeStartElement(QStringLiteral("HeadingPairs"));
writer.writeStartElement(vt, QStringLiteral("vector"));
writer.writeAttribute(QStringLiteral("size"), QString::number(m_headingPairsList.size()*2));
writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("variant"));
typedef QPair<QString,int> PairType; //Make foreach happy
foreach (PairType pair, m_headingPairsList) {
writer.writeStartElement(vt, QStringLiteral("variant"));
writer.writeTextElement(vt, QStringLiteral("lpstr"), pair.first);
writer.writeEndElement(); //vt:variant
writer.writeStartElement(vt, QStringLiteral("variant"));
writer.writeTextElement(vt, QStringLiteral("i4"), QString::number(pair.second));
writer.writeEndElement(); //vt:variant
}
writer.writeEndElement();//vt:vector
writer.writeEndElement();//HeadingPairs
writer.writeStartElement(QStringLiteral("TitlesOfParts"));
writer.writeStartElement(vt, QStringLiteral("vector"));
writer.writeAttribute(QStringLiteral("size"), QString::number(m_titlesOfPartsList.size()));
writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("lpstr"));
foreach (QString title, m_titlesOfPartsList)
writer.writeTextElement(vt, QStringLiteral("lpstr"), title);
writer.writeEndElement();//vt:vector
writer.writeEndElement();//TitlesOfParts
if (m_properties.contains(QStringLiteral("manager")))
writer.writeTextElement(QStringLiteral("Manager"), m_properties[QStringLiteral("manager")]);
//Not like "manager", "company" always exists for Excel generated file.
writer.writeTextElement(QStringLiteral("Company"), m_properties.contains(QStringLiteral("company")) ? m_properties[QStringLiteral("company")]: QString());
writer.writeTextElement(QStringLiteral("LinksUpToDate"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("SharedDoc"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("HyperlinksChanged"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("AppVersion"), QStringLiteral("12.0000"));
writer.writeEndElement(); //Properties
writer.writeEndDocument();
}
bool DocPropsApp::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("Properties"))
continue;
if (reader.name() == QStringLiteral("Manager")) {
setProperty(QStringLiteral("manager"), reader.readElementText());
} else if (reader.name() == QStringLiteral("Company")) {
setProperty(QStringLiteral("company"), reader.readElementText());
}
}
if (reader.hasError()) {
qDebug("Error when read doc props app file.");
}
}
return true;
}
} //namespace

View File

@ -0,0 +1,168 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxdocpropscore_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QDebug>
#include <QBuffer>
namespace QXlsx {
DocPropsCore::DocPropsCore(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
bool DocPropsCore::setProperty(const QString &name, const QString &value)
{
static QStringList validKeys;
if (validKeys.isEmpty()) {
validKeys << QStringLiteral("title") << QStringLiteral("subject")
<< QStringLiteral("keywords") << QStringLiteral("description")
<< QStringLiteral("category") << QStringLiteral("status")
<< QStringLiteral("created") << QStringLiteral("creator");
}
if (!validKeys.contains(name))
return false;
if (value.isEmpty())
m_properties.remove(name);
else
m_properties[name] = value;
return true;
}
QString DocPropsCore::property(const QString &name) const
{
if (m_properties.contains(name))
return m_properties[name];
return QString();
}
QStringList DocPropsCore::propertyNames() const
{
return m_properties.keys();
}
void DocPropsCore::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/");
const QString dcterms = QStringLiteral("http://purl.org/dc/terms/");
const QString dcmitype = QStringLiteral("http://purl.org/dc/dcmitype/");
const QString xsi = QStringLiteral("http://www.w3.org/2001/XMLSchema-instance");
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("cp:coreProperties"));
writer.writeNamespace(cp, QStringLiteral("cp"));
writer.writeNamespace(dc, QStringLiteral("dc"));
writer.writeNamespace(dcterms, QStringLiteral("dcterms"));
writer.writeNamespace(dcmitype, QStringLiteral("dcmitype"));
writer.writeNamespace(xsi, QStringLiteral("xsi"));
if (m_properties.contains(QStringLiteral("title")))
writer.writeTextElement(dc, QStringLiteral("title"), m_properties[QStringLiteral("title")]);
if (m_properties.contains(QStringLiteral("subject")))
writer.writeTextElement(dc, QStringLiteral("subject"), m_properties[QStringLiteral("subject")]);
writer.writeTextElement(dc, QStringLiteral("creator"), m_properties.contains(QStringLiteral("creator")) ? m_properties[QStringLiteral("creator")] : QStringLiteral("Qt Xlsx Library"));
if (m_properties.contains(QStringLiteral("keywords")))
writer.writeTextElement(cp, QStringLiteral("keywords"), m_properties[QStringLiteral("keywords")]);
if (m_properties.contains(QStringLiteral("description")))
writer.writeTextElement(dc, QStringLiteral("description"), m_properties[QStringLiteral("description")]);
writer.writeTextElement(cp, QStringLiteral("lastModifiedBy"), m_properties.contains(QStringLiteral("creator")) ? m_properties[QStringLiteral("creator")] : QStringLiteral("Qt Xlsx Library"));
writer.writeStartElement(dcterms, QStringLiteral("created"));
writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF"));
writer.writeCharacters(m_properties.contains(QStringLiteral("created")) ? m_properties[QStringLiteral("created")] : QDateTime::currentDateTime().toString(Qt::ISODate));
writer.writeEndElement();//dcterms:created
writer.writeStartElement(dcterms, QStringLiteral("modified"));
writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF"));
writer.writeCharacters(QDateTime::currentDateTime().toString(Qt::ISODate));
writer.writeEndElement();//dcterms:created
if (m_properties.contains(QStringLiteral("category")))
writer.writeTextElement(cp, QStringLiteral("category"), m_properties[QStringLiteral("category")]);
if (m_properties.contains(QStringLiteral("status")))
writer.writeTextElement(cp, QStringLiteral("contentStatus"), m_properties[QStringLiteral("status")]);
writer.writeEndElement(); //cp:coreProperties
writer.writeEndDocument();
}
bool DocPropsCore::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/");
const QString dcterms = QStringLiteral("http://purl.org/dc/terms/");
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
const QStringRef nsUri = reader.namespaceUri();
const QStringRef name = reader.name();
if (name == QStringLiteral("subject") && nsUri == dc) {
setProperty(QStringLiteral("subject"), reader.readElementText());
} else if (name == QStringLiteral("title") && nsUri == dc) {
setProperty(QStringLiteral("title"), reader.readElementText());
} else if (name == QStringLiteral("creator") && nsUri == dc) {
setProperty(QStringLiteral("creator"), reader.readElementText());
} else if (name == QStringLiteral("description") && nsUri == dc) {
setProperty(QStringLiteral("description"), reader.readElementText());
} else if (name == QStringLiteral("keywords") && nsUri == cp) {
setProperty(QStringLiteral("keywords"), reader.readElementText());
} else if (name == QStringLiteral("created") && nsUri == dcterms) {
setProperty(QStringLiteral("created"), reader.readElementText());
} else if (name == QStringLiteral("category") && nsUri == cp) {
setProperty(QStringLiteral("category"), reader.readElementText());
} else if (name == QStringLiteral("contentStatus") && nsUri == cp) {
setProperty(QStringLiteral("status"), reader.readElementText());
}
}
if (reader.hasError()) {
qDebug()<<"Error when read doc props core file."<<reader.errorString();
}
}
return true;
}
} //namespace

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxdrawing_p.h"
#include "xlsxdrawinganchor_p.h"
#include "xlsxabstractsheet.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QBuffer>
namespace QXlsx {
Drawing::Drawing(AbstractSheet *sheet, CreateFlag flag)
:AbstractOOXmlFile(flag), sheet(sheet)
{
workbook = sheet->workbook();
}
Drawing::~Drawing()
{
qDeleteAll(anchors);
}
void Drawing::saveToXmlFile(QIODevice *device) const
{
relationships()->clear();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("xdr:wsDr"));
writer.writeAttribute(QStringLiteral("xmlns:xdr"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"));
writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main"));
foreach (DrawingAnchor *anchor, anchors)
anchor->saveToXml(writer);
writer.writeEndElement();//xdr:wsDr
writer.writeEndDocument();
}
bool Drawing::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("absoluteAnchor")) {
DrawingAbsoluteAnchor * anchor = new DrawingAbsoluteAnchor(this);
anchor->loadFromXml(reader);
} else if (reader.name() == QLatin1String("oneCellAnchor")) {
DrawingOneCellAnchor * anchor = new DrawingOneCellAnchor(this);
anchor->loadFromXml(reader);
} else if (reader.name() == QLatin1String("twoCellAnchor")) {
DrawingTwoCellAnchor * anchor = new DrawingTwoCellAnchor(this);
anchor->loadFromXml(reader);
}
}
}
return true;
}
} // namespace QXlsx

View File

@ -0,0 +1,529 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxdrawinganchor_p.h"
#include "xlsxdrawing_p.h"
#include "xlsxmediafile_p.h"
#include "xlsxchart.h"
#include "xlsxworkbook.h"
#include "xlsxutility_p.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QBuffer>
#include <QDir>
namespace QXlsx {
/*
The vertices that define the position of a graphical object
within the worksheet in pixels.
+------------+------------+
| A | B |
+-----+------------+------------+
| |(x1,y1) | |
| 1 |(A1)._______|______ |
| | | | |
| | | | |
+-----+----| OBJECT |-----+
| | | | |
| 2 | |______________. |
| | | (B2)|
| | | (x2,y2)|
+---- +------------+------------+
Example of an object that covers some of the area from cell A1 to B2.
Based on the width and height of the object we need to calculate 8 vars:
col_start, row_start, col_end, row_end, x1, y1, x2, y2.
We also calculate the absolute x and y position of the top left vertex of
the object. This is required for images.
The width and height of the cells that the object occupies can be
variable and have to be taken into account.
*/
//anchor
DrawingAnchor::DrawingAnchor(Drawing *drawing, ObjectType objectType)
:m_drawing(drawing), m_objectType(objectType)
{
m_drawing->anchors.append(this);
m_id = m_drawing->anchors.size();//must be unique in one drawing{x}.xml file.
}
DrawingAnchor::~DrawingAnchor()
{
}
void DrawingAnchor::setObjectPicture(const QImage &img)
{
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
img.save(&buffer, "PNG");
m_pictureFile = QSharedPointer<MediaFile>(new MediaFile(ba, QStringLiteral("png"), QStringLiteral("image/png")));
m_drawing->workbook->addMediaFile(m_pictureFile);
m_objectType = Picture;
}
void DrawingAnchor::setObjectGraphicFrame(QSharedPointer<Chart> chart)
{
m_chartFile = chart;
m_drawing->workbook->addChartFile(chart);
m_objectType = GraphicFrame;
}
QPoint DrawingAnchor::loadXmlPos(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("pos"));
QPoint pos;
QXmlStreamAttributes attrs = reader.attributes();
pos.setX(attrs.value(QLatin1String("x")).toString().toInt());
pos.setY(attrs.value(QLatin1String("y")).toString().toInt());
return pos;
}
QSize DrawingAnchor::loadXmlExt(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("ext"));
QSize size;
QXmlStreamAttributes attrs = reader.attributes();
size.setWidth(attrs.value(QLatin1String("cx")).toString().toInt());
size.setHeight(attrs.value(QLatin1String("cy")).toString().toInt());
return size;
}
XlsxMarker DrawingAnchor::loadXmlMarker(QXmlStreamReader &reader, const QString &node)
{
Q_ASSERT(reader.name() == node);
int col = 0;
int colOffset = 0;
int row = 0;
int rowOffset = 0;
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("col")) {
col = reader.readElementText().toInt();
} else if (reader.name() == QLatin1String("colOff")) {
colOffset = reader.readElementText().toInt();
} else if (reader.name() == QLatin1String("row")) {
row = reader.readElementText().toInt();
} else if (reader.name() == QLatin1String("rowOff")) {
rowOffset = reader.readElementText().toInt();
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == node) {
break;
}
}
return XlsxMarker(row, col, rowOffset, colOffset);
}
void DrawingAnchor::loadXmlObject(QXmlStreamReader &reader)
{
if (reader.name() == QLatin1String("sp")) {
//Shape
m_objectType = Shape;
loadXmlObjectShape(reader);
} else if (reader.name() == QLatin1String("grpSp")) {
//Group Shape
m_objectType = GroupShape;
loadXmlObjectGroupShape(reader);
} else if (reader.name() == QLatin1String("graphicFrame")) {
//Graphic Frame
m_objectType = GraphicFrame;
loadXmlObjectGraphicFrame(reader);
} else if (reader.name() == QLatin1String("cxnSp")) {
//Connection Shape
m_objectType = ConnectionShape;
loadXmlObjectConnectionShape(reader);
} else if (reader.name() == QLatin1String("pic")) {
//Picture
m_objectType = Picture;
loadXmlObjectPicture(reader);
}
}
void DrawingAnchor::loadXmlObjectConnectionShape(QXmlStreamReader &reader)
{
Q_UNUSED(reader)
}
void DrawingAnchor::loadXmlObjectGraphicFrame(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("graphicFrame"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("chart")) {
QString rId = reader.attributes().value(QLatin1String("r:id")).toString();
QString name = m_drawing->relationships()->getRelationshipById(rId).target;
QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name);
bool exist = false;
QList<QSharedPointer<Chart> > cfs = m_drawing->workbook->chartFiles();
for (int i=0; i<cfs.size(); ++i) {
if (cfs[i]->filePath() == path) {
//already exist
exist = true;
m_chartFile = cfs[i];
}
}
if (!exist) {
m_chartFile = QSharedPointer<Chart> (new Chart(m_drawing->sheet, Chart::F_LoadFromExists));
m_chartFile->setFilePath(path);
m_drawing->workbook->addChartFile(m_chartFile);
}
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("graphicFrame")) {
break;
}
}
return;
}
void DrawingAnchor::loadXmlObjectGroupShape(QXmlStreamReader &reader)
{
Q_UNUSED(reader)
}
void DrawingAnchor::loadXmlObjectPicture(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("pic"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("blip")) {
QString rId = reader.attributes().value(QLatin1String("r:embed")).toString();
QString name = m_drawing->relationships()->getRelationshipById(rId).target;
QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name);
bool exist = false;
QList<QSharedPointer<MediaFile> > mfs = m_drawing->workbook->mediaFiles();
for (int i=0; i<mfs.size(); ++i) {
if (mfs[i]->fileName() == path) {
//already exist
exist = true;
m_pictureFile = mfs[i];
}
}
if (!exist) {
m_pictureFile = QSharedPointer<MediaFile> (new MediaFile(path));
m_drawing->workbook->addMediaFile(m_pictureFile, true);
}
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("pic")) {
break;
}
}
return;
}
void DrawingAnchor::loadXmlObjectShape(QXmlStreamReader &reader)
{
Q_UNUSED(reader)
}
void DrawingAnchor::saveXmlPos(QXmlStreamWriter &writer, const QPoint &pos) const
{
writer.writeEmptyElement(QStringLiteral("xdr:pos"));
writer.writeAttribute(QStringLiteral("x"), QString::number(pos.x()));
writer.writeAttribute(QStringLiteral("y"), QString::number(pos.y()));
}
void DrawingAnchor::saveXmlExt(QXmlStreamWriter &writer, const QSize &ext) const
{
writer.writeStartElement(QStringLiteral("xdr:ext"));
writer.writeAttribute(QStringLiteral("cx"), QString::number(ext.width()));
writer.writeAttribute(QStringLiteral("cy"), QString::number(ext.height()));
writer.writeEndElement(); //xdr:ext
}
void DrawingAnchor::saveXmlMarker(QXmlStreamWriter &writer, const XlsxMarker &marker, const QString &node) const
{
writer.writeStartElement(node); //xdr:from or xdr:to
writer.writeTextElement(QStringLiteral("xdr:col"), QString::number(marker.col()));
writer.writeTextElement(QStringLiteral("xdr:colOff"), QString::number(marker.colOff()));
writer.writeTextElement(QStringLiteral("xdr:row"), QString::number(marker.row()));
writer.writeTextElement(QStringLiteral("xdr:rowOff"), QString::number(marker.rowOff()));
writer.writeEndElement();
}
void DrawingAnchor::saveXmlObject(QXmlStreamWriter &writer) const
{
if (m_objectType == Picture)
saveXmlObjectPicture(writer);
else if (m_objectType == ConnectionShape)
saveXmlObjectConnectionShape(writer);
else if (m_objectType == GraphicFrame)
saveXmlObjectGraphicFrame(writer);
else if (m_objectType == GroupShape)
saveXmlObjectGroupShape(writer);
else if (m_objectType == Shape)
saveXmlObjectShape(writer);
}
void DrawingAnchor::saveXmlObjectConnectionShape(QXmlStreamWriter &writer) const
{
Q_UNUSED(writer)
}
void DrawingAnchor::saveXmlObjectGraphicFrame(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:graphicFrame"));
writer.writeAttribute(QStringLiteral("macro"), QString());
writer.writeStartElement(QStringLiteral("xdr:nvGraphicFramePr"));
writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
writer.writeAttribute(QStringLiteral("id"), QString::number(m_id));
writer.writeAttribute(QStringLiteral("name"),QStringLiteral("Chart %1").arg(m_id));
writer.writeEmptyElement(QStringLiteral("xdr:cNvGraphicFramePr"));
writer.writeEndElement();//xdr:nvGraphicFramePr
writer.writeStartElement(QStringLiteral("xdr:xfrm"));
writer.writeEndElement(); //xdr:xfrm
writer.writeStartElement(QStringLiteral("a:graphic"));
writer.writeStartElement(QStringLiteral("a:graphicData"));
writer.writeAttribute(QStringLiteral("uri"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
int idx = m_drawing->workbook->chartFiles().indexOf(m_chartFile);
m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/chart"), QStringLiteral("../charts/chart%1.xml").arg(idx+1));
writer.writeEmptyElement(QStringLiteral("c:chart"));
writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count()));
writer.writeEndElement(); //a:graphicData
writer.writeEndElement(); //a:graphic
writer.writeEndElement(); //xdr:graphicFrame
}
void DrawingAnchor::saveXmlObjectGroupShape(QXmlStreamWriter &writer) const
{
Q_UNUSED(writer)
}
void DrawingAnchor::saveXmlObjectPicture(QXmlStreamWriter &writer) const
{
Q_ASSERT(m_objectType == Picture && !m_pictureFile.isNull());
writer.writeStartElement(QStringLiteral("xdr:pic"));
writer.writeStartElement(QStringLiteral("xdr:nvPicPr"));
writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
writer.writeAttribute(QStringLiteral("id"), QString::number(m_id));
writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Picture %1").arg(m_id));
writer.writeStartElement(QStringLiteral("xdr:cNvPicPr"));
writer.writeEmptyElement(QStringLiteral("a:picLocks"));
writer.writeAttribute(QStringLiteral("noChangeAspect"), QStringLiteral("1"));
writer.writeEndElement(); //xdr:cNvPicPr
writer.writeEndElement(); //xdr:nvPicPr
m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/image"), QStringLiteral("../media/image%1.%2")
.arg(m_pictureFile->index()+1)
.arg(m_pictureFile->suffix()));
writer.writeStartElement(QStringLiteral("xdr:blipFill"));
writer.writeEmptyElement(QStringLiteral("a:blip"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
writer.writeAttribute(QStringLiteral("r:embed"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count()));
writer.writeStartElement(QStringLiteral("a:stretch"));
writer.writeEmptyElement(QStringLiteral("a:fillRect"));
writer.writeEndElement(); //a:stretch
writer.writeEndElement();//xdr:blipFill
writer.writeStartElement(QStringLiteral("xdr:spPr"));
writer.writeStartElement(QStringLiteral("a:prstGeom"));
writer.writeAttribute(QStringLiteral("prst"), QStringLiteral("rect"));
writer.writeEmptyElement(QStringLiteral("a:avLst"));
writer.writeEndElement(); //a:prstGeom
writer.writeEndElement(); //xdr:spPr
writer.writeEndElement(); //xdr:pic
}
void DrawingAnchor::saveXmlObjectShape(QXmlStreamWriter &writer) const
{
Q_UNUSED(writer)
}
//absolute anchor
DrawingAbsoluteAnchor::DrawingAbsoluteAnchor(Drawing *drawing, ObjectType objectType)
:DrawingAnchor(drawing, objectType)
{
}
bool DrawingAbsoluteAnchor::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("absoluteAnchor"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("pos")) {
pos = loadXmlPos(reader);
} else if (reader.name() == QLatin1String("ext")) {
ext = loadXmlExt(reader);
} else {
loadXmlObject(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("absoluteAnchor")) {
break;
}
}
return true;
}
void DrawingAbsoluteAnchor::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:absoluteAnchor"));
saveXmlPos(writer, pos);
saveXmlExt(writer, ext);
saveXmlObject(writer);
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
writer.writeEndElement(); //xdr:absoluteAnchor
}
//one cell anchor
DrawingOneCellAnchor::DrawingOneCellAnchor(Drawing *drawing, ObjectType objectType)
:DrawingAnchor(drawing, objectType)
{
}
bool DrawingOneCellAnchor::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("oneCellAnchor"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("from")) {
from = loadXmlMarker(reader, QLatin1String("from"));
} else if (reader.name() == QLatin1String("ext")) {
ext = loadXmlExt(reader);
} else {
loadXmlObject(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("oneCellAnchor")) {
break;
}
}
return true;
}
void DrawingOneCellAnchor::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:oneCellAnchor"));
saveXmlMarker(writer, from, QStringLiteral("xdr:from"));
saveXmlExt(writer, ext);
saveXmlObject(writer);
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
writer.writeEndElement(); //xdr:oneCellAnchor
}
/*
Two cell anchor
This class specifies a two cell anchor placeholder for a group
, a shape, or a drawing element. It moves with
cells and its extents are in EMU units.
*/
DrawingTwoCellAnchor::DrawingTwoCellAnchor(Drawing *drawing, ObjectType objectType)
:DrawingAnchor(drawing, objectType)
{
}
bool DrawingTwoCellAnchor::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("twoCellAnchor"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("from")) {
from = loadXmlMarker(reader, QLatin1String("from"));
} else if (reader.name() == QLatin1String("to")) {
to = loadXmlMarker(reader, QLatin1String("to"));
} else {
loadXmlObject(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("twoCellAnchor")) {
break;
}
}
return true;
}
void DrawingTwoCellAnchor::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:twoCellAnchor"));
writer.writeAttribute(QStringLiteral("editAs"), QStringLiteral("oneCell"));
saveXmlMarker(writer, from, QStringLiteral("xdr:from"));
saveXmlMarker(writer, to, QStringLiteral("xdr:to"));
saveXmlObject(writer);
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
writer.writeEndElement(); //xdr:twoCellAnchor
}
} // namespace QXlsx

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxmediafile_p.h"
#include <QCryptographicHash>
namespace QXlsx {
MediaFile::MediaFile(const QByteArray &bytes, const QString &suffix, const QString &mimeType)
: m_contents(bytes), m_suffix(suffix), m_mimeType(mimeType)
, m_index(0), m_indexValid(false)
{
m_hashKey = QCryptographicHash::hash(m_contents, QCryptographicHash::Md5);
}
MediaFile::MediaFile(const QString &fileName)
:m_fileName(fileName), m_index(0), m_indexValid(false)
{
}
void MediaFile::set(const QByteArray &bytes, const QString &suffix, const QString &mimeType)
{
m_contents = bytes;
m_suffix = suffix;
m_mimeType = mimeType;
m_hashKey = QCryptographicHash::hash(m_contents, QCryptographicHash::Md5);
m_indexValid = false;
}
void MediaFile::setFileName(const QString &name)
{
m_fileName = name;
}
QString MediaFile::fileName() const
{
return m_fileName;
}
QString MediaFile::suffix() const
{
return m_suffix;
}
QString MediaFile::mimeType() const
{
return m_mimeType;
}
QByteArray MediaFile::contents() const
{
return m_contents;
}
int MediaFile::index() const
{
return m_index;
}
bool MediaFile::isIndexValid() const
{
return m_indexValid;
}
void MediaFile::setIndex(int idx)
{
m_index = idx;
m_indexValid = true;
}
QByteArray MediaFile::hashKey() const
{
return m_hashKey;
}
} // namespace QXlsx

View File

@ -0,0 +1,94 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxnumformatparser_p.h"
#include <QString>
namespace QXlsx {
bool NumFormatParser::isDateTime(const QString &formatCode)
{
for (int i = 0; i < formatCode.length(); ++i) {
const QChar &c = formatCode[i];
switch (c.unicode()) {
case '[':
// [h], [m], [s] are valid format for time
if (i < formatCode.length()-2 && formatCode[i+2] == QLatin1Char(']')) {
const QChar cc = formatCode[i+1].toLower();
if (cc == QLatin1Char('h') || cc == QLatin1Char('m') || cc == QLatin1Char('s'))
return true;
i+=2;
break;
} else {
// condition or color: don't care, ignore
while (i < formatCode.length() && formatCode[i] != QLatin1Char(']'))
++i;
break;
}
// quoted plain text block: don't care, ignore
case '"':
while (i < formatCode.length()-1 && formatCode[++i] != QLatin1Char('"'))
;
break;
// escaped char: don't care, ignore
case '\\':
if (i < formatCode.length() - 1)
++i;
break;
// date/time can only be positive number,
// so only the first section of the format make sense.
case ';':
return false;
break;
// days
case 'D':
case 'd':
// years
case 'Y':
case 'y':
// hours
case 'H':
case 'h':
// seconds
case 'S':
case 's':
// minutes or months, depending on context
case 'M':
case 'm':
return true;
default:
break;
}
}
return false;
}
} // namespace QXlsx

View File

@ -0,0 +1,189 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxrelationships_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QBuffer>
namespace QXlsx {
const QString schema_doc = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
const QString schema_msPackage = QStringLiteral("http://schemas.microsoft.com/office/2006/relationships");
const QString schema_package = QStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships");
//const QString schema_worksheet = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
Relationships::Relationships()
{
}
QList<XlsxRelationship> Relationships::documentRelationships(const QString &relativeType) const
{
return relationships(schema_doc + relativeType);
}
void Relationships::addDocumentRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_doc + relativeType, target);
}
QList<XlsxRelationship> Relationships::msPackageRelationships(const QString &relativeType) const
{
return relationships(schema_msPackage + relativeType);
}
void Relationships::addMsPackageRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_msPackage + relativeType, target);
}
QList<XlsxRelationship> Relationships::packageRelationships(const QString &relativeType) const
{
return relationships(schema_package + relativeType);
}
void Relationships::addPackageRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_package + relativeType, target);
}
QList<XlsxRelationship> Relationships::worksheetRelationships(const QString &relativeType) const
{
return relationships(schema_doc + relativeType);
}
void Relationships::addWorksheetRelationship(const QString &relativeType, const QString &target, const QString &targetMode)
{
addRelationship(schema_doc + relativeType, target, targetMode);
}
QList<XlsxRelationship> Relationships::relationships(const QString &type) const
{
QList<XlsxRelationship> res;
foreach (XlsxRelationship ship, m_relationships) {
if (ship.type == type)
res.append(ship);
}
return res;
}
void Relationships::addRelationship(const QString &type, const QString &target, const QString &targetMode)
{
XlsxRelationship relation;
relation.id = QStringLiteral("rId%1").arg(m_relationships.size()+1);
relation.type = type;
relation.target = target;
relation.targetMode = targetMode;
m_relationships.append(relation);
}
void Relationships::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Relationships"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships"));
foreach (XlsxRelationship relation, m_relationships) {
writer.writeStartElement(QStringLiteral("Relationship"));
writer.writeAttribute(QStringLiteral("Id"), relation.id);
writer.writeAttribute(QStringLiteral("Type"), relation.type);
writer.writeAttribute(QStringLiteral("Target"), relation.target);
if (!relation.targetMode.isNull())
writer.writeAttribute(QStringLiteral("TargetMode"), relation.targetMode);
writer.writeEndElement();
}
writer.writeEndElement();//Relationships
writer.writeEndDocument();
}
QByteArray Relationships::saveToXmlData() const
{
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
saveToXmlFile(&buffer);
return data;
}
bool Relationships::loadFromXmlFile(QIODevice *device)
{
clear();
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QStringLiteral("Relationship")) {
QXmlStreamAttributes attributes = reader.attributes();
XlsxRelationship relationship;
relationship.id = attributes.value(QLatin1String("Id")).toString();
relationship.type = attributes.value(QLatin1String("Type")).toString();
relationship.target = attributes.value(QLatin1String("Target")).toString();
relationship.targetMode = attributes.value(QLatin1String("TargetMode")).toString();
m_relationships.append(relationship);
}
}
if (reader.hasError())
return false;
}
return true;
}
bool Relationships::loadFromXmlData(const QByteArray &data)
{
QBuffer buffer;
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
return loadFromXmlFile(&buffer);
}
XlsxRelationship Relationships::getRelationshipById(const QString &id) const
{
foreach (XlsxRelationship ship, m_relationships) {
if (ship.id == id)
return ship;
}
return XlsxRelationship();
}
void Relationships::clear()
{
m_relationships.clear();
}
int Relationships::count() const
{
return m_relationships.count();
}
bool Relationships::isEmpty() const
{
return m_relationships.isEmpty();
}
} //namespace

View File

@ -0,0 +1,343 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxrichstring.h"
#include "xlsxrichstring_p.h"
#include "xlsxformat_p.h"
#include <QDebug>
#include <QTextDocument>
#include <QTextFragment>
QT_BEGIN_NAMESPACE_XLSX
RichStringPrivate::RichStringPrivate()
:_dirty(true)
{
}
RichStringPrivate::RichStringPrivate(const RichStringPrivate &other)
:QSharedData(other), fragmentTexts(other.fragmentTexts)
,fragmentFormats(other.fragmentFormats)
, _idKey(other.idKey()), _dirty(other._dirty)
{
}
RichStringPrivate::~RichStringPrivate()
{
}
/*!
\class RichString
\inmodule QtXlsx
\brief This class add support for the rich text string of the cell.
*/
/*!
Constructs a null string.
*/
RichString::RichString()
:d(new RichStringPrivate)
{
}
/*!
Constructs a plain string with the given \a text.
*/
RichString::RichString(const QString text)
:d(new RichStringPrivate)
{
addFragment(text, Format());
}
/*!
Constructs a copy of \a other.
*/
RichString::RichString(const RichString &other)
:d(other.d)
{
}
/*!
Destructs the string.
*/
RichString::~RichString()
{
}
/*!
Assigns \a other to this string and returns a reference to this string
*/
RichString &RichString::operator =(const RichString &other)
{
this->d = other.d;
return *this;
}
/*!
Returns the rich string as a QVariant
*/
RichString::operator QVariant() const
{
return QVariant(qMetaTypeId<RichString>(), this);
}
/*!
Returns true if this is rich text string.
*/
bool RichString::isRichString() const
{
if (fragmentCount() > 1) //Is this enough??
return true;
return false;
}
/*!
Returns true is this is an Null string.
*/
bool RichString::isNull() const
{
return d->fragmentTexts.size() == 0;
}
/*!
Returns true is this is an empty string.
*/
bool RichString::isEmtpy() const
{
foreach (const QString str, d->fragmentTexts) {
if (!str.isEmpty())
return false;
}
return true;
}
/*!
Converts to plain text string.
*/
QString RichString::toPlainString() const
{
if (isEmtpy())
return QString();
if (d->fragmentTexts.size() == 1)
return d->fragmentTexts[0];
return d->fragmentTexts.join(QString());
}
/*!
Converts to html string
*/
QString RichString::toHtml() const
{
//: Todo
return QString();
}
/*!
Replaces the entire contents of the document
with the given HTML-formatted text in the \a text string
*/
void RichString::setHtml(const QString &text)
{
QTextDocument doc;
doc.setHtml(text);
QTextBlock block = doc.firstBlock();
QTextBlock::iterator it;
for (it = block.begin(); !(it.atEnd()); ++it) {
QTextFragment textFragment = it.fragment();
if (textFragment.isValid()) {
Format fmt;
fmt.setFont(textFragment.charFormat().font());
fmt.setFontColor(textFragment.charFormat().foreground().color());
addFragment(textFragment.text(), fmt);
}
}
}
/*!
Returns fragment count.
*/
int RichString::fragmentCount() const
{
return d->fragmentTexts.size();
}
/*!
Appends a fragment with the given \a text and \a format.
*/
void RichString::addFragment(const QString &text, const Format &format)
{
d->fragmentTexts.append(text);
d->fragmentFormats.append(format);
d->_dirty = true;
}
/*!
Returns fragment text at the position \a index.
*/
QString RichString::fragmentText(int index) const
{
if (index < 0 || index >= fragmentCount())
return QString();
return d->fragmentTexts[index];
}
/*!
Returns fragment format at the position \a index.
*/
Format RichString::fragmentFormat(int index) const
{
if (index < 0 || index >= fragmentCount())
return Format();
return d->fragmentFormats[index];
}
/*!
* \internal
*/
QByteArray RichStringPrivate::idKey() const
{
if (_dirty) {
RichStringPrivate *rs = const_cast<RichStringPrivate *>(this);
QByteArray bytes;
if (fragmentTexts.size() == 1) {
bytes = fragmentTexts[0].toUtf8();
} else {
//Generate a hash value base on QByteArray ?
bytes.append("@@QtXlsxRichString=");
for (int i=0; i<fragmentTexts.size(); ++i) {
bytes.append("@Text");
bytes.append(fragmentTexts[i].toUtf8());
bytes.append("@Format");
if (fragmentFormats[i].hasFontData())
bytes.append(fragmentFormats[i].fontKey());
}
}
rs->_idKey = bytes;
rs->_dirty = false;
}
return _idKey;
}
/*!
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator==(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return false;
return rs1.d->idKey() == rs2.d->idKey();
}
/*!
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator!=(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return true;
return rs1.d->idKey() != rs2.d->idKey();
}
/*!
* \internal
*/
bool operator<(const RichString &rs1, const RichString &rs2)
{
return rs1.d->idKey() < rs2.d->idKey();
}
/*!
\overload
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator ==(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return true;
return false;
}
/*!
\overload
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator !=(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return false;
return true;
}
/*!
\overload
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator ==(const QString &rs1, const RichString &rs2)
{
return rs2 == rs1;
}
/*!
\overload
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator !=(const QString &rs1, const RichString &rs2)
{
return rs2 != rs1;
}
uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW
{
return qHash(rs.d->idKey(), seed);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const RichString &rs)
{
dbg.nospace() << "QXlsx::RichString(" << rs.d->fragmentTexts << ")";
return dbg.space();
}
#endif
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,400 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxrichstring.h"
#include "xlsxsharedstrings_p.h"
#include "xlsxutility_p.h"
#include "xlsxformat_p.h"
#include "xlsxcolor_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDebug>
#include <QBuffer>
namespace QXlsx {
/*
* Note that, when we open an existing .xlsx file (broken file?),
* duplicated string items may exist in the shared string table.
*
* In such case, the size of stringList will larger than stringTable.
* Duplicated items can be removed once we loaded all the worksheets.
*/
SharedStrings::SharedStrings(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
m_stringCount = 0;
}
int SharedStrings::count() const
{
return m_stringCount;
}
bool SharedStrings::isEmpty() const
{
return m_stringList.isEmpty();
}
int SharedStrings::addSharedString(const QString &string)
{
return addSharedString(RichString(string));
}
int SharedStrings::addSharedString(const RichString &string)
{
m_stringCount += 1;
if (m_stringTable.contains(string)) {
XlsxSharedStringInfo &item = m_stringTable[string];
item.count += 1;
return item.index;
}
int index = m_stringList.size();
m_stringTable[string] = XlsxSharedStringInfo(index);
m_stringList.append(string);
return index;
}
void SharedStrings::incRefByStringIndex(int idx)
{
if (idx <0 || idx >= m_stringList.size()) {
qDebug("SharedStrings: invlid index");
return;
}
addSharedString(m_stringList[idx]);
}
/*
* Broken, don't use.
*/
void SharedStrings::removeSharedString(const QString &string)
{
removeSharedString(RichString(string));
}
/*
* Broken, don't use.
*/
void SharedStrings::removeSharedString(const RichString &string)
{
if (!m_stringTable.contains(string))
return;
m_stringCount -= 1;
XlsxSharedStringInfo &item = m_stringTable[string];
item.count -= 1;
if (item.count <= 0) {
for (int i=item.index+1; i<m_stringList.size(); ++i)
m_stringTable[m_stringList[i]].index -= 1;
m_stringList.removeAt(item.index);
m_stringTable.remove(string);
}
}
int SharedStrings::getSharedStringIndex(const QString &string) const
{
return getSharedStringIndex(RichString(string));
}
int SharedStrings::getSharedStringIndex(const RichString &string) const
{
if (m_stringTable.contains(string))
return m_stringTable[string].index;
return -1;
}
RichString SharedStrings::getSharedString(int index) const
{
if (index < m_stringList.count() && index >= 0)
return m_stringList[index];
return RichString();
}
QList<RichString> SharedStrings::getSharedStrings() const
{
return m_stringList;
}
void SharedStrings::writeRichStringPart_rPr(QXmlStreamWriter &writer, const Format &format) const
{
if (!format.hasFontData())
return;
if (format.fontBold())
writer.writeEmptyElement(QStringLiteral("b"));
if (format.fontItalic())
writer.writeEmptyElement(QStringLiteral("i"));
if (format.fontStrikeOut())
writer.writeEmptyElement(QStringLiteral("strike"));
if (format.fontOutline())
writer.writeEmptyElement(QStringLiteral("outline"));
if (format.boolProperty(FormatPrivate::P_Font_Shadow))
writer.writeEmptyElement(QStringLiteral("shadow"));
if (format.hasProperty(FormatPrivate::P_Font_Underline)) {
Format::FontUnderline u = format.fontUnderline();
if (u != Format::FontUnderlineNone) {
writer.writeEmptyElement(QStringLiteral("u"));
if (u== Format::FontUnderlineDouble)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double"));
else if (u == Format::FontUnderlineSingleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting"));
else if (u == Format::FontUnderlineDoubleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting"));
}
}
if (format.hasProperty(FormatPrivate::P_Font_Script)) {
Format::FontScript s = format.fontScript();
if (s != Format::FontScriptNormal) {
writer.writeEmptyElement(QStringLiteral("vertAlign"));
if (s == Format::FontScriptSuper)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript"));
else
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript"));
}
}
if (format.hasProperty(FormatPrivate::P_Font_Size)) {
writer.writeEmptyElement(QStringLiteral("sz"));
writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize()));
}
if (format.hasProperty(FormatPrivate::P_Font_Color)) {
XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>();
color.saveToXml(writer);
}
if (!format.fontName().isEmpty()) {
writer.writeEmptyElement(QStringLiteral("rFont"));
writer.writeAttribute(QStringLiteral("val"), format.fontName());
}
if (format.hasProperty(FormatPrivate::P_Font_Family)) {
writer.writeEmptyElement(QStringLiteral("family"));
writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family)));
}
if (format.hasProperty(FormatPrivate::P_Font_Scheme)) {
writer.writeEmptyElement(QStringLiteral("scheme"));
writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme));
}
}
void SharedStrings::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
if (m_stringList.size() != m_stringTable.size()) {
//Duplicated string items exist in m_stringList
//Clean up can not be done here, as the indices
//have been used when we save the worksheets part.
}
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("sst"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount));
writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringList.size()));
foreach (RichString string, m_stringList) {
writer.writeStartElement(QStringLiteral("si"));
if (string.isRichString()) {
//Rich text string
for (int i=0; i<string.fragmentCount(); ++i) {
writer.writeStartElement(QStringLiteral("r"));
if (string.fragmentFormat(i).hasFontData()) {
writer.writeStartElement(QStringLiteral("rPr"));
writeRichStringPart_rPr(writer, string.fragmentFormat(i));
writer.writeEndElement();// rPr
}
writer.writeStartElement(QStringLiteral("t"));
if (isSpaceReserveNeeded(string.fragmentText(i)))
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(string.fragmentText(i));
writer.writeEndElement();// t
writer.writeEndElement(); //r
}
} else {
writer.writeStartElement(QStringLiteral("t"));
QString pString = string.toPlainString();
if (isSpaceReserveNeeded(pString))
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(pString);
writer.writeEndElement();//t
}
writer.writeEndElement();//si
}
writer.writeEndElement(); //sst
writer.writeEndDocument();
}
void SharedStrings::readString(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("si"));
RichString richString;
while (!reader.atEnd() && !(reader.name() == QLatin1String("si") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("r"))
readRichStringPart(reader, richString);
else if (reader.name() == QLatin1String("t"))
readPlainStringPart(reader, richString);
}
}
int idx = m_stringList.size();
m_stringTable[richString] = XlsxSharedStringInfo(idx, 0);
m_stringList.append(richString);
}
void SharedStrings::readRichStringPart(QXmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("r"));
QString text;
Format format;
while (!reader.atEnd() && !(reader.name() == QLatin1String("r") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("rPr")) {
format = readRichStringPart_rPr(reader);
} else if (reader.name() == QLatin1String("t")) {
text = reader.readElementText();
}
}
}
richString.addFragment(text, format);
}
void SharedStrings::readPlainStringPart(QXmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("t"));
//QXmlStreamAttributes attributes = reader.attributes();
QString text = reader.readElementText();
richString.addFragment(text, Format());
}
Format SharedStrings::readRichStringPart_rPr(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("rPr"));
Format format;
while (!reader.atEnd() && !(reader.name() == QLatin1String("rPr") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
QXmlStreamAttributes attributes = reader.attributes();
if (reader.name() == QLatin1String("rFont")) {
format.setFontName(attributes.value(QLatin1String("val")).toString());
} else if (reader.name() == QLatin1String("charset")) {
format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("family")) {
format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("b")) {
format.setFontBold(true);
} else if (reader.name() == QLatin1String("i")) {
format.setFontItalic(true);
} else if (reader.name() == QLatin1String("strike")) {
format.setFontStrikeOut(true);
} else if (reader.name() == QLatin1String("outline")) {
format.setFontOutline(true);
} else if (reader.name() == QLatin1String("shadow")) {
format.setProperty(FormatPrivate::P_Font_Shadow, true);
} else if (reader.name() == QLatin1String("condense")) {
format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("extend")) {
format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
format.setProperty(FormatPrivate::P_Font_Color, color);
} else if (reader.name() == QLatin1String("sz")) {
format.setFontSize(attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("u")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("double"))
format.setFontUnderline(Format::FontUnderlineDouble);
else if (value == QLatin1String("doubleAccounting"))
format.setFontUnderline(Format::FontUnderlineDoubleAccounting);
else if (value == QLatin1String("singleAccounting"))
format.setFontUnderline(Format::FontUnderlineSingleAccounting);
else
format.setFontUnderline(Format::FontUnderlineSingle);
} else if (reader.name() == QLatin1String("vertAlign")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("superscript"))
format.setFontScript(Format::FontScriptSuper);
else if (value == QLatin1String("subscript"))
format.setFontScript(Format::FontScriptSub);
} else if (reader.name() == QLatin1String("scheme")) {
format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString());
}
}
}
return format;
}
bool SharedStrings::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
int count = 0;
bool hasUniqueCountAttr=true;
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("sst")) {
QXmlStreamAttributes attributes = reader.attributes();
if ((hasUniqueCountAttr = attributes.hasAttribute(QLatin1String("uniqueCount"))))
count = attributes.value(QLatin1String("uniqueCount")).toString().toInt();
} else if (reader.name() == QLatin1String("si")) {
readString(reader);
}
}
}
if (hasUniqueCountAttr && m_stringList.size() != count) {
qDebug("Error: Shared string count");
return false;
}
if (m_stringList.size() != m_stringTable.size()) {
//qDebug("Warning: Duplicated items exist in shared string table.");
//Nothing we can do here, as indices of the strings will be used when loading sheets.
}
return true;
}
} //namespace

View File

@ -0,0 +1,56 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxsimpleooxmlfile_p.h"
#include <QIODevice>
namespace QXlsx {
SimpleOOXmlFile::SimpleOOXmlFile(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void SimpleOOXmlFile::saveToXmlFile(QIODevice *device) const
{
device->write(xmlData);
}
QByteArray SimpleOOXmlFile::saveToXmlData() const
{
return xmlData;
}
bool SimpleOOXmlFile::loadFromXmlData(const QByteArray &data)
{
xmlData = data;
return true;
}
bool SimpleOOXmlFile::loadFromXmlFile(QIODevice *device)
{
xmlData = device->readAll();
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxtheme_p.h"
#include <QIODevice>
namespace QXlsx {
const char *defaultXmlData =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office \xe4\xb8\xbb\xe9\xa2\x98\">"
"<a:themeElements>"
"<a:clrScheme name=\"Office\">"
"<a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1>"
"<a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1>"
"<a:dk2><a:srgbClr val=\"1F497D\"/></a:dk2>"
"<a:lt2><a:srgbClr val=\"EEECE1\"/></a:lt2>"
"<a:accent1><a:srgbClr val=\"4F81BD\"/></a:accent1>"
"<a:accent2><a:srgbClr val=\"C0504D\"/></a:accent2>"
"<a:accent3><a:srgbClr val=\"9BBB59\"/></a:accent3>"
"<a:accent4><a:srgbClr val=\"8064A2\"/></a:accent4>"
"<a:accent5><a:srgbClr val=\"4BACC6\"/></a:accent5>"
"<a:accent6><a:srgbClr val=\"F79646\"/></a:accent6>"
"<a:hlink><a:srgbClr val=\"0000FF\"/></a:hlink>"
"<a:folHlink><a:srgbClr val=\"800080\"/></a:folHlink>"
"</a:clrScheme>"
"<a:fontScheme name=\"Office\">"
"<a:majorFont>"
"<a:latin typeface=\"Cambria\"/>"
"<a:ea typeface=\"\"/>"
"<a:cs typeface=\"\"/>"
"<a:font script=\"Jpan\" typeface=\"\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf\"/>"
"<a:font script=\"Hang\" typeface=\"\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95\"/>"
"<a:font script=\"Hans\" typeface=\"\xe5\xae\x8b\xe4\xbd\x93\"/>"
"<a:font script=\"Hant\" typeface=\"\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94\"/>"
"<a:font script=\"Arab\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Hebr\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Thai\" typeface=\"Tahoma\"/>"
"<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
"<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
"<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
"<a:font script=\"Khmr\" typeface=\"MoolBoran\"/>"
"<a:font script=\"Knda\" typeface=\"Tunga\"/>"
"<a:font script=\"Guru\" typeface=\"Raavi\"/>"
"<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
"<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
"<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
"<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
"<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
"<a:font script=\"Deva\" typeface=\"Mangal\"/>"
"<a:font script=\"Telu\" typeface=\"Gautami\"/>"
"<a:font script=\"Taml\" typeface=\"Latha\"/>"
"<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
"<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
"<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
"<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
"<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
"<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
"<a:font script=\"Viet\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
"</a:majorFont>"
"<a:minorFont>"
"<a:latin typeface=\"Calibri\"/>"
"<a:ea typeface=\"\"/>"
"<a:cs typeface=\"\"/>"
"<a:font script=\"Jpan\" typeface=\"\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf\"/>"
"<a:font script=\"Hang\" typeface=\"\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95\"/>"
"<a:font script=\"Hans\" typeface=\"\xe5\xae\x8b\xe4\xbd\x93\"/>"
"<a:font script=\"Hant\" typeface=\"\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94\"/>"
"<a:font script=\"Arab\" typeface=\"Arial\"/>"
"<a:font script=\"Hebr\" typeface=\"Arial\"/>"
"<a:font script=\"Thai\" typeface=\"Tahoma\"/>"
"<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
"<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
"<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
"<a:font script=\"Khmr\" typeface=\"DaunPenh\"/>"
"<a:font script=\"Knda\" typeface=\"Tunga\"/>"
"<a:font script=\"Guru\" typeface=\"Raavi\"/>"
"<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
"<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
"<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
"<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
"<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
"<a:font script=\"Deva\" typeface=\"Mangal\"/>"
"<a:font script=\"Telu\" typeface=\"Gautami\"/>"
"<a:font script=\"Taml\" typeface=\"Latha\"/>"
"<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
"<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
"<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
"<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
"<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
"<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
"<a:font script=\"Viet\" typeface=\"Arial\"/>"
"<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
"</a:minorFont>"
"</a:fontScheme>"
"<a:fmtScheme name=\"Office\">"
"<a:fillStyleLst>"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"50000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"35000\"><a:schemeClr val=\"phClr\"><a:tint val=\"37000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:tint val=\"15000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:lin ang=\"16200000\" scaled=\"1\"/>"
"</a:gradFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:shade val=\"51000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"80000\"><a:schemeClr val=\"phClr\"><a:shade val=\"93000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"94000\"/><a:satMod val=\"135000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:lin ang=\"16200000\" scaled=\"0\"/>"
"</a:gradFill>"
"</a:fillStyleLst>"
"<a:lnStyleLst>"
"<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"><a:shade val=\"95000\"/><a:satMod val=\"105000\"/></a:schemeClr></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"<a:ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"<a:ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"</a:lnStyleLst>"
"<a:effectStyleLst>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"38000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"</a:effectStyle>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"</a:effectStyle>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"<a:scene3d>"
"<a:camera prst=\"orthographicFront\"><a:rot lat=\"0\" lon=\"0\" rev=\"0\"/></a:camera>"
"<a:lightRig rig=\"threePt\" dir=\"t\"><a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/></a:lightRig>"
"</a:scene3d>"
"<a:sp3d><a:bevelT w=\"63500\" h=\"25400\"/></a:sp3d>"
"</a:effectStyle>"
"</a:effectStyleLst>"
"<a:bgFillStyleLst>"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"40000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"40000\"><a:schemeClr val=\"phClr\"><a:tint val=\"45000\"/><a:shade val=\"99000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"20000\"/><a:satMod val=\"255000\"/></a:schemeClr></a:gs></a:gsLst>"
"<a:path path=\"circle\"><a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/></a:path>"
"</a:gradFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"80000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"30000\"/><a:satMod val=\"200000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:path path=\"circle\"><a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/></a:path>"
"</a:gradFill>"
"</a:bgFillStyleLst>"
"</a:fmtScheme>"
"</a:themeElements>"
"<a:objectDefaults/>"
"<a:extraClrSchemeLst/>"
"</a:theme>"
;
Theme::Theme(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void Theme::saveToXmlFile(QIODevice *device) const
{
if (xmlData.isEmpty())
device->write(defaultXmlData);
else
device->write(xmlData);
}
QByteArray Theme::saveToXmlData() const
{
if (xmlData.isEmpty())
return defaultXmlData;
else
return xmlData;
}
bool Theme::loadFromXmlData(const QByteArray &data)
{
xmlData = data;
return true;
}
bool Theme::loadFromXmlFile(QIODevice *device)
{
xmlData = device->readAll();
return true;
}
}

View File

@ -0,0 +1,276 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxutility_p.h"
#include "xlsxcellreference.h"
#include <QString>
#include <QPoint>
#include <QRegularExpression>
#include <QMap>
#include <QStringList>
#include <QColor>
#include <QDateTime>
#include <QDebug>
namespace QXlsx {
bool parseXsdBoolean(const QString &value, bool defaultValue)
{
if (value == QLatin1String("1") || value == QLatin1String("true"))
return true;
if (value == QLatin1String("0") || value == QLatin1String("false"))
return false;
return defaultValue;
}
QStringList splitPath(const QString &path)
{
int idx = path.lastIndexOf(QLatin1Char('/'));
if (idx == -1)
return QStringList()<<QStringLiteral(".")<<path;
return QStringList()<<path.left(idx)<<path.mid(idx+1);
}
/*
* Return the .rel file path based on filePath
*/
QString getRelFilePath(const QString &filePath)
{
int idx = filePath.lastIndexOf(QLatin1Char('/'));
if (idx == -1)
return QString();
return QString(filePath.left(idx) + QLatin1String("/_rels/")
+ filePath.mid(idx+1) + QLatin1String(".rels"));
}
double datetimeToNumber(const QDateTime &dt, bool is1904)
{
//Note, for number 0, Excel2007 shown as 1900-1-0, which should be 1899-12-31
QDateTime epoch(is1904 ? QDate(1904, 1, 1): QDate(1899, 12, 31), QTime(0,0));
double excel_time = epoch.msecsTo(dt) / (1000*60*60*24.0);
#if QT_VERSION >= 0x050200
if (dt.isDaylightTime()) // Add one hour if the date is Daylight
excel_time += 1.0 / 24.0;
#endif
if (!is1904 && excel_time > 59) {//31+28
//Account for Excel erroneously treating 1900 as a leap year.
excel_time += 1;
}
return excel_time;
}
double timeToNumber(const QTime &time)
{
return QTime(0,0).msecsTo(time) / (1000*60*60*24.0);
}
QDateTime datetimeFromNumber(double num, bool is1904)
{
if (!is1904 && num > 60)
num = num - 1;
qint64 msecs = static_cast<qint64>(num * 1000*60*60*24.0 + 0.5);
QDateTime epoch(is1904 ? QDate(1904, 1, 1): QDate(1899, 12, 31), QTime(0,0));
QDateTime dt = epoch.addMSecs(msecs);
#if QT_VERSION >= 0x050200
// Remove one hour to see whether the date is Daylight
QDateTime dt2 = dt.addMSecs(-3600);
if (dt2.isDaylightTime())
return dt2;
#endif
return dt;
}
/*
Creates a valid sheet name
minimum length is 1
maximum length is 31
doesn't contain special chars: / \ ? * ] [ :
Sheet names must not begin or end with ' (apostrophe)
Invalid characters are replaced by one space character ' '.
*/
QString createSafeSheetName(const QString &nameProposal)
{
if (nameProposal.isEmpty())
return QString();
QString ret = nameProposal;
if (nameProposal.length() > 2 && nameProposal.startsWith(QLatin1Char('\'')) && nameProposal.endsWith(QLatin1Char('\'')))
ret = unescapeSheetName(ret);
//Replace invalid chars with space.
if (nameProposal.contains(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]"))))
ret.replace(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]")), QStringLiteral(" "));
if (ret.startsWith(QLatin1Char('\'')))
ret[0] = QLatin1Char(' ');
if (ret.endsWith(QLatin1Char('\'')))
ret[ret.size()-1] = QLatin1Char(' ');
if (ret.size() > 31)
ret = ret.left(31);
return ret;
}
/*
* When sheetName contains space or apostrophe, escaped is needed by cellFormula/definedName/chartSerials.
*/
QString escapeSheetName(const QString &sheetName)
{
//Already escaped.
Q_ASSERT(!sheetName.startsWith(QLatin1Char('\'')) && !sheetName.endsWith(QLatin1Char('\'')));
//These is no need to escape
if (!sheetName.contains(QRegularExpression(QStringLiteral("[ +\\-,%^=<>'&]"))))
return sheetName;
//OK, escape is needed.
QString name = sheetName;
name.replace(QLatin1Char('\''), QLatin1String("\'\'"));
return QLatin1Char('\'') + name + QLatin1Char('\'');
}
/*
*/
QString unescapeSheetName(const QString &sheetName)
{
Q_ASSERT(sheetName.length() > 2 && sheetName.startsWith(QLatin1Char('\'')) && sheetName.endsWith(QLatin1Char('\'')));
QString name = sheetName.mid(1, sheetName.length()-2);
name.replace(QLatin1String("\'\'"), QLatin1String("\'"));
return name;
}
/*
* whether the string s starts or ends with space
*/
bool isSpaceReserveNeeded(const QString &s)
{
QString spaces(QStringLiteral(" \t\n\r"));
return !s.isEmpty() && (spaces.contains(s.at(0))||spaces.contains(s.at(s.length()-1)));
}
/*
* Convert shared formula for non-root cells.
*
* For example, if "B1:B10" have shared formula "=A1*A1", this function will return "=A2*A2"
* for "B2" cell, "=A3*A3" for "B3" cell, etc.
*
* Note, the formula "=A1*A1" for B1 can also be written as "=RC[-1]*RC[-1]", which is the same
* for all other cells. In other words, this formula is shared.
*
* For long run, we need a formula parser.
*/
QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell)
{
//Find all the "$?[A-Z]+$?[0-9]+" patterns in the rootFormula.
QList<QPair<QString, int> > segments;
QString segment;
bool inQuote = false;
enum RefState{INVALID, PRE_AZ, AZ, PRE_09, _09};
RefState refState = INVALID;
int refFlag = 0; // 0x00, 0x01, 0x02, 0x03 ==> A1, $A1, A$1, $A$1
foreach (QChar ch, rootFormula) {
if (inQuote) {
segment.append(ch);
if (ch == QLatin1Char('"'))
inQuote = false;
} else {
if (ch == QLatin1Char('"')) {
inQuote = true;
refState = INVALID;
segment.append(ch);
} else if (ch == QLatin1Char('$')) {
if (refState == AZ) {
segment.append(ch);
refState = PRE_09;
refFlag |= 0x02;
} else {
segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
segment = QString(ch); //Start new segment.
refState = PRE_AZ;
refFlag = 0x01;
}
} else if (ch >= QLatin1Char('A') && ch <=QLatin1Char('Z')) {
if (refState == PRE_AZ || refState == AZ) {
segment.append(ch);
} else {
segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
segment = QString(ch); //Start new segment.
refFlag = 0x00;
}
refState = AZ;
} else if (ch >= QLatin1Char('0') && ch <=QLatin1Char('9')) {
segment.append(ch);
if (refState == AZ || refState == PRE_09 || refState == _09)
refState = _09;
else
refState = INVALID;
} else {
if (refState == _09) {
segments.append(qMakePair(segment, refFlag));
segment = QString(ch); //Start new segment.
} else {
segment.append(ch);
}
refState = INVALID;
}
}
}
if (!segment.isEmpty())
segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
//Replace "A1", "$A1", "A$1" segment with proper one.
QStringList result;
typedef QPair<QString, int> PairType;
foreach (PairType p, segments) {
//qDebug()<<p.first<<p.second;
if (p.second != -1 && p.second != 3) {
CellReference oldRef(p.first);
int row = p.second & 0x02 ? oldRef.row() : oldRef.row()-rootCell.row()+cell.row();
int col = p.second & 0x01 ? oldRef.column() : oldRef.column()-rootCell.column()+cell.column();
result.append(CellReference(row, col).toString(p.second & 0x02, p.second & 0x01));
} else {
result.append(p.first);
}
}
//OK
return result.join(QString());
}
} //namespace QXlsx

View File

@ -0,0 +1,693 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxworkbook.h"
#include "xlsxworkbook_p.h"
#include "xlsxsharedstrings_p.h"
#include "xlsxworksheet.h"
#include "xlsxchartsheet.h"
#include "xlsxstyles_p.h"
#include "xlsxformat.h"
#include "xlsxworksheet_p.h"
#include "xlsxformat_p.h"
#include "xlsxmediafile_p.h"
#include "xlsxutility_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QFile>
#include <QBuffer>
#include <QDir>
QT_BEGIN_NAMESPACE_XLSX
WorkbookPrivate::WorkbookPrivate(Workbook *q, Workbook::CreateFlag flag) :
AbstractOOXmlFilePrivate(q, flag)
{
sharedStrings = QSharedPointer<SharedStrings> (new SharedStrings(flag));
styles = QSharedPointer<Styles>(new Styles(flag));
theme = QSharedPointer<Theme>(new Theme(flag));
x_window = 240;
y_window = 15;
window_width = 16095;
window_height = 9660;
strings_to_numbers_enabled = false;
strings_to_hyperlinks_enabled = true;
html_to_richstring_enabled = false;
date1904 = false;
defaultDateFormat = QStringLiteral("yyyy-mm-dd");
activesheetIndex = 0;
firstsheet = 0;
table_count = 0;
last_worksheet_index = 0;
last_chartsheet_index = 0;
last_sheet_id = 0;
}
Workbook::Workbook(CreateFlag flag)
: AbstractOOXmlFile(new WorkbookPrivate(this, flag))
{
}
Workbook::~Workbook()
{
}
bool Workbook::isDate1904() const
{
Q_D(const Workbook);
return d->date1904;
}
/*!
Excel for Windows uses a default epoch of 1900 and Excel
for Mac uses an epoch of 1904. However, Excel on either
platform will convert automatically between one system
and the other. Qt Xlsx stores dates in the 1900 format
by default.
\note This function should be called before any date/time
has been written.
*/
void Workbook::setDate1904(bool date1904)
{
Q_D(Workbook);
d->date1904 = date1904;
}
/*
Enable the worksheet.write() method to convert strings
to numbers, where possible, using float() in order to avoid
an Excel warning about "Numbers Stored as Text".
The default is false
*/
void Workbook::setStringsToNumbersEnabled(bool enable)
{
Q_D(Workbook);
d->strings_to_numbers_enabled = enable;
}
bool Workbook::isStringsToNumbersEnabled() const
{
Q_D(const Workbook);
return d->strings_to_numbers_enabled;
}
void Workbook::setStringsToHyperlinksEnabled(bool enable)
{
Q_D(Workbook);
d->strings_to_hyperlinks_enabled = enable;
}
bool Workbook::isStringsToHyperlinksEnabled() const
{
Q_D(const Workbook);
return d->strings_to_hyperlinks_enabled;
}
void Workbook::setHtmlToRichStringEnabled(bool enable)
{
Q_D(Workbook);
d->html_to_richstring_enabled = enable;
}
bool Workbook::isHtmlToRichStringEnabled() const
{
Q_D(const Workbook);
return d->html_to_richstring_enabled;
}
QString Workbook::defaultDateFormat() const
{
Q_D(const Workbook);
return d->defaultDateFormat;
}
void Workbook::setDefaultDateFormat(const QString &format)
{
Q_D(Workbook);
d->defaultDateFormat = format;
}
/*!
* \brief Create a defined name in the workbook.
* \param name The defined name
* \param formula The cell or range that the defined name refers to.
* \param comment
* \param scope The name of one worksheet, or empty which means golbal scope.
* \return Return false if the name invalid.
*/
bool Workbook::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope)
{
Q_D(Workbook);
//Remove the = sign from the formula if it exists.
QString formulaString = formula;
if (formulaString.startsWith(QLatin1Char('=')))
formulaString = formula.mid(1);
int id=-1;
if (!scope.isEmpty()) {
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetName() == scope) {
id = d->sheets[i]->sheetId();
break;
}
}
}
d->definedNamesList.append(XlsxDefineNameData(name, formulaString, comment, id));
return true;
}
AbstractSheet *Workbook::addSheet(const QString &name, AbstractSheet::SheetType type)
{
Q_D(Workbook);
return insertSheet(d->sheets.size(), name, type);
}
/*!
* \internal
*/
QStringList Workbook::worksheetNames() const
{
Q_D(const Workbook);
return d->sheetNames;
}
/*!
* \internal
* Used only when load the xlsx file!!
*/
AbstractSheet *Workbook::addSheet(const QString &name, int sheetId, AbstractSheet::SheetType type)
{
Q_D(Workbook);
if (sheetId > d->last_sheet_id)
d->last_sheet_id = sheetId;
AbstractSheet *sheet=0;
if (type == AbstractSheet::ST_WorkSheet) {
sheet = new Worksheet(name, sheetId, this, F_LoadFromExists);
} else if (type == AbstractSheet::ST_ChartSheet) {
sheet = new Chartsheet(name, sheetId, this, F_LoadFromExists);
} else {
qWarning("unsupported sheet type.");
Q_ASSERT(false);
}
d->sheets.append(QSharedPointer<AbstractSheet>(sheet));
d->sheetNames.append(name);
return sheet;
}
AbstractSheet *Workbook::insertSheet(int index, const QString &name, AbstractSheet::SheetType type)
{
Q_D(Workbook);
QString sheetName = createSafeSheetName(name);
if (!sheetName.isEmpty()) {
//If user given an already in-used name, we should not continue any more!
if (d->sheetNames.contains(sheetName))
return 0;
} else {
if (type == AbstractSheet::ST_WorkSheet) {
do {
++d->last_worksheet_index;
sheetName = QStringLiteral("Sheet%1").arg(d->last_worksheet_index);
} while (d->sheetNames.contains(sheetName));
} else if (type == AbstractSheet::ST_ChartSheet) {
do {
++d->last_chartsheet_index;
sheetName = QStringLiteral("Chart%1").arg(d->last_chartsheet_index);
} while (d->sheetNames.contains(sheetName));
} else {
qWarning("unsupported sheet type.");
return 0;
}
}
++d->last_sheet_id;
AbstractSheet *sheet;
if (type == AbstractSheet::ST_WorkSheet)
sheet = new Worksheet(sheetName, d->last_sheet_id, this, F_NewFromScratch);
else
sheet = new Chartsheet(sheetName, d->last_sheet_id, this, F_NewFromScratch);
d->sheets.insert(index, QSharedPointer<AbstractSheet>(sheet));
d->sheetNames.insert(index, sheetName);
d->activesheetIndex = index;
return sheet;
}
/*!
* Returns current active worksheet.
*/
AbstractSheet *Workbook::activeSheet() const
{
Q_D(const Workbook);
if (d->sheets.isEmpty())
const_cast<Workbook*>(this)->addSheet();
return d->sheets[d->activesheetIndex].data();
}
bool Workbook::setActiveSheet(int index)
{
Q_D(Workbook);
if (index < 0 || index >= d->sheets.size()) {
//warning
return false;
}
d->activesheetIndex = index;
return true;
}
/*!
* Rename the worksheet at the \a index to \a newName.
*/
bool Workbook::renameSheet(int index, const QString &newName)
{
Q_D(Workbook);
QString name = createSafeSheetName(newName);
if (index < 0 || index >= d->sheets.size())
return false;
//If user given an already in-used name, return false
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetName() == name)
return false;
}
d->sheets[index]->setSheetName(name);
d->sheetNames[index] = name;
return true;
}
/*!
* Remove the worksheet at pos \a index.
*/
bool Workbook::deleteSheet(int index)
{
Q_D(Workbook);
if (d->sheets.size() <= 1)
return false;
if (index < 0 || index >= d->sheets.size())
return false;
d->sheets.removeAt(index);
d->sheetNames.removeAt(index);
return true;
}
/*!
* Moves the worksheet form \a srcIndex to \a distIndex.
*/
bool Workbook::moveSheet(int srcIndex, int distIndex)
{
Q_D(Workbook);
if (srcIndex == distIndex)
return false;
if (srcIndex < 0 || srcIndex >= d->sheets.size())
return false;
QSharedPointer<AbstractSheet> sheet = d->sheets.takeAt(srcIndex);
d->sheetNames.takeAt(srcIndex);
if (distIndex >= 0 || distIndex <= d->sheets.size()) {
d->sheets.insert(distIndex, sheet);
d->sheetNames.insert(distIndex, sheet->sheetName());
} else {
d->sheets.append(sheet);
d->sheetNames.append(sheet->sheetName());
}
return true;
}
bool Workbook::copySheet(int index, const QString &newName)
{
Q_D(Workbook);
if (index < 0 || index >= d->sheets.size())
return false;
QString worksheetName = createSafeSheetName(newName);
if (!newName.isEmpty()) {
//If user given an already in-used name, we should not continue any more!
if (d->sheetNames.contains(newName))
return false;
} else {
int copy_index = 1;
do {
++copy_index;
worksheetName = QStringLiteral("%1(%2)").arg(d->sheets[index]->sheetName()).arg(copy_index);
} while (d->sheetNames.contains(worksheetName));
}
++d->last_sheet_id;
AbstractSheet *sheet = d->sheets[index]->copy(worksheetName, d->last_sheet_id);
d->sheets.append(QSharedPointer<AbstractSheet> (sheet));
d->sheetNames.append(sheet->sheetName());
return false;
}
/*!
* Returns count of worksheets.
*/
int Workbook::sheetCount() const
{
Q_D(const Workbook);
return d->sheets.count();
}
/*!
* Returns the sheet object at index \a sheetIndex.
*/
AbstractSheet *Workbook::sheet(int index) const
{
Q_D(const Workbook);
if (index < 0 || index >= d->sheets.size())
return 0;
return d->sheets.at(index).data();
}
SharedStrings *Workbook::sharedStrings() const
{
Q_D(const Workbook);
return d->sharedStrings.data();
}
Styles *Workbook::styles()
{
Q_D(Workbook);
return d->styles.data();
}
Theme *Workbook::theme()
{
Q_D(Workbook);
return d->theme.data();
}
/*!
* \internal
*
* Unlike media files, drawing file is a property of the sheet.
*/
QList<Drawing *> Workbook::drawings()
{
Q_D(Workbook);
QList<Drawing *> ds;
for (int i=0; i<d->sheets.size(); ++i) {
QSharedPointer<AbstractSheet> sheet = d->sheets[i];
if (sheet->drawing())
ds.append(sheet->drawing());
}
return ds;
}
/*!
* \internal
*/
QList<QSharedPointer<AbstractSheet> > Workbook::getSheetsByTypes(AbstractSheet::SheetType type) const
{
Q_D(const Workbook);
QList<QSharedPointer<AbstractSheet> > list;
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetType() == type)
list.append(d->sheets[i]);
}
return list;
}
void Workbook::saveToXmlFile(QIODevice *device) const
{
Q_D(const Workbook);
d->relationships->clear();
if (d->sheets.isEmpty())
const_cast<Workbook *>(this)->addSheet();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("workbook"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
writer.writeEmptyElement(QStringLiteral("fileVersion"));
writer.writeAttribute(QStringLiteral("appName"), QStringLiteral("xl"));
writer.writeAttribute(QStringLiteral("lastEdited"), QStringLiteral("4"));
writer.writeAttribute(QStringLiteral("lowestEdited"), QStringLiteral("4"));
writer.writeAttribute(QStringLiteral("rupBuild"), QStringLiteral("4505"));
// writer.writeAttribute(QStringLiteral("codeName"), QStringLiteral("{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}"));
writer.writeEmptyElement(QStringLiteral("workbookPr"));
if (d->date1904)
writer.writeAttribute(QStringLiteral("date1904"), QStringLiteral("1"));
writer.writeAttribute(QStringLiteral("defaultThemeVersion"), QStringLiteral("124226"));
writer.writeStartElement(QStringLiteral("bookViews"));
writer.writeEmptyElement(QStringLiteral("workbookView"));
writer.writeAttribute(QStringLiteral("xWindow"), QString::number(d->x_window));
writer.writeAttribute(QStringLiteral("yWindow"), QString::number(d->y_window));
writer.writeAttribute(QStringLiteral("windowWidth"), QString::number(d->window_width));
writer.writeAttribute(QStringLiteral("windowHeight"), QString::number(d->window_height));
//Store the firstSheet when it isn't the default
//For example, when "the first sheet 0 is hidden", the first sheet will be 1
if (d->firstsheet > 0)
writer.writeAttribute(QStringLiteral("firstSheet"), QString::number(d->firstsheet + 1));
//Store the activeTab when it isn't the first sheet
if (d->activesheetIndex > 0)
writer.writeAttribute(QStringLiteral("activeTab"), QString::number(d->activesheetIndex));
writer.writeEndElement();//bookViews
writer.writeStartElement(QStringLiteral("sheets"));
int worksheetIndex = 0;
int chartsheetIndex = 0;
for (int i=0; i<d->sheets.size(); ++i) {
QSharedPointer<AbstractSheet> sheet = d->sheets[i];
writer.writeEmptyElement(QStringLiteral("sheet"));
writer.writeAttribute(QStringLiteral("name"), sheet->sheetName());
writer.writeAttribute(QStringLiteral("sheetId"), QString::number(sheet->sheetId()));
if (sheet->sheetState() == AbstractSheet::SS_Hidden)
writer.writeAttribute(QStringLiteral("state"), QStringLiteral("hidden"));
else if (sheet->sheetState() == AbstractSheet::SS_VeryHidden)
writer.writeAttribute(QStringLiteral("state"), QStringLiteral("veryHidden"));
if (sheet->sheetType() == AbstractSheet::ST_WorkSheet)
d->relationships->addDocumentRelationship(QStringLiteral("/worksheet"), QStringLiteral("worksheets/sheet%1.xml").arg(++worksheetIndex));
else
d->relationships->addDocumentRelationship(QStringLiteral("/chartsheet"), QStringLiteral("chartsheets/sheet%1.xml").arg(++chartsheetIndex));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
}
writer.writeEndElement();//sheets
if (d->externalLinks.size() > 0) {
writer.writeStartElement(QStringLiteral("externalReferences"));
for (int i=0; i<d->externalLinks.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("externalReference"));
d->relationships->addDocumentRelationship(QStringLiteral("/externalLink"), QStringLiteral("externalLinks/externalLink%1.xml").arg(i+1));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
}
writer.writeEndElement();//externalReferences
}
if (!d->definedNamesList.isEmpty()) {
writer.writeStartElement(QStringLiteral("definedNames"));
foreach (XlsxDefineNameData data, d->definedNamesList) {
writer.writeStartElement(QStringLiteral("definedName"));
writer.writeAttribute(QStringLiteral("name"), data.name);
if (!data.comment.isEmpty())
writer.writeAttribute(QStringLiteral("comment"), data.comment);
if (data.sheetId != -1) {
//find the local index of the sheet.
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetId() == data.sheetId) {
writer.writeAttribute(QStringLiteral("localSheetId"), QString::number(i));
break;
}
}
}
writer.writeCharacters(data.formula);
writer.writeEndElement();//definedName
}
writer.writeEndElement();//definedNames
}
writer.writeStartElement(QStringLiteral("calcPr"));
writer.writeAttribute(QStringLiteral("calcId"), QStringLiteral("124519"));
writer.writeEndElement(); //calcPr
writer.writeEndElement();//workbook
writer.writeEndDocument();
d->relationships->addDocumentRelationship(QStringLiteral("/theme"), QStringLiteral("theme/theme1.xml"));
d->relationships->addDocumentRelationship(QStringLiteral("/styles"), QStringLiteral("styles.xml"));
if (!sharedStrings()->isEmpty())
d->relationships->addDocumentRelationship(QStringLiteral("/sharedStrings"), QStringLiteral("sharedStrings.xml"));
}
bool Workbook::loadFromXmlFile(QIODevice *device)
{
Q_D(Workbook);
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("sheet")) {
QXmlStreamAttributes attributes = reader.attributes();
const QString name = attributes.value(QLatin1String("name")).toString();
int sheetId = attributes.value(QLatin1String("sheetId")).toString().toInt();
const QString rId = attributes.value(QLatin1String("r:id")).toString();
const QStringRef &stateString = attributes.value(QLatin1String("state"));
AbstractSheet::SheetState state = AbstractSheet::SS_Visible;
if (stateString == QLatin1String("hidden"))
state = AbstractSheet::SS_Hidden;
else if (stateString == QLatin1String("veryHidden"))
state = AbstractSheet::SS_VeryHidden;
XlsxRelationship relationship = d->relationships->getRelationshipById(rId);
AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet;
if (relationship.type.endsWith(QLatin1String("/worksheet")))
type = AbstractSheet::ST_WorkSheet;
else if (relationship.type.endsWith(QLatin1String("/chartsheet")))
type = AbstractSheet::ST_ChartSheet;
else if (relationship.type.endsWith(QLatin1String("/dialogsheet")))
type = AbstractSheet::ST_DialogSheet;
else if (relationship.type.endsWith(QLatin1String("/xlMacrosheet")))
type = AbstractSheet::ST_MacroSheet;
else
qWarning("unknown sheet type");
AbstractSheet *sheet = addSheet(name, sheetId, type);
sheet->setSheetState(state);
const QString fullPath = QDir::cleanPath(splitPath(filePath())[0] +QLatin1String("/")+ relationship.target);
sheet->setFilePath(fullPath);
} else if (reader.name() == QLatin1String("workbookPr")) {
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("date1904")))
d->date1904 = true;
} else if (reader.name() == QLatin1String("bookviews")) {
while (!(reader.name() == QLatin1String("bookviews") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("workbookView")) {
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("xWindow")))
d->x_window = attrs.value(QLatin1String("xWindow")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("yWindow")))
d->y_window = attrs.value(QLatin1String("yWindow")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("windowWidth")))
d->window_width = attrs.value(QLatin1String("windowWidth")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("windowHeight")))
d->window_height = attrs.value(QLatin1String("windowHeight")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("firstSheet")))
d->firstsheet = attrs.value(QLatin1String("firstSheet")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("activeTab")))
d->activesheetIndex = attrs.value(QLatin1String("activeTab")).toString().toInt();
}
}
}
} else if (reader.name() == QLatin1String("externalReference")) {
QXmlStreamAttributes attributes = reader.attributes();
const QString rId = attributes.value(QLatin1String("r:id")).toString();
XlsxRelationship relationship = d->relationships->getRelationshipById(rId);
QSharedPointer<SimpleOOXmlFile> link(new SimpleOOXmlFile(F_LoadFromExists));
const QString fullPath = QDir::cleanPath(splitPath(filePath())[0] +QLatin1String("/")+ relationship.target);
link->setFilePath(fullPath);
d->externalLinks.append(link);
} else if (reader.name() == QLatin1String("definedName")) {
QXmlStreamAttributes attrs = reader.attributes();
XlsxDefineNameData data;
data.name = attrs.value(QLatin1String("name")).toString();
if (attrs.hasAttribute(QLatin1String("comment")))
data.comment = attrs.value(QLatin1String("comment")).toString();
if (attrs.hasAttribute(QLatin1String("localSheetId"))) {
int localId = attrs.value(QLatin1String("localSheetId")).toString().toInt();
int sheetId = d->sheets.at(localId)->sheetId();
data.sheetId = sheetId;
}
data.formula = reader.readElementText();
d->definedNamesList.append(data);
}
}
}
return true;
}
/*!
* \internal
*/
QList<QSharedPointer<MediaFile> > Workbook::mediaFiles() const
{
Q_D(const Workbook);
return d->mediaFiles;
}
/*!
* \internal
*/
void Workbook::addMediaFile(QSharedPointer<MediaFile> media, bool force)
{
Q_D(Workbook);
if (!force) {
for (int i=0; i<d->mediaFiles.size(); ++i) {
if (d->mediaFiles[i]->hashKey() == media->hashKey()) {
media->setIndex(i);
return;
}
}
}
media->setIndex(d->mediaFiles.size());
d->mediaFiles.append(media);
}
/*!
* \internal
*/
QList<QSharedPointer<Chart> > Workbook::chartFiles() const
{
Q_D(const Workbook);
return d->chartFiles;
}
/*!
* \internal
*/
void Workbook::addChartFile(QSharedPointer<Chart> chart)
{
Q_D(Workbook);
if (!d->chartFiles.contains(chart))
d->chartFiles.append(chart);
}
QT_END_NAMESPACE_XLSX

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxzipreader_p.h"
#include <private/qzipreader_p.h>
#include <QVector>
#include <QList>
namespace QXlsx {
ZipReader::ZipReader(const QString &filePath) :
m_reader(new QZipReader(filePath))
{
init();
}
ZipReader::ZipReader(QIODevice *device) :
m_reader(new QZipReader(device))
{
init();
}
ZipReader::~ZipReader()
{
}
void ZipReader::init()
{
QList<QZipReader::FileInfo> allFiles = m_reader->fileInfoList().toList();
foreach (const QZipReader::FileInfo &fi, allFiles) {
if (fi.isFile)
m_filePaths.append(fi.filePath);
}
}
bool ZipReader::exists() const
{
return m_reader->exists();
}
QStringList ZipReader::filePaths() const
{
return m_filePaths;
}
QByteArray ZipReader::fileData(const QString &fileName) const
{
return m_reader->fileData(fileName);
}
} // namespace QXlsx

View File

@ -0,0 +1,68 @@
/****************************************************************************
** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "xlsxzipwriter_p.h"
#include <QDebug>
#include <private/qzipwriter_p.h>
namespace QXlsx {
ZipWriter::ZipWriter(const QString &filePath)
{
m_writer = new QZipWriter(filePath, QIODevice::WriteOnly);
m_writer->setCompressionPolicy(QZipWriter::AutoCompress);
}
ZipWriter::ZipWriter(QIODevice *device)
{
m_writer = new QZipWriter(device);
m_writer->setCompressionPolicy(QZipWriter::AutoCompress);
}
ZipWriter::~ZipWriter()
{
delete m_writer;
}
bool ZipWriter::error() const
{
return m_writer->status() != QZipWriter::NoError;
}
void ZipWriter::addFile(const QString &filePath, QIODevice *device)
{
m_writer->addFile(filePath, device);
}
void ZipWriter::addFile(const QString &filePath, const QByteArray &data)
{
m_writer->addFile(filePath, data);
}
void ZipWriter::close()
{
m_writer->close();
}
} // namespace QXlsx

View File

@ -11,7 +11,19 @@
#include "log4cplus/asyncappender.h"
#include "log4cplus/fileappender.h"
#include "boost/filesystem.hpp"
//< 屏蔽xml_parser编译告警
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif
#include "boost/property_tree/xml_parser.hpp"
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#include "boost/typeof/typeof.hpp"
#include "boost/thread/thread.hpp"
@ -212,7 +224,7 @@ bool searchLogger( const std::string& sPathFile )
const bool bCreateDirs = true;
const string sAppender = "RollingFileAppender";
//const string sEncoding = "UTF-8";
const string sConversionPattern = "%D{%y-%m-%d %H:%M:%S} [%t] %-5p %x %l - %m %n";
const string sConversionPattern = "%D{%y-%m-%d %H:%M:%S.%q} %p %T %l - %m %n";
const string sAppName = g_sAppName;
const bool bAsync = false;
const int nQueueSize = 100;
@ -320,7 +332,7 @@ void addDefaultLogger()
const int nMaxBackupIndex = 10;
const string sFile = "default.log";
const bool bCreateDirs = true;
const string sConversionPattern = "%D{%y-%m-%d %H:%M:%S} [%t] %-5p %x %l - %m %n";
const string sConversionPattern = "%D{%y-%m-%d %H:%M:%S.%q} %p %T %l - %m %n";
const string sAppName = g_sAppName;
string sTmpFile = getLogFilePathName( sAppName, sFile );

View File

@ -14,8 +14,20 @@
#include "boost/lexical_cast.hpp"
#include "boost/format.hpp"
#include "boost/asio/ip/host_name.hpp"
//< 屏蔽xml_parser编译告警
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif
#include "boost/property_tree/xml_parser.hpp"
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#include "pub_logger_api/logger.h"
#include "pub_utility_api/FileUtil.h"
#include "SysInfoData.h"

View File

@ -1027,7 +1027,7 @@ unsigned int CSysInfoImp::getUniqueIdOfNodeInfo()
}
// 获取字符串crc
nRet = calcCRC32( (unsigned char*)sInfo.c_str(), sInfo.size() );
nRet = calcCRC32( (unsigned char*)sInfo.c_str(), static_cast<int>(sInfo.size()) );
// 基本不可能发生以防万一是以防43亿分之一
if ( nRet == 0 )

View File

@ -64,7 +64,7 @@ int iot_public::CProcessSharedMutex::init( char *cName, int nKey )
pthread_mutexattr_init(&mutexAttr);/*初始化互斥锁的属性*/
pthread_mutexattr_setpshared(&mutexAttr,PTHREAD_PROCESS_SHARED);/*设置互斥锁的属性*/
pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT);
pthread_mutexattr_setrobust_np(&mutexAttr,PTHREAD_MUTEX_ROBUST_NP);
pthread_mutexattr_setrobust(&mutexAttr,PTHREAD_MUTEX_ROBUST_NP);
if ( 0 != pthread_mutex_init(m_pLock,&mutexAttr) )/*互斥锁的初始化*/
{
LOGERROR("创建互斥锁 %s 时,初始化互斥锁失败,shmId=%d", m_cName, nShmId);
@ -138,7 +138,7 @@ int iot_public::CProcessSharedMutex::lock()
if ( nRet == EOWNERDEAD )
{
LOGERROR("互斥锁 %s 上次持有者异常退出", m_cName);
nRet = pthread_mutex_consistent_np( m_pLock );
nRet = pthread_mutex_consistent( m_pLock );
if ( 0 == nRet )
{
LOGWARN("互斥锁 %s 从上次异常退出中恢复正常", m_cName);

View File

@ -4,7 +4,19 @@
@author
*/
#include "pub_utility_api/CommonConfigParse.h"
//< 屏蔽xml_parser编译告警
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif
#include "boost/property_tree/xml_parser.hpp"
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#include "boost/typeof/typeof.hpp"
#include "boost/filesystem.hpp"
#include "Common.h"

View File

@ -10,7 +10,7 @@
#include "pub_logger_api/logger.h"
#include "pub_utility_api/FileUtil.h"
#include "pub_utility_api/CommonConfigParse.h"
#include "pub_utility_api/I18N.h"
#include "pub_utility_api/FileStyle.h"
namespace iot_public
@ -40,27 +40,41 @@ std::string CFileStyle::getCurStyle( const std::string &strDefault )
}
std::string CFileStyle::getPathOfStyleFile( const std::string &strFileName, const std::string &strPlatOrProd,
std::string CFileStyle::getPathOfStyleFile( const std::string &strFileName,
const std::string &strDefaultLang,
const std::string &strDefaultStyle )
{
boost::filesystem::path objFullPath = CFileUtil::getCurModuleDir();
objFullPath /= "../../" + strPlatOrProd + "/common/style/" + getCurStyle() + "/" + strFileName;
if ( boost::filesystem::exists( objFullPath ))
return objFullPath.string();
//< 如果样式配置文件配错比如老工程有blue样式当前是没有的
std::string strCurLang;
std::string strCurStyle;
if(!strDefaultLang.empty())
{
LOGERROR( "getPathOfStyleFile(): 未找到样式文件[%s],尝试使用默认样式[%s]",
objFullPath.c_str(), strDefaultStyle.c_str());
objFullPath = CFileUtil::getCurModuleDir();
objFullPath /= "../../" + strPlatOrProd + "/common/style/" + strDefaultStyle + "/" + strFileName;
if ( boost::filesystem::exists( objFullPath ))
return objFullPath.string();
strCurLang = strDefaultLang;
}
else
{
strCurLang = getCurLanguage();
}
LOGERROR( "getPathOfStyleFile(): 未找到样式文件[%s],返回空", objFullPath.c_str());
return "";
if(!strDefaultStyle.empty())
{
strCurStyle = strDefaultStyle;
}
else
{
strCurStyle = getCurStyle();
}
boost::filesystem::path objFullPath = CFileUtil::getCurModuleDir();
if( objFullPath.string().empty() )
{
LOGERROR( "getPathOfStyleFile(): 未找到样式文件[%s],返回空", objFullPath.c_str());
return "";
}
objFullPath /= "../../resource/"+ strCurLang +"/style/" + strCurStyle + "/" + strFileName;
return objFullPath.string();
}
} //namespace iot_public

View File

@ -42,7 +42,13 @@ std::string CFileUtil::getCurModuleDir()
::memset( pcDirectory, 0, sizeof( pcDirectory ));
#if defined(WIN32)
::GetModuleFileNameA(NULL, pcDirectory, BUF_LEN);
wchar_t pwcDirectory[BUF_LEN];
::memset( pwcDirectory, 0, sizeof( pwcDirectory ));
::GetModuleFileNameW(NULL, pwcDirectory, BUF_LEN);
int len = WideCharToMultiByte(CP_UTF8, 0, pwcDirectory, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, pwcDirectory, -1, pcDirectory, (len > BUF_LEN ? BUF_LEN : len), NULL, NULL);
#elif defined(__linux)
readlink( "/proc/self/exe", pcDirectory, BUF_LEN );
#elif defined(_AIX)
@ -322,7 +328,7 @@ std::string CFileUtil::getPathOfCfgFile( const std::string &strFileName, const s
//< 不判 boost::filesystem::is_regular_file( objFullPath ),允许传入目录名
if ( boost::filesystem::exists( objFullPath ))
{
LOGINFO( "getPathOfCfgFile(): 使用data下配置文件[%s]", objFullPath.c_str());
LOGINFO( "getPathOfCfgFile(): 使用data下配置文件[%s]", objFullPath.string().c_str());
return objFullPath.string();
}
@ -339,33 +345,30 @@ std::string CFileUtil::getPathOfCfgFile( const std::string &strFileName, const s
std::string CFileUtil::getPathOfResFile( const std::string &strFileName,
const std::string &strPlatOrProd,
const std::string &strDefaultLang )
{
//< 获取一次开销相对较大,保存下来
const std::string &&strCurDir = CFileUtil::getCurModuleDir();
const std::string &&strCurLang = getCurLanguage( strDefaultLang );
std::string strCurLang;
if(strDefaultLang.empty())
{
strCurLang = getCurLanguage();
}
else
{
strCurLang = strDefaultLang;
}
//< 判断是否存在,外部代码可省去判断,只需判断是否为空
boost::filesystem::path objFullPath = strCurDir;
objFullPath /= "../../" + strPlatOrProd + "/common/resource/" + strCurLang;
objFullPath /= "../../resource/" + strCurLang;
objFullPath /= strFileName;
//< 不判 boost::filesystem::is_regular_file( objFullPath ),允许传入目录名
if ( boost::filesystem::exists( objFullPath ))
return objFullPath.string();
//< 如果默认语言和当前语言不一样,再尝试默认语言
if ( strCurLang != strDefaultLang )
{
objFullPath = strCurDir;
objFullPath /= "../../" + strPlatOrProd + "/common/resource/" + strDefaultLang;
objFullPath /= strFileName;
//< 不判 boost::filesystem::is_regular_file( objFullPath ),允许传入目录名
if ( boost::filesystem::exists( objFullPath ))
return objFullPath.string();
}
LOGERROR( "getPathOfResFile(): 未找到资源文件[%s],返回空", strFileName.c_str());
auto strFullPath=(objFullPath).string();
LOGERROR( "parent[%s] getPathOfResFile(): 未找到资源文件[%s],返回空",strFullPath.c_str(), strFileName.c_str());
return "";
}

View File

@ -5,7 +5,7 @@
*/
#include "boost/filesystem.hpp"
#include <boost/concept_check.hpp>
#include "common/Common.h"
#include "pub_logger_api/logger.h"
#include "pub_utility_api/FileUtil.h"
@ -29,12 +29,14 @@ std::string getCurLanguage( const std::string &strDefault )
std::string strLanguage = std::move( config.getStringWithDefault( "language", "language", strDefault ));
LOGDEBUG( "getCurLanguage(): 获得的国际化语言是[%s]", strLanguage.c_str());
return std::move( strLanguage );
return strLanguage;
}
bool initI18N( const std::string &strRelativePath, const std::string &strFileName, const std::string &strPlatOrProd )
{
boost::ignore_unused_variable_warning(strPlatOrProd);
//获得国际化语言
const std::string strLanguage = std::move( getCurLanguage());
@ -47,7 +49,7 @@ bool initI18N( const std::string &strRelativePath, const std::string &strFileNam
return false;
}
boost::filesystem::path objPathTemp = strCurDir;
objPathTemp /= "../../" + strPlatOrProd + "/common/resource/";
objPathTemp /= "../../resource/";
const std::string strRootPath = objPathTemp.string();
//设置boost messages_info
@ -83,4 +85,4 @@ bool initI18N( const std::string &strRelativePath, const std::string &strFileNam
}
} //< namespace iot_public
} //< namespace iot_public

View File

@ -111,7 +111,7 @@ bool iot_public::CSingleProcInstance::hasInstanceRunning(const string& strUnique
{
std::transform(strName.begin(), strName.end(), strName.begin(), ::tolower);
}
strName = "__kbdct_" + strName;
strName = "__iot_" + strName;
if (!g_objGlobalMutex_.create(strName.c_str()))
{
//_assert(false);
@ -143,7 +143,7 @@ bool iot_public::CSingleProcInstance::hasInstanceRunning(const string& strUnique
{
std::transform(strName.begin(), strName.end(), strName.begin(), ::tolower);
}
strName = TMPDIR"/__kbdct_" + strName;
strName = TMPDIR"/__iot_" + strName;
int fdLockFile;
struct flock fl;
/* 打开锁文件 */

View File

@ -10,12 +10,10 @@ win32{
}
# arm下的release版本关闭死锁检测节省资源开销
contains(QMAKE_HOST.arch, aarch64)
{
CONFIG(release, debug|release)
{
DEFINES += ISCS_DISABLE_DEADLOCK_CHECK
}
contains(QMAKE_HOST.arch, aarch64) | linux-aarch64* {
CONFIG(release, debug|release) {
DEFINES += ISCS_DISABLE_DEADLOCK_CHECK
}
}
# Input

View File

@ -0,0 +1,204 @@
#include "pub_widget/AlertMessageBox.h"
#include <QLabel>
#include <QResizeEvent>
#include <QDesktopWidget>
#include <QApplication>
#include <QDebug>
AlertMessageBox* AlertMessageBox::m_handle = 0;
AlertMessageBox::AlertMessageBox( QWidget *parent ) :
QMenu( parent )
, m_hideCount( 0 )
, m_hideTransparent(10)
, m_hideTotal( 18 )
{
setWindowFlags( windowFlags() | Qt::FramelessWindowHint );
setAttribute( Qt::WA_TranslucentBackground );//设置背景透明
m_showIcon = new AdaptImage( this );
m_showIcon->setMouseTracking( true );
m_showText = new QLabel( this );
m_showText->setMouseTracking( true );
m_showText->setAlignment( Qt::AlignCenter );
m_showText->setWordWrap(true);
m_stayTimer = new QTimer( this );
m_hideTimer = new QTimer( this );
connect( m_stayTimer, SIGNAL( timeout() ), this, SLOT( slot_stay() ) );
connect( m_hideTimer, SIGNAL( timeout() ), this, SLOT( slot_hide() ) );
setMouseTracking( true );
}
void AlertMessageBox::resizeEvent( QResizeEvent *ev )
{
QMenu::resizeEvent( ev );
const int w = ev->size().width();
const int h = ev->size().height();
m_showIcon->setGeometry( 30, (h-42)/2, 42, 42 );
m_showText->setGeometry( 30+42+10, 0, w - (30+42+10+10), h );
}
void AlertMessageBox::showEvent( QShowEvent *ev )
{
m_pos = QCursor::pos();
m_hideCount = 0;
setWindowOpacity( 1 );
m_hideTimer->stop();
m_stayTimer->start( 1000 );
QMenu::showEvent( ev );
}
void AlertMessageBox::hideEvent( QHideEvent *ev )
{
m_hideCount = 0;
setWindowOpacity( 1 );
m_stayTimer->stop();
m_hideTimer->stop();
m_showText->clear();
QMenu::hideEvent( ev );
}
void AlertMessageBox::mousePressEvent( QMouseEvent *ev )
{
hide();
QMenu::mousePressEvent( ev );
}
void AlertMessageBox::mouseMoveEvent(QMouseEvent *ev)
{
QMenu::mouseMoveEvent( ev );
/* 鼠标移动即开始隐藏窗口 */
if ( m_pos != QCursor::pos() )
{
m_stayTimer->stop();
if ( !m_hideTimer->isActive() )
{
m_hideTimer->start( 100 );
}
}
}
void AlertMessageBox::setIcon( N_MSG_BOX_ICON icon )
{
switch ( icon )//初始化图标
{
case ICON_WARNING:
{
m_showIcon->setProperty("MSG_TYPE","ICON_WARNING");
}
break;
case ICON_ERROR:
{
m_showIcon->setProperty("MSG_TYPE","ICON_ERROR");
}
break;
case ICON_INFORMATION:
{
m_showIcon->setProperty("MSG_TYPE","ICON_INFORMATION");
}
break;
case ICON_QUESTION:
{
m_showIcon->setProperty("MSG_TYPE","ICON_QUESTION");
}
break;
default:
m_showIcon->setProperty("MSG_TYPE","ICON_DEFAULT");
break;
}
m_showIcon->style()->polish(m_showIcon);
}
void AlertMessageBox::setText( const QString &text )
{
m_showText->setText( text );
adjustTextToFixWidth( text );
}
void AlertMessageBox::adjustTextToFixWidth( const QString & text )
{
QFontMetrics fm ( m_showText->font() );
int textWidth = fm.width( text );
int nWidth = this->width() - 160;
if ( nWidth < textWidth )
{
m_showText->setAlignment( Qt::AlignVCenter| Qt::AlignLeft );
}
else
{
m_showText->setAlignment( Qt::AlignCenter );
}
}
void AlertMessageBox::ReleaseInstance()
{
if ( m_handle )
{
delete m_handle;
m_handle = 0;
}
}
void AlertMessageBox::Warning(QWidget *parent, const QString &msg )
{
message(parent, msg ,ICON_WARNING );
}
void AlertMessageBox::Error(QWidget *parent, const QString &msg )
{
message(parent, msg,ICON_ERROR );
}
void AlertMessageBox::Information(QWidget *parent, const QString &msg )
{
message(parent, msg ,ICON_INFORMATION);
}
void AlertMessageBox::message(QWidget *parent,const QString &msg ,N_MSG_BOX_ICON icon )
{
if ( 0 == m_handle )
{
m_handle = new AlertMessageBox(parent);
}
m_handle->setIcon( icon );
m_handle->setText( msg );
QDesktopWidget *deskTop = QApplication::desktop();
QRect deskRect = deskTop->availableGeometry();
m_handle->move(( deskRect.width() - m_handle->width() ) / 2, ( deskRect.height() - m_handle->height() ) / 2 );
m_handle->show();
}
void AlertMessageBox::slot_stay()
{
m_stayTimer->stop();
if ( !m_hideTimer->isActive() )
{
m_hideTimer->start( 100 );
}
}
/*!Note that under X11 you need to have a composite manager running, and the X11 specific _NET_WM_WINDOW_OPACITY atom
**needs to be supported by the window manager you are using.
*/
void AlertMessageBox::slot_hide()
{
m_hideCount += 1;
if ( m_hideCount > m_hideTransparent )
{
if ( m_hideCount >= m_hideTotal )
{
m_hideTimer->stop();
hide();
}
else
setWindowOpacity( ((double)m_hideTotal - m_hideCount)/(m_hideTotal-m_hideTransparent) );
}
}

View File

@ -0,0 +1,722 @@
#include "Calendar.h"
#include "LanguageSrc.h"
#include <QButtonGroup>
#include <QDate>
/***************************************************************************************************/
CalendarButton::CalendarButton( const QString &text, QWidget *parent )
: TVTButton( parent )
{
m_number = new QLabel( this );
m_text = new QLabel( text, this );
m_number->setStyleSheet( " QLabel {background: transparent; font: bold 42px; color: rgb(216,216,216);} " );
m_number->setAlignment( Qt::AlignCenter );
m_text->setStyleSheet( " QLabel {background: transparent; font: 16px; color: rgb(209,209,209);} " );
m_text->setAlignment( Qt::AlignCenter );
setStyleSheet( " CalendarButton { background: rgb(45,45,45); border-radius: 4px;}" );
}
void CalendarButton::setCurrentValue( int value )
{
m_number->setText( QString::number( value ) );
}
void CalendarButton::resizeEvent( QResizeEvent *e )
{
TVTButton::resizeEvent( e );
const int w = e->size().width();
const int h = e->size().height();
m_number->setGeometry( 10, 00, w - 40, h );
m_text->setGeometry( w - 30, 0, 30, h );
}
/***************************************************************************************************/
CalendarAssistButton::CalendarAssistButton( QWidget *parent )
: TVTButton( parent )
{
}
void CalendarAssistButton::setEnterStyle( const QString &strStyle )
{
m_strEnterStyle = strStyle;
}
void CalendarAssistButton::setLeaveStyle( const QString &strStyle )
{
m_strLeaveStyle = strStyle;
setStyleSheet( m_strLeaveStyle );
}
void CalendarAssistButton::enterEvent( QEvent *e )
{
TVTButton::enterEvent( e );
if ( isEnabled() )
{
setCursor( Qt::PointingHandCursor );
setStyleSheet( m_strEnterStyle );
}
}
void CalendarAssistButton::leaveEvent( QEvent *e )
{
TVTButton::leaveEvent( e );
if ( isEnabled() )
{
setCursor( Qt::ArrowCursor );
setStyleSheet( m_strLeaveStyle );
}
}
/***************************************************************************************************/
CalendarItem::CalendarItem( const QString &text, QWidget *parent )
: QLabel( parent )
{
m_label1 = new CalendarAssistButton( this );
m_label2 = new CalendarAssistButton( this );
m_calendarButton = new CalendarButton( text, this );
m_label3 = new CalendarAssistButton( this );
m_label4 = new CalendarAssistButton( this );
QString strEnterStyle = " CalendarAssistButton {background: transparent; border: 0px; color: rgb(216, 216, 216); font: bold %1px;} ";
QString strLeaveStyle = " CalendarAssistButton {background: transparent; border: 0px; color: rgb(138, 138, 138); font: %1px;} ";
m_label1->setEnterStyle( strEnterStyle.arg( 22 ) );
m_label1->setLeaveStyle( strLeaveStyle.arg( 22 ) );
m_label2->setEnterStyle( strEnterStyle.arg( 32 ) );
m_label2->setLeaveStyle( strLeaveStyle.arg( 32 ) );
m_label3->setEnterStyle( strEnterStyle.arg( 32 ) );
m_label3->setLeaveStyle( strLeaveStyle.arg( 32 ) );
m_label4->setEnterStyle( strEnterStyle.arg( 22 ) );
m_label4->setLeaveStyle( strLeaveStyle.arg( 22 ) );
QButtonGroup *btnGroup = new QButtonGroup( this );
btnGroup->addButton( m_label1 );
btnGroup->addButton( m_label2 );
btnGroup->addButton( m_label3 );
btnGroup->addButton( m_label4 );
m_value = 0;
m_maxValue = 0;
m_minValue = 0;
memset(m_variableValue, 0, sizeof(m_variableValue));
connect( btnGroup, SIGNAL( buttonClicked( QAbstractButton* ) ), this, SLOT( slot_buttonClicked( QAbstractButton* ) ) );
}
void CalendarItem::slot_buttonClicked( QAbstractButton* btn )
{
int value = btn->text().toInt();
m_calendarButton->setCurrentValue( value );
setCurrentValue( value, false );
}
void CalendarItem::setValueRange( int min, int max )
{
m_minValue = min;
m_maxValue = max;
if ( m_value > m_maxValue )
{
m_value = m_maxValue;
}
setCurrentValue( m_value, false );
}
void CalendarItem::setCurrentValue( int value , bool blockSignals )
{
m_value = value;
m_calendarButton->setCurrentValue( m_value );
m_variableValue[0] = m_value - 2;
m_variableValue[1] = m_value - 1;
m_variableValue[2] = m_value + 1;
m_variableValue[3] = m_value + 2;
adjustValue();
if ( !blockSignals )
{
emit sig_value( m_value );
}
}
int CalendarItem::value()
{
return m_value;
}
void CalendarItem::adjustValue()
{
for ( int i = 0; i < sizeof( m_variableValue ) / sizeof( m_variableValue[0] ); i++ )
{
if ( m_variableValue[i] > m_maxValue )
{
m_variableValue[i] -= ( m_maxValue - m_minValue + 1 );
}
else if ( m_variableValue[i] < m_minValue )
{
m_variableValue[i] += ( m_maxValue - m_minValue + 1 );
}
}
m_label1->setText( QString::number( m_variableValue[0] ) );
m_label2->setText( QString::number( m_variableValue[1] ) );
m_label3->setText( QString::number( m_variableValue[2] ) );
m_label4->setText( QString::number( m_variableValue[3] ) );
}
void CalendarItem::enterEvent( QEvent *e )
{
QLabel::enterEvent( e );
m_calendarButton->setStyleSheet( " CalendarButton {background: rgb(0, 31, 36);border: 1px solid rgb(56, 145, 180); border-radius: 4px;} " );
}
void CalendarItem::leaveEvent( QEvent *e )
{
QLabel::leaveEvent( e );
m_calendarButton->setStyleSheet( " CalendarButton { background: rgb(45,45,45); border-radius: 4px;} " );
}
void CalendarItem::wheelEvent( QWheelEvent *e )
{
QLabel::wheelEvent( e );
int degree = e->delta() / 8;
int steps = degree / 15;
m_value -= steps;
if ( m_value > m_maxValue )
{
m_value -= ( m_maxValue - m_minValue + 1 );
}
else if ( m_value < m_minValue )
{
m_value += ( m_maxValue - m_minValue + 1 );
}
m_calendarButton->setCurrentValue( m_value );
m_variableValue[0] = m_value - 2;
m_variableValue[1] = m_value - 1;
m_variableValue[2] = m_value + 1;
m_variableValue[3] = m_value + 2;
adjustValue();
emit sig_value( m_value );
}
void CalendarItem::resizeEvent( QResizeEvent *e )
{
QLabel::resizeEvent( e );
const int w = e->size().width();
const int h = e->size().height();
QFontMetrics fm( m_label1->font() );
int width = fm.width( m_label1->text() ) + 20;
m_label1->setGeometry(( w - 20 - width ) / 2, 0, width, 50 );
fm = QFontMetrics( m_label2->font() );
width = fm.width( m_label2->text() ) + 20;
m_label2->setGeometry(( w - 20 - width ) / 2, 50, width, 60 );
m_calendarButton->setGeometry( 0, 110, w, 60 );
fm = QFontMetrics( m_label3->font() );
width = fm.width( m_label3->text() ) + 20;
m_label3->setGeometry(( w - 20 - width ) / 2, 170, width, 60 );
fm = QFontMetrics( m_label4->font() );
width = fm.width( m_label4->text() ) + 20;
m_label4->setGeometry(( w - 20 - width ) / 2, 230, width, 50 );
}
/***************************************************************************************************/
Calendar::Calendar( QWidget *parent ) :
QLabel( parent )
{
m_yearItem = new CalendarItem( GET_TXT( "IDCS_YEAR" ), this );
m_yearItem->setValueRange( 2010, 2037 ); //2038-01-19T03:14:06
m_monthItem = new CalendarItem( GET_TXT( "IDCS_MONTH" ), this );
m_monthItem->setValueRange( 1, 12 );
m_dayItem = new CalendarItem( GET_TXT( "IDCS_DAY" ), this );
m_dayItem->setValueRange( 1, 31 );
m_hourItem = new CalendarItem( GET_TXT( "IDCS_HOUR" ), this );
m_hourItem->setValueRange( 0, 23 );
m_minuteItem = new CalendarItem( GET_TXT( "IDCS_MINUTE" ), this );
m_minuteItem->setValueRange( 0, 59 );
m_secondItem = new CalendarItem( GET_TXT( "IDCS_SECOND" ), this );
m_secondItem->setValueRange( 0, 59 );
connect( m_yearItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_yearChange( int ) ) );
connect( m_monthItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_monthChange( int ) ) );
connect( m_dayItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_dayChange( int ) ) );
connect( m_hourItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_hourChange( int ) ) );
connect( m_minuteItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_minuteChange( int ) ) );
connect( m_secondItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_secondChange( int ) ) );
setFixedSize( 685, 280 );
//setAttribute( Qt::WA_TranslucentBackground );
}
void Calendar::slot_yearChange( int value )
{
if ( m_minDateTime.isValid() )
{
changeTime( COMPARE_MIN, YEAR );
}
else if ( m_maxDateTime.isValid() )
{
changeTime( COMPARE_MAX, YEAR );
}
else
{
m_currentYear = value;
QDate date;
date.setDate( m_currentYear, m_currentMonth, 1 );
/* 根据年份和月份调整日期的最大最小值 */
m_dayItem->setValueRange( 1, date.daysInMonth() );
}
}
void Calendar::slot_monthChange( int value )
{
if ( m_minDateTime.isValid() )
{
changeTime( COMPARE_MIN, MONTH );
}
else if ( m_maxDateTime.isValid() )
{
changeTime( COMPARE_MAX, MONTH );
}
m_currentMonth = m_monthItem->value();
QDate date;
date.setDate( m_currentYear, m_currentMonth, 1 );
m_dayItem->setValueRange( 1, date.daysInMonth() );
}
void Calendar::slot_dayChange( int value )
{
if ( m_minDateTime.isValid() )
{
changeTime( COMPARE_MIN, DAY );
}
else if ( m_maxDateTime.isValid() )
{
changeTime( COMPARE_MAX, DAY );
}
}
void Calendar::slot_hourChange( int value )
{
if ( m_minDateTime.isValid() )
{
changeTime( COMPARE_MIN, HOUR );
}
else if ( m_maxDateTime.isValid() )
{
changeTime( COMPARE_MAX, HOUR );
}
}
void Calendar::slot_minuteChange( int value )
{
if ( m_minDateTime.isValid() )
{
changeTime( COMPARE_MIN, MINUTE );
}
else if ( m_maxDateTime.isValid() )
{
changeTime( COMPARE_MAX, MINUTE );
}
}
void Calendar::slot_secondChange( int value )
{
if ( m_minDateTime.isValid() )
{
changeTime( COMPARE_MIN, SECOND );
}
else if ( m_maxDateTime.isValid() )
{
changeTime( COMPARE_MAX, SECOND );
}
}
void Calendar::changeTime( CompareType compare, TimeType time)
{
if ( COMPARE_MAX == compare )
{
/* switch没有break语句因为年月日时分秒要依次比较 */
switch( time )
{
case YEAR:
{
if ( m_maxDateTime < getDateTime() )
{
m_yearItem->setCurrentValue( m_maxDateTime.date().year(), true );
}
}
case MONTH:
{
if ( m_maxDateTime < getDateTime() )
{
m_monthItem->setCurrentValue(m_maxDateTime.date().month(), true);
}
}
case DAY:
{
if ( m_maxDateTime < getDateTime() )
{
m_dayItem->setCurrentValue( m_maxDateTime.date().day(), true );
}
}
case HOUR:
{
if ( m_maxDateTime < getDateTime() )
{
m_hourItem->setCurrentValue( m_maxDateTime.time().hour(), true );
}
}
case MINUTE:
{
if ( m_maxDateTime < getDateTime() )
{
m_minuteItem->setCurrentValue( m_maxDateTime.time().minute(), true );
}
}
case SECOND:
{
if ( m_maxDateTime < getDateTime() )
{
m_secondItem->setCurrentValue( m_maxDateTime.time().second(), true );
}
}
break;
}
}
else if ( COMPARE_MIN == compare )
{
switch( time )
{
case YEAR:
{
if ( m_minDateTime > getDateTime() )
{
m_yearItem->setCurrentValue( m_minDateTime.date().year(), true );
}
}
case MONTH:
{
if ( m_minDateTime > getDateTime() )
{
m_monthItem->setCurrentValue(m_minDateTime.date().month(), true);
}
}
case DAY:
{
if ( m_minDateTime > getDateTime() )
{
m_dayItem->setCurrentValue( m_minDateTime.date().day(), true );
}
}
case HOUR:
{
if ( m_minDateTime > getDateTime() )
{
m_hourItem->setCurrentValue( m_minDateTime.time().hour(), true );
}
}
case MINUTE:
{
if ( m_minDateTime > getDateTime() )
{
m_minuteItem->setCurrentValue( m_minDateTime.time().minute(), true );
}
}
case SECOND:
{
if ( m_minDateTime > getDateTime() )
{
m_secondItem->setCurrentValue( m_minDateTime.time().second(), true );
}
}
break;
}
}
}
void Calendar::setDateTime( const QDateTime& dateTime)
{
m_yearItem->setCurrentValue( dateTime.date().year(), false );
m_monthItem->setCurrentValue( dateTime.date().month(), false );
m_dayItem->setCurrentValue( dateTime.date().day(), false );
m_hourItem->setCurrentValue( dateTime.time().hour(), false );
m_minuteItem->setCurrentValue( dateTime.time().minute(), false );
m_secondItem->setCurrentValue( dateTime.time().second(), false );
m_currentYear = dateTime.date().year();
m_currentMonth = dateTime.date().month();
QDate date;
date.setDate( m_currentYear, m_currentMonth, 1 );
m_dayItem->setValueRange( 1, date.daysInMonth() );
}
QDateTime Calendar::getDateTime( ) const
{
QDateTime tmp( QDate( m_yearItem->value(), m_monthItem->value(), m_dayItem->value() ),
QTime( m_hourItem->value(), m_minuteItem->value(), m_secondItem->value() ) );
return tmp;
}
void Calendar::resizeEvent( QResizeEvent *e )
{
QLabel::resizeEvent( e );
const int h = e->size().height();
m_yearItem->setGeometry( 10, 0, 150, h );
m_monthItem->setGeometry( 165, 0, 95, h );
m_dayItem->setGeometry( 265, 0, 95, h );
m_hourItem->setGeometry( 380, 0, 95, h );
m_minuteItem->setGeometry( 480, 0, 95, h );
m_secondItem->setGeometry( 580, 0, 95, h );
}
void Calendar::setMinDateTime( const QDateTime & dateTime )
{
m_minDateTime = dateTime;
if (m_minDateTime.isValid())
{
changeTime( COMPARE_MIN, YEAR);
}
}
void Calendar::setMaxDateTime( const QDateTime & dateTime )
{
m_maxDateTime = dateTime;
if ( m_maxDateTime.isValid() )
{
changeTime( COMPARE_MAX, YEAR);
}
}
/***************************************************************************************************/
CalendarDialog::CalendarDialog( QWidget *parent )
: TVTMenu( parent )
{
m_Calendar = new Calendar( this );
m_Calendar->setDateTime( QDateTime::currentDateTime() );
m_line = new QWidget( this );
m_line->setStyleSheet( "QWidget {background: rgb(40,40,40);}" );
m_btnEnter = new TVTPushButton( GET_TXT( "IDCS_OK" ), this );
m_btnCancel = new TVTPushButton( GET_TXT( "IDCS_CANCEL" ), this );
//嵌入式linux下改成直角圆角弹出时闪烁setAttribute( Qt::WA_TranslucentBackground );
setStyleSheet( "CalendarDialog {border :1px solid rgb(149,149,149);background-color :rgb(16,17,20);margin:0px; }" );
setFixedSize( 685, 350 );
connect( m_btnEnter, SIGNAL( clicked() ), this, SLOT( slot_enter() ) );
connect( m_btnCancel, SIGNAL( clicked() ), this, SLOT( slot_cancel() ) );
}
void CalendarDialog::setMinDateTime( const QDateTime & dateTime )
{
m_Calendar->setMinDateTime( dateTime );
}
void CalendarDialog::setMaxDateTime( const QDateTime & dateTime )
{
m_Calendar->setMaxDateTime( dateTime );
}
void CalendarDialog::setDateTime( const QDateTime & dateTime )
{
m_Calendar->setDateTime( dateTime );
}
void CalendarDialog::slot_enter()
{
emit sig_sendDateTime( m_Calendar->getDateTime() );
hide();
}
void CalendarDialog::slot_cancel()
{
hide();
}
void CalendarDialog::resizeEvent( QResizeEvent* e )
{
TVTMenu::resizeEvent( e );
const int w = e->size().width();
m_Calendar->setGeometry( 0, 0, 685, 280 );
m_line->setGeometry( 1, 280, w - 2, 2 );
m_btnEnter->setGeometry( (w-240)/2, 295, 105, 40 );
m_btnCancel->setGeometry( (w-240)/2 + 150, 295, 105, 40 );
}
void CalendarDialog::mousePressEvent( QMouseEvent *ev )
{
QRect rect = this->rect();
if( rect.contains( ev->pos() ) )
{
ev->accept();
}
else
{
TVTMenu::mousePressEvent( ev );
}
}
/***************************************************************************************************/
DateDialog::DateDialog( QWidget *parent /* = 0 */ )
: TVTMenu( parent )
{
m_yearItem = new CalendarItem( GET_TXT( "IDCS_YEAR" ), this );
m_yearItem->setValueRange( 2010, 2037 );
m_monthItem = new CalendarItem( GET_TXT( "IDCS_MONTH" ), this );
m_monthItem->setValueRange( 1, 12 );
m_dayItem = new CalendarItem( GET_TXT( "IDCS_DAY" ), this );
m_dayItem->setValueRange( 1, 31 );
QDate date = QDate::currentDate();
m_yearItem->setCurrentValue( date.year(), false );
m_monthItem->setCurrentValue( date.month(), false );
m_dayItem->setCurrentValue( date.day(), false );
m_bg = new QWidget( this );
m_line = new QWidget( this );
m_line->setStyleSheet( "QWidget {background: rgb(40,40,40);}" );
m_btnEnter = new TVTPushButton( GET_TXT( "IDCS_OK" ), this );
m_btnCancel = new TVTPushButton( GET_TXT( "IDCS_CANCEL" ), this );
m_bg->setStyleSheet( ".QWidget { border : 1px solid rgb(149,149,149); border-radius : 4px; background-color : rgb(16,17,20); }" );
setFixedSize( 460, 350 );
setAttribute( Qt::WA_TranslucentBackground );
setStyleSheet( "DateDialog { border-radius : 4px; background : transparent; }" );
connect( m_yearItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_yearChange( int ) ) );
connect( m_monthItem, SIGNAL( sig_value( int ) ), this, SLOT( slot_monthChange( int ) ) );
connect( m_btnEnter, SIGNAL( clicked() ), this, SLOT( slot_enter() ) );
connect( m_btnCancel, SIGNAL( clicked() ), this, SLOT( slot_cancel() ) );
}
void DateDialog::slot_enter()
{
hide();
}
void DateDialog::slot_cancel()
{
hide();
}
void DateDialog::slot_yearChange( int value )
{
m_currentYear = value;
QDate date;
date.setDate( m_currentYear, m_currentMonth, 1 );
/* 根据年份和月份调整日期的最大最小值 */
m_dayItem->setValueRange( 1, date.daysInMonth() );
}
void DateDialog::slot_monthChange( int value )
{
m_currentMonth = value;
QDate date;
date.setDate( m_currentYear, m_currentMonth, 1 );
m_dayItem->setValueRange( 1, date.daysInMonth() );
}
void DateDialog::resizeEvent( QResizeEvent* e )
{
TVTMenu::resizeEvent( e );
const int w = e->size().width();
m_bg->setGeometry( rect() );
m_yearItem->setGeometry( 10, 0, 180, 280 );
m_monthItem->setGeometry( 200, 0, 120, 280 );
m_dayItem->setGeometry( 330, 0, 120, 280 );
m_line->setGeometry( 1, 280, w - 2, 2 );
m_btnEnter->setGeometry( (w-240)/2, 295, 105, 40 );
m_btnCancel->setGeometry( (w-240)/2 + 150, 295, 105, 40 );
}
/***************************************************************************************************/
TimeDialog::TimeDialog( QWidget *parent /* = 0 */ )
: TVTMenu( parent )
{
m_bg = new QWidget( this );
QTime time = QTime::currentTime();
m_hourItem = new CalendarItem( GET_TXT( "IDCS_HOUR" ), this );
m_hourItem->setValueRange( 0, 23 );
m_minuteItem = new CalendarItem( GET_TXT( "IDCS_MINUTE" ), this );
m_minuteItem->setValueRange( 0, 59 );
m_secondItem = new CalendarItem( GET_TXT( "IDCS_SECOND" ), this );
m_secondItem->setValueRange( 0, 59 );
m_hourItem->setCurrentValue( time.hour(), false );
m_minuteItem->setCurrentValue( time.minute(), false );
m_secondItem->setCurrentValue( time.second(), false );
m_line = new QWidget( this );
m_line->setStyleSheet( "QWidget {background: rgb(40,40,40);}" );
m_btnEnter = new TVTPushButton( GET_TXT( "IDCS_OK" ), this );
m_btnCancel = new TVTPushButton( GET_TXT( "IDCS_CANCEL" ), this );
m_bg->setStyleSheet( ".QWidget { border : 1px solid rgb(149,149,149); border-radius : 4px; background-color : rgb(16,17,20); }" );
setStyleSheet( "TimeDialog { border-radius : 4px; background : transparent; }" );
setFixedSize( 400, 350 );
setAttribute( Qt::WA_TranslucentBackground );
connect( m_btnEnter, SIGNAL( clicked() ), this, SLOT( slot_enter() ) );
connect( m_btnCancel, SIGNAL( clicked() ), this, SLOT( slot_cancel() ) );
}
void TimeDialog::slot_enter()
{
QTime time = QTime( m_hourItem->value(), m_minuteItem->value(), m_secondItem->value() );
emit sig_sendTime( time );
hide();
}
void TimeDialog::slot_cancel()
{
hide();
}
void TimeDialog::resizeEvent( QResizeEvent* e )
{
TVTMenu::resizeEvent( e );
const int w = e->size().width();
m_bg->setGeometry( rect() );
m_hourItem->setGeometry( 10, 0, 120, 280 );
m_minuteItem->setGeometry( 140, 0, 120, 280 );
m_secondItem->setGeometry( 270, 0, 120, 280 );
m_line->setGeometry( 1, 280, w - 2, 2 );
m_btnEnter->setGeometry( (w-240)/2, 295, 105, 40 );
m_btnCancel->setGeometry( (w-240)/2 + 140, 295, 105, 40 );
}

View File

@ -0,0 +1,222 @@
#include "pub_widget/CustomDialog.h"
#include <QLabel>
#include <QGraphicsDropShadowEffect>
#include <QVBoxLayout>
#include <QPushButton>
#include "pub_utility_api/FileStyle.h"
CustomDialog::CustomDialog(QWidget *parent,bool translucentBackground) : FramelessWindow<QDialog>(translucentBackground, parent), shadow_(nullptr)
{
setupUi();
CustomDialog::setWindowTitle(QApplication::applicationName());
QVector<QWidget*> widgets = m_titleWidget->getAllWidgets();
widgets.push_back(m_titleWidget);
setTitlebar(widgets);
setShadowEnable(false);
setResizeable(true);
connect(m_titleWidget, SIGNAL(closeClicked()), this,SLOT(slot_close()));
}
CustomDialog::~CustomDialog()
{
if(!shadow_)
{
delete shadow_;
shadow_ = nullptr;
}
}
void CustomDialog::addUserLayout(QLayout *layout,int spacing)
{
mainLayout_->addLayout(layout);
mainLayout_->addSpacing(spacing);
}
void CustomDialog::setLayout(QLayout *layout)
{
mainLayout_->addLayout(layout);
}
void CustomDialog::setCloseBtnVisible(bool visible)
{
m_titleWidget->setCloseBtnVisible(visible);
}
int CustomDialog::titleHeight()
{
return m_titleWidget->height();
}
void CustomDialog::setupUi()
{
this->setObjectName("CustomDialog");
centralWidget_ = new QWidget();
centralWidget_->setObjectName("CustomDialogCentralWidget");
m_titleWidget = new CustomDialogTitle(this);
QHBoxLayout* hlTitle = new QHBoxLayout();
hlTitle->setContentsMargins(0, 0, 0, 0);
hlTitle->setSpacing(0);
hlTitle->addWidget(m_titleWidget);
// hlTitle->setSizeConstraint(QLayout::SetMinimumSize); //设定其为固定的大小
mainLayout_ = new QVBoxLayout();
centralWidget_->setLayout(mainLayout_);
QVBoxLayout* hMain = new QVBoxLayout();
hMain->setContentsMargins(0, 0, 0, 0);
hMain->setSpacing(0);
hMain->addLayout(hlTitle);
hMain->addWidget(centralWidget_);
QDialog::setLayout(hMain);
}
void CustomDialog::setShadowEnable(bool enable)
{
if (!shadow_) {
shadow_ = new QGraphicsDropShadowEffect();
shadow_->setColor(QColor(2, 122, 255, 255));
shadow_->setBlurRadius(20);
shadow_->setOffset(0.0);
}
centralWidget_->setGraphicsEffect(enable ? shadow_ : nullptr);
}
void CustomDialog::setWindowTitle(const QString &title)
{
QDialog::setWindowTitle(title);
m_titleWidget->setTitle(title);
}
void CustomDialog::slot_close()
{
close();
}
////用UI方式加载的用以下方法
CustomUiDialog::CustomUiDialog(QWidget *parent,bool translucentBackground) : FramelessWindow<QDialog>(translucentBackground, parent)
{
m_mainLayout_ = NULL;
m_centralWidget_ = NULL;
m_bAutoLayout = false;
this->setObjectName("CustomDialog");
m_titleWidget = new CustomDialogTitle(this);
CustomUiDialog::setWindowTitle(QApplication::applicationName());
QVector<QWidget*> widgets = m_titleWidget->getAllWidgets();
widgets.push_back(m_titleWidget);
setTitlebar(widgets);
m_titleWidget->raise();
setResizeable(true);
connect(m_titleWidget, SIGNAL(closeClicked()), this,SLOT(slot_close()));
}
CustomUiDialog::~CustomUiDialog()
{
}
void CustomUiDialog::resizeEvent(QResizeEvent *ev)
{
QDialog::resizeEvent( ev );
const int w = ev->size().width();
const int t_h = m_titleWidget->height();
m_titleWidget->setGeometry(0,0, w,t_h);
if(m_bAutoLayout)
{
QMargins margins = this->contentsMargins();
if(margins.top() != m_titleWidget->height())
{
margins.setTop(m_titleWidget->height());
this->setContentsMargins(margins);
}
}
}
void CustomUiDialog::keyPressEvent(QKeyEvent *ev)
{
if (!ev->modifiers() || (ev->modifiers() & Qt::KeypadModifier && ev->key() == Qt::Key_Enter))
{
if( ev->key() == Qt::Key_Enter || ev->key() == Qt::Key_Return )
{
ev->accept();
return;
}
else if( ev->key() == Qt::Key_Escape )
{
ev->accept();
return;
}
}
QDialog::keyPressEvent( ev );
}
void CustomUiDialog::setCloseBtnVisible(bool visible)
{
m_titleWidget->setCloseBtnVisible(visible);
}
void CustomUiDialog::addTitlebar(QWidget *w)
{
w->stackUnder(m_titleWidget);
w->lower();
m_titleWidget->raise();
w->setMinimumHeight(m_titleWidget->height());
FramelessWindow<QDialog>::addTitlebar(w);
}
int CustomUiDialog::titleHeight()
{
return m_titleWidget->height();
}
void CustomUiDialog::setAutoLayout(bool bEnable)
{
if(m_mainLayout_ == NULL)
{
m_mainLayout_ = new QVBoxLayout();
m_mainLayout_->setSpacing(0);
m_mainLayout_->setContentsMargins(0,0,0,0);
}
if(m_centralWidget_ == NULL)
{
m_centralWidget_ = new QWidget();
m_centralWidget_->setObjectName("CustomDialogCentralWidget");
m_mainLayout_->addWidget(m_centralWidget_);
m_centralWidget_->setLayout(this->layout());
this->setLayout(m_mainLayout_);
}
m_bAutoLayout = bEnable;
setCustomMainMargins(bEnable);
}
void CustomUiDialog::setWindowTitle(const QString &title)
{
QDialog::setWindowTitle(title);
m_titleWidget->setTitle(title);
}
void CustomUiDialog::slot_close()
{
close();
}

View File

@ -0,0 +1,92 @@
#include "pub_widget/CustomDialog2.h"
#include <QLabel>
#include <QGraphicsDropShadowEffect>
#include <QVBoxLayout>
#include <QPushButton>
#include "pub_utility_api/FileStyle.h"
CustomDialog2::CustomDialog2(QWidget *parent) : FramelessWindow<QDialog>(true, parent), shadow_(nullptr)
{
setupUi();
CustomDialog2::setWindowTitle(QApplication::applicationName());
setTitlebar({centralWidget_, labelTitle_});
std::string strFullPath = iot_public::CFileStyle::getPathOfStyleFile("customDialog2.qss");
loadStyleSheetFile(strFullPath.c_str(), this);
setShadowEnable(true);
setResizeable(true);
connect(pushButtonClose_, &QPushButton::clicked, [this]() { reject(); });
}
CustomDialog2::~CustomDialog2()
{
if(!shadow_)
{
delete shadow_;
shadow_ = nullptr;
}
}
void CustomDialog2::addUserLayout(QLayout *layout,int spacing)
{
mainLayout_->addLayout(layout);
mainLayout_->addSpacing(spacing);
}
void CustomDialog2::setLayout(QLayout *layout)
{
addUserLayout(layout,0);
}
void CustomDialog2::setupUi()
{
this->setObjectName("CustomDialog");
centralWidget_ = new QWidget();
centralWidget_->setObjectName("CustomDialogCentralWidget");
pushButtonClose_ = new QPushButton();
pushButtonClose_->setObjectName("CustomDialogButtonClose");
pushButtonClose_->setCursor(QCursor(Qt::PointingHandCursor));
labelTitle_ = new QLabel();
labelTitle_->setObjectName("CustomDialogTitle");
QHBoxLayout* hlTitle = new QHBoxLayout();
hlTitle->setContentsMargins(0, 0, 0, 0);
hlTitle->setSpacing(0);
hlTitle->addWidget(labelTitle_);
hlTitle->addStretch();
hlTitle->addWidget(pushButtonClose_);
// hlTitle->setSizeConstraint(QLayout::SetMinimumSize); //设定其为固定的大小
mainLayout_ = new QVBoxLayout();
mainLayout_->addLayout(hlTitle);
centralWidget_->setLayout(mainLayout_);
QHBoxLayout* hMain = new QHBoxLayout();
hMain->setContentsMargins(0, 0, 0, 0);
hMain->addWidget(centralWidget_);
QDialog::setLayout(hMain);
}
void CustomDialog2::setShadowEnable(bool enable)
{
if (!shadow_) {
shadow_ = new QGraphicsDropShadowEffect();
shadow_->setColor(QColor(2, 122, 255, 255));
shadow_->setBlurRadius(20);
shadow_->setOffset(0.0);
}
centralWidget_->setGraphicsEffect(enable ? shadow_ : nullptr);
}
void CustomDialog2::setWindowTitle(const QString &title)
{
QDialog::setWindowTitle(title);
labelTitle_->setText(title);
}

View File

@ -0,0 +1,55 @@
#include "pub_widget/CustomDialogTitle.h"
#include <QApplication>
CustomDialogTitle::CustomDialogTitle(QWidget *parent)
: QLabel(parent)
{
m_btnClose = new QPushButton(this);
m_icon = new AdaptImage(this);
m_title = new CustomLabel(this);
m_icon->setObjectName("icon");
m_title->setObjectName("title");
// 最小化、最大化、关闭按钮
m_btnClose->setToolTip(tr("关闭"));
m_btnClose->setObjectName("close_btn");
//这个close 没有信号了
connect(m_btnClose, SIGNAL(clicked()), this, SIGNAL(closeClicked()));
}
CustomDialogTitle::~CustomDialogTitle()
{
}
void CustomDialogTitle::setTitle(const QString& title)
{
m_title->setText(title);
}
void CustomDialogTitle::setCloseBtnVisible(bool visible)
{
m_btnClose->setVisible( visible );
}
QVector<QWidget*> CustomDialogTitle::getAllWidgets()
{
return {m_icon,m_title};
}
void CustomDialogTitle::resizeEvent(QResizeEvent *ev)
{
const int w = ev->size().width();
const int h = ev->size().height();
int curX = 10;
int curY = (h-32)/2;
m_icon->setGeometry( curX, curY, 32, 32 );
curX += 32;
m_title->setGeometry(curX,curY, w-(32+curX+10),32);
curX = w - 10;
curX -= 32;
m_btnClose->setGeometry( curX, curY, 32, 32 );
}

View File

@ -0,0 +1,179 @@
#include "pub_widget/CustomMainWindow.h"
#include <QVBoxLayout>
CustomMainWindow::CustomMainWindow(QWidget *parent)
: FramelessWindow<QMainWindow>(false,parent)
{
setupUi();
CustomMainWindow::setWindowTitle(QApplication::applicationName());
QVector<QWidget*> widgets = m_titleWidget->getAllWidgets();
widgets.push_back(m_titleWidget);
setTitlebar(widgets);
setResizeable(true);
}
CustomMainWindow::~CustomMainWindow()
{
}
void CustomMainWindow::setWindowTitle(const QString &title)
{
FramelessWindow<QMainWindow>::setWindowTitle(title);
m_titleWidget->setTitle(title);
}
void CustomMainWindow::setCentralWidget(QWidget *widget)
{
mainLayout_->addWidget(widget);
}
void CustomMainWindow::setLayout(QLayout *layout)
{
mainLayout_->addLayout(layout);
}
void CustomMainWindow::setSendCloseSignal(bool isSend)
{
m_titleWidget->setSendCloseSignal(isSend);
}
void CustomMainWindow::setupUi()
{
this->setObjectName("CustomMainWindow");
QWidget* mainWidget = new QWidget();
centralWidget_ = new QWidget();
centralWidget_->setObjectName("CustomDialogCentralWidget");
m_titleWidget = new MainTitle(this);
QHBoxLayout* hlTitle = new QHBoxLayout();
hlTitle->setContentsMargins(0, 0, 0, 0);
hlTitle->setSpacing(0);
hlTitle->addWidget(m_titleWidget);
// hlTitle->setSizeConstraint(QLayout::SetMinimumSize); //设定其为固定的大小
mainLayout_ = new QVBoxLayout();
centralWidget_->setLayout(mainLayout_);
QVBoxLayout* hMain = new QVBoxLayout(mainWidget);
hMain->setContentsMargins(0, 0, 0, 0);
hMain->setSpacing(0);
hMain->addLayout(hlTitle);
hMain->addWidget(centralWidget_);
connect(m_titleWidget , &MainTitle::closeClicked , [=](){
emit closeClicked();
});
QMainWindow::setCentralWidget(mainWidget);
}
////用UI方式加载的用以下方法
CustomUiMainWindow::CustomUiMainWindow(QWidget *parent)
: FramelessWindow<QMainWindow>(false, parent)
{
m_bAutoLayout = false;
m_userTitleBar = nullptr;
this->setObjectName("CustomUiMainWindow");
m_titleWidget = new MainTitle(this);
CustomUiMainWindow::setWindowTitle(QApplication::applicationName());
QVector<QWidget*> widgets = m_titleWidget->getAllWidgets();
widgets.push_back(m_titleWidget);
setTitlebar(widgets);
m_titleWidget->raise();
setResizeable(true);
connect(m_titleWidget, SIGNAL(sizeChanged()), this, SLOT(slot_titleSizeChanged()));
connect(m_titleWidget , &MainTitle::closeClicked , [=](){
emit closeClicked();
});
}
CustomUiMainWindow::~CustomUiMainWindow()
{
}
void CustomUiMainWindow::resizeEvent(QResizeEvent *ev)
{
int w = this->width();
// int h = this->height();
const int t_h = m_titleWidget->height();
m_titleWidget->setGeometry(0,0, w,t_h);
if(m_bAutoLayout)
{
QMargins margins = this->contentsMargins();
if(margins.top() != m_titleWidget->height())
{
margins.setTop(m_titleWidget->height());
this->setContentsMargins(margins);
}
}
QMainWindow::resizeEvent( ev );
}
void CustomUiMainWindow::setTitleWidget(QWidget *w)
{
m_userTitleBar = w;
w->stackUnder(m_titleWidget);
w->lower();
m_titleWidget->raise();
int h = m_titleWidget->maximumHeight();
w->setMinimumHeight(h);
w->setMaximumHeight(h);
FramelessWindow<QMainWindow>::addTitlebar(w);
}
void CustomUiMainWindow::setAutoLayout(bool bEnable)
{
m_bAutoLayout = bEnable;
setCustomMainMargins(bEnable);
}
void CustomUiMainWindow::hideWindowTitle()
{
m_titleWidget->hide();
}
int CustomUiMainWindow::titleHeight()
{
return m_titleWidget->height();
}
void CustomUiMainWindow::setSendCloseSignal(bool isSend)
{
m_titleWidget->setSendCloseSignal(isSend);
}
void CustomUiMainWindow::setWindowTitle(const QString &title)
{
m_titleWidget->show();
QMainWindow::setWindowTitle(title);
m_titleWidget->setTitle(title);
}
void CustomUiMainWindow::slot_titleSizeChanged()
{
int h = m_titleWidget->maximumHeight();
if(m_userTitleBar)
{
m_userTitleBar->setMinimumHeight(h);
m_userTitleBar->setMaximumHeight(h);
}
}

View File

@ -0,0 +1,150 @@
#include "pub_widget/MainTitle.h"
#include "pub_widget/Widgets.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QUrl>
#include <QMessageBox>
#include "pub_widget/MessageBox.h"
MainTitle::MainTitle(QWidget *parent)
: QLabel(parent), m_isMaximized(false),m_sendCloseSignal(false)
{
m_btnMax = new CustomButton(this);
m_btnMin = new CustomButton(this);
m_btnClose = new CustomButton(this);
m_icon = new QLabel(this);
m_title = new CustomLabel(this);
m_icon->setObjectName("icon");
m_title->setObjectName("title");
// 最小化、最大化、关闭按钮
m_btnMin->setToolTip(tr("最小化"));
m_btnMax->setToolTip(tr("最大化"));
m_btnClose->setToolTip(tr("关闭"));
m_btnMin->setObjectName("min_btn");
m_btnMax->setObjectName("max_btn");
m_btnClose->setObjectName("close_btn");
connect(m_btnMin, SIGNAL(clicked()), this, SLOT(slot_min()));
connect(m_btnMax, SIGNAL(clicked()), this, SLOT(slot_max()));
connect(m_btnClose, SIGNAL(clicked()), this, SLOT(slot_close()));
QWidget *win = this->window();
Q_ASSERT( win != NULL );
bool isMax = win->isMaximized();
setBtnMaxSheet(isMax);
}
void MainTitle::setBtnMaxSheet(bool isMax)
{
if(isMax)
{
m_btnMax->setProperty("buttonStatus", "max");
m_btnMax->setToolTip(tr("最大化"));
}
else
{
m_btnMax->setProperty("buttonStatus", "normal");
m_btnMax->setToolTip(tr("正常"));
}
m_btnMax->style()->polish(m_btnMax);
}
void MainTitle::setSendCloseSignal(bool isSend)
{
m_sendCloseSignal = isSend;
}
QVector<QWidget *> MainTitle::getAllWidgets()
{
return {m_icon,m_title};
}
void MainTitle::slot_min()
{
QWidget *win = this->window();
Q_ASSERT( win != NULL );
win->showMinimized();
}
void MainTitle::slot_max()
{
QWidget *win = this->window();
Q_ASSERT( win != NULL );
if (win->isMaximized())
{
win->showNormal();
}
else
{
win->showMaximized();
}
bool isMax = win->isMaximized();
setBtnMaxSheet(isMax);
emit maximized(isMax);
}
void MainTitle::slot_close()
{
if(!m_sendCloseSignal)
{
int button = N_MessageBox::question(this, tr("提示"),tr("是否退出?"));
if (button == N_MessageBox::Ok) {
QMetaObject::invokeMethod( qApp, "quit", Qt::QueuedConnection );
}
}
else
{
emit closeClicked();
}
}
MainTitle::~MainTitle()
{
}
void MainTitle::setTitle(const QString& title)
{
m_title->setText(title);
}
void MainTitle::resizeEvent(QResizeEvent *ev)
{
const int w = ev->size().width();
const int h = ev->size().height();
int curX = 10;
int curY = (h-32)/2;
m_icon->setGeometry( curX, curY, 32, 32 );
curX += 32;
m_title->setGeometry(curX,curY, w-(32*6),32);
curX = w - 10;
curX -= 32;
m_btnClose->setGeometry( curX, curY, 32, 32 );
curX -= 32;
m_btnMax->setGeometry( curX, curY, 32, 32 );
curX -= 32;
m_btnMin->setGeometry( curX, curY, 32, 32 );
QWidget *win = this->window();
if(win)
{
bool isMax = win->isMaximized();
setBtnMaxSheet(isMax);
}
emit sizeChanged();
}
void MainTitle::mouseDoubleClickEvent(QMouseEvent *ev)
{
slot_max();
}

View File

@ -0,0 +1,198 @@
#include "pub_widget/MenuFrame.h"
#include <QHBoxLayout>
#include <QScrollArea>
#include <QScrollBar>
#include <QDebug>
MenuFrame::MenuFrame(QWidget *parent) : QFrame(parent)
{
this->setObjectName("MenuForm");
m_btnGroup = new QButtonGroup;
// 创建滚动区域
m_scrollArea = new QScrollArea(this);
m_scrollArea->setWidgetResizable(true);
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QWidget* scrollAreaWidget = new QWidget(m_scrollArea);
scrollAreaWidget->setObjectName("scrollAreaWidget");
QVBoxLayout* scrollAreaWidgetVLayout = new QVBoxLayout(scrollAreaWidget);
scrollAreaWidgetVLayout->setSpacing(0);
scrollAreaWidgetVLayout->setContentsMargins(0,0,0,0);
m_centralWidget = new QWidget(scrollAreaWidget);
scrollAreaWidget->setObjectName("centralWidget");
QSpacerItem* verticalSpacer = new QSpacerItem(5, 5, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
scrollAreaWidgetVLayout->addWidget(m_centralWidget);
scrollAreaWidgetVLayout->addItem(verticalSpacer);
QVBoxLayout* verticalLayout = new QVBoxLayout(m_centralWidget);
verticalLayout->setSpacing(0);
verticalLayout->setContentsMargins(0,0,0,0);
QWidget* toolBtnWidget = new QWidget(m_scrollArea);
scrollAreaWidget->setObjectName("toolBtnWidget");
QHBoxLayout* HLayout = new QHBoxLayout(toolBtnWidget);
HLayout->setSpacing(0);
HLayout->setContentsMargins(0,0,0,0);
// 创建自定义滚动按钮
m_upButton = new QPushButton("", toolBtnWidget);
m_upButton->setObjectName("upButton");
m_downButton = new QPushButton("", toolBtnWidget);
m_downButton->setObjectName("downButton");
QSpacerItem* horizontalSpacer1 = new QSpacerItem(20, 5, QSizePolicy::Expanding, QSizePolicy::Minimum);
QSpacerItem* horizontalSpacer2 = new QSpacerItem(20, 5, QSizePolicy::Expanding, QSizePolicy::Minimum);
HLayout->addItem(horizontalSpacer1);
HLayout->addWidget(m_upButton);
HLayout->addWidget(m_downButton);
HLayout->addItem(horizontalSpacer2);
QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(toolBtnWidget->sizePolicy().hasHeightForWidth());
toolBtnWidget->setSizePolicy(sizePolicy);
QHBoxLayout* scrollAreaHLayout = new QHBoxLayout(m_scrollArea);
scrollAreaHLayout->setSpacing(0);
scrollAreaHLayout->setContentsMargins(0,0,0,0);
scrollAreaHLayout->addWidget(scrollAreaWidget);
m_scrollArea->setWidget(scrollAreaWidget);
// 设置布局
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0,0,0,0);
this->setLayout(mainLayout);
mainLayout->addWidget(m_scrollArea);
mainLayout->addWidget(toolBtnWidget);
connect( m_btnGroup, static_cast<void (QButtonGroup::*)(int)
>(&QButtonGroup::buttonClicked),
this, &MenuFrame::slotButtonEmit);
connect( m_upButton, SIGNAL(clicked()), this, SLOT(slotUpBtnClicked()) );
connect( m_downButton, SIGNAL(clicked()), this, SLOT(slotDownBtnClicked()) );
}
MenuFrame::~MenuFrame()
{
}
void MenuFrame::addToolBtn(QPushButton *btn,int id)
{
btn->setCheckable(true);
int nBtnId = (id==-1) ? m_btnGroup->buttons().count() : id;
m_btnGroup->addButton(btn,nBtnId);
m_centralWidget->layout()->addWidget(btn);
}
QPushButton *MenuFrame::addToolBtn(const QString &btnStr,int id)
{
QPushButton* btn = new QPushButton(m_centralWidget);
btn->setCheckable(true);
int nBtnId = (id==-1) ? m_btnGroup->buttons().count() : id;
m_btnGroup->addButton(btn,nBtnId);
btn->setText(btnStr);
btn->setToolTip(btnStr);
m_centralWidget->layout()->addWidget(btn);
return btn;
}
void MenuFrame::setButtonClicked(int id)
{
QAbstractButton *btn = m_btnGroup->button(id);
if(btn != NULL)
{
slotButtonEmit(id);
btn->setChecked(true);
}
}
int MenuFrame::checkedId()
{
return m_btnGroup->checkedId();
}
void MenuFrame::resizeEvent(QResizeEvent *ev)
{
QFrame::resizeEvent(ev);
QList<QAbstractButton*> btns = m_btnGroup->buttons();
int btnsHeight = 0;
if(btns.count() != 0)
{
btnsHeight = btns.count()*btns.at(0)->height();
}
int upBtnHeight = m_upButton->height();
if(btnsHeight + upBtnHeight > m_scrollArea->height())
{
m_upButton->setHidden(false);
m_downButton->setHidden(false);
}
else
{
m_upButton->setHidden(true);
m_downButton->setHidden(true);
}
}
void MenuFrame::slotButtonEmit(int index )
{
if( index >= 0)
{
emit buttonClicked(index);
}
}
void MenuFrame::slotUpBtnClicked()
{
QScrollBar * verticalScrollBar = m_scrollArea->verticalScrollBar();
QList<QAbstractButton*> btns = m_btnGroup->buttons();
int btnsHeight = 0;
if(btns.count() != 0)
{
btnsHeight = btns.at(0)->height();
}
int value = verticalScrollBar->value() - btnsHeight; // 向上滚动
if (value < verticalScrollBar->minimum()) {
value = verticalScrollBar->minimum();
}
verticalScrollBar->setValue(value);
}
void MenuFrame::slotDownBtnClicked()
{
QScrollBar * verticalScrollBar = m_scrollArea->verticalScrollBar();
QList<QAbstractButton*> btns = m_btnGroup->buttons();
int btnsHeight = 0;
if(btns.count() != 0)
{
btnsHeight = btns.at(0)->height();
}
int value = verticalScrollBar->value() + btnsHeight; // 向下滚动
if (value > verticalScrollBar->maximum()) {
value = verticalScrollBar->maximum();
}
verticalScrollBar->setValue(value);
}

View File

@ -0,0 +1,232 @@
#include "pub_widget/MessageBox.h"
#include <QtDebug>
#include <QApplication>
#include "pub_widget/Widgets.h"
N_MessageBox::N_MessageBox( const QString &text, int btnMode, N_MSG_BOX_ICON icon, QWidget* parent )
: CustomDialog( parent ), m_curReturnValue( NoButton ), m_btnMode( btnMode )
{
switch ( icon )//初始化图标
{
case ICON_WARNING:
{
m_icon = new AdaptImage(this );
m_icon->setProperty("MSG_TYPE","ICON_WARNING");
setWindowTitle( tr( "警告" ) );
}
break;
case ICON_ERROR:
{
m_icon = new AdaptImage(this );
m_icon->setProperty("MSG_TYPE","ICON_ERROR");
setWindowTitle( tr( "错误" ) );
}
break;
case ICON_INFORMATION:
{
m_icon = new AdaptImage(this );
m_icon->setProperty("MSG_TYPE","ICON_INFORMATION");
setWindowTitle( tr( "提示" ) );
}
break;
case ICON_QUESTION:
{
m_icon = new AdaptImage(this );
m_icon->setProperty("MSG_TYPE","ICON_QUESTION");
setWindowTitle( tr( "问题" ) );
}
break;
default:
m_icon = new AdaptImage(this );
m_icon->setProperty("MSG_TYPE","ICON_DEFAULT");
break;
}
//初始化文字及分割线
m_text = new QLabel( text, this );
m_text->setObjectName( "showText" );
m_text->setAlignment( Qt::AlignCenter );
m_text->setWordWrap( true );
adjustTextToFixWidth( text );
setCloseBtnVisible( false );
m_btnGroup = new QButtonGroup( this );
connect( m_btnGroup, SIGNAL( buttonClicked( int ) ), this, SLOT( slot_buttonClicked( int ) ) );
QPushButton *lastButton = NULL;
if ( 0 != ( YesToAll & btnMode ) )
lastButton = AddButton( YesToAll, tr( "全部是" ) );
if ( 0 != ( NoToAll & btnMode ) )
lastButton = AddButton( NoToAll, tr( "全部否" ) );
if ( 0 != ( Ok & btnMode ) )
lastButton = AddButton( Ok, tr( "确定" ) );
if ( 0 != ( Cancel & btnMode ) )
lastButton = AddButton( Cancel, tr( "取消" ) );
if ( 0 != ( Yes & btnMode ) )
lastButton = AddButton( Yes, tr( "" ) );
if ( 0 != ( No & btnMode ) )
lastButton = AddButton( No, tr( "" ) );
//最右边的作为默认按钮
if ( NULL != lastButton )
{
lastButton->setAutoDefault( true );
lastButton->setFocus();
m_curReturnValue = m_btnGroup->id( lastButton );
}
}
N_MessageBox::~N_MessageBox()
{
}
int N_MessageBox::message(const QString &title, const QString &text, int btnMode, N_MSG_BOX_ICON icon, QWidget *parent )
{
N_MessageBox box( text, btnMode, icon, parent );
if(!title.isEmpty())
{
box.setWindowTitle(title);
}
box.exec();
return box.m_curReturnValue;
}
int N_MessageBox::warning(QWidget *parent,const QString &title, const QString &text, int button0 , int button1 , int button2 )
{
return N_MessageBox::message(title, text, button0 | button1 | button2, ICON_WARNING, parent );
}
void N_MessageBox::error(QWidget *parent,const QString &title, const QString &text )
{
N_MessageBox::message(title, text, Ok, ICON_ERROR, parent );
}
int N_MessageBox::information(QWidget *parent,const QString &title, const QString &text , int button0, int button1, int button2 )
{
return N_MessageBox::message(title, text, button0 | button1 | button2, ICON_INFORMATION, parent );
}
int N_MessageBox::question(QWidget *parent,const QString &title, const QString &text, int button0 , int button1 , int button2 )
{
return N_MessageBox::message(title, text, button0 | button1 | button2, ICON_QUESTION, parent );
}
int N_MessageBox::choice(QWidget *parent,const QString &title, const QString &text )
{
return N_MessageBox::message(title, text, Yes | No, ICON_QUESTION, parent );
}
int N_MessageBox::error_choice(QWidget *parent,const QString &title, const QString &text )
{
return N_MessageBox::message(title, text, Yes | No, ICON_ERROR, parent );
}
int N_MessageBox::about(QWidget *parent, const QString &title, const QString &text)
{
return N_MessageBox::message(title, text, Yes, ICON_INFORMATION, parent );
}
int N_MessageBox::critical(QWidget *parent, const QString &title, const QString &text)
{
return N_MessageBox::message(title, text, Yes, ICON_WARNING, parent );
}
void N_MessageBox::slot_buttonClicked( int id )
{
m_curReturnValue = id;
accept();
}
void N_MessageBox::resizeEvent(QResizeEvent *ev)
{
CustomDialog::resizeEvent( ev );
const int title_h = this->titleHeight();
int w = ev->size().width();
int h = ev->size().height()-title_h;
const int x_begin = 0;
const int y_begin = title_h;
if(h<=84)
{
h = 86;
}
m_icon->setGeometry( x_begin+50,(h-42+y_begin)/2, 42, 42 );
m_text->setGeometry( x_begin+50+42+10, (h-84+y_begin)/2, w - (x_begin+50+42+10+20), 84 );
QList<QAbstractButton*> listBtn = m_btnGroup->buttons();
int curX = w - 10;
int curY = title_h;
bool bSpace = true;
for ( int i = listBtn.size() - 1; i >= 0; i-- )
{
///如果是全否或者全是需要间隔大一点
if ( bSpace && ( 0 != ( NoToAll & m_btnGroup->id( listBtn[i] ) ) || 0 != ( YesToAll == m_btnGroup->id( listBtn[i] ) ) ) )
{
curX -= 10;
bSpace = false;
}
curX -= 90;
listBtn[i]->setGeometry( curX, ev->size().height() - 52, 80, 32 );
}
}
void N_MessageBox::keyPressEvent( QKeyEvent *ev )
{
bool ok = false;
if ( !ev->modifiers() && ev->key() == Qt::Key_Escape )//不是单纯的esc键就退出
{
ok = true;
}
if ( ok )
{
if ( 0 != ( NoToAll & m_btnMode ) )
{
m_curReturnValue = NoToAll;
}
if ( 0 != ( No & m_btnMode ) )
{
m_curReturnValue = No;
}
if ( 0 != ( Cancel & m_btnMode ) )
{
m_curReturnValue = Cancel;
}
}
CustomDialog::keyPressEvent( ev );
}
CustomPushButton *N_MessageBox::AddButton( N_MSG_BOX_RETURN retValue, const QString &text )
{
CustomPushButton *btn = new CustomPushButton( text, this );
m_btnGroup->addButton( btn, retValue );
return btn;
}
void N_MessageBox::adjustTextToFixWidth( const QString & text )
{
QFontMetrics fm ( m_text->font() );
int textWidth = fm.width( text );
int nWidth = m_text->width();
if ( nWidth < textWidth )
{
m_text->setAlignment( Qt::AlignVCenter| Qt::AlignLeft );
}
else
{
m_text->setAlignment( Qt::AlignCenter );
}
}

View File

@ -0,0 +1,620 @@
/*
FramelessHelper, an easy way to support move/resize on
frameless toplevel windows.
Copyright (C) 2011 Nishant Parashar
Email:- nishcode (at) gmail (dot) com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QRubberBand>
#include <QMouseEvent>
#include <QMutex>
#include <QDebug>
#include "pub_widget/NcFramelessHelper.h"
class NcCursorPosCalculator
{
public:
NcCursorPosCalculator();
void reset();
void recalculate( const QPoint& globalMousePos, const QRect& frameRect );
public:
bool onEdges;
bool onLeftEdge;
bool onRightEdge;
bool onTopEdge;
bool onBottomEdge;
bool onTopLeftEdge;
bool onBottomLeftEdge;
bool onTopRightEdge;
bool onBottomRightEdge;
static int mBorderWidth;
};
//TODO: Should not be static.
int NcCursorPosCalculator::mBorderWidth = 5;
class NcWidgetData
{
public:
NcWidgetData( NcFramelessHelperImpl* _d, QWidget* topLevelWidget );
~NcWidgetData();
//void setWidget( QWidget* topLevelWidget );
QWidget* widget();
void handleWidgetEvent( QEvent* event );
void updateRubberBandStatus();
private:
void updateCursorShape( const QPoint& globalMousePos );
void resizeWidget( const QPoint& globalMousePos );
void moveWidget( const QPoint& globalMousePos );
void handleMousePressEvent( QMouseEvent* event );
void handleMouseReleaseEvent( QMouseEvent* event );
void handleMouseMoveEvent( QMouseEvent* event );
void handleLeaveEvent( QEvent* event );
void handleHoverMoveEvent( QHoverEvent* event );
private:
NcFramelessHelperImpl* d;
QRubberBand* mRubberBand;
bool mLeftButtonPressed;
QWidget* mWidget;
QPoint mDragPos;
NcCursorPosCalculator mPressedMousePos;
NcCursorPosCalculator mMoveMousePos;
bool mCursorShapeChanged;
Qt::WindowFlags mWindowFlags;
//鼠标是否在标题栏中点击
bool mTitlePressed;
};
class NcFramelessHelperImpl
{
public:
QHash< QWidget*, NcWidgetData* > mHashWidgetData;
bool mWidgetMovable;
bool mWidgetResizable;
bool mUseRubberBandOnResize;
bool mUseRubberBandOnMove;
};
NcCursorPosCalculator::NcCursorPosCalculator()
{
reset();
}
void NcCursorPosCalculator::reset()
{
onEdges = false;
onLeftEdge = false;
onRightEdge = false;
onTopEdge = false;
onBottomEdge = false;
onTopLeftEdge = false;
onBottomLeftEdge = false;
onTopRightEdge = false;
onBottomRightEdge = false;
}
void NcCursorPosCalculator::recalculate( const QPoint& globalMousePos, const QRect& frameRect )
{
int globalMouseX = globalMousePos.x();
int globalMouseY = globalMousePos.y();
int frameX = frameRect.x();
int frameY = frameRect.y();
int frameWidth = frameRect.width();
int frameHeight = frameRect.height();
onLeftEdge = globalMouseX >= frameX &&
globalMouseX <= frameX + mBorderWidth;
onRightEdge = globalMouseX >= frameX + frameWidth - mBorderWidth &&
globalMouseX <= frameX + frameWidth;
onTopEdge = globalMouseY >= frameY &&
globalMouseY <= frameY + mBorderWidth;
onBottomEdge = globalMouseY >= frameY + frameHeight - mBorderWidth &&
globalMouseY <= frameY + frameHeight;
onTopLeftEdge = onTopEdge && onLeftEdge;
onBottomLeftEdge = onBottomEdge && onLeftEdge;
onTopRightEdge = onTopEdge && onRightEdge;
onBottomRightEdge = onBottomEdge && onRightEdge;
//only these checks would be enough
onEdges = onLeftEdge || onRightEdge ||
onTopEdge || onBottomEdge;
}
NcWidgetData::NcWidgetData( NcFramelessHelperImpl* _d, QWidget* topLevelWidget )
{
d = _d;
mWidget = topLevelWidget;
mLeftButtonPressed = false;
mRubberBand = 0;
mCursorShapeChanged = false;
mTitlePressed = false;
mWindowFlags = mWidget->windowFlags();
//---from Qt docs of setWindowFlags()----
//Note: This function calls setParent() when
//changing the flags for a window, causing the
//widget to be hidden. You must call show()
//to make the widget visible again..
bool visible = mWidget->isVisible();
mWidget->setMouseTracking( true );
//mWidget->setWindowFlags( Qt::CustomizeWindowHint|Qt::FramelessWindowHint );
mWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint );
//Bug fix, mouse move events does not propagate from child widgets.
//so need the hover events.
mWidget->setAttribute( Qt::WA_Hover );
updateRubberBandStatus();
mWidget->setVisible( visible );
}
NcWidgetData::~NcWidgetData()
{
//---from Qt docs of setWindowFlags()----
//Note: This function calls setParent() when
//changing the flags for a window, causing the
//widget to be hidden. You must call show()
//to make the widget visible again..
bool visible = mWidget->isVisible();
mWidget->setMouseTracking( false );
mWidget->setWindowFlags( mWindowFlags );//^ Qt::CustomizeWindowHint ^ Qt::FramelessWindowHint );
mWidget->setAttribute( Qt::WA_Hover, false );
mWidget->setVisible( visible );
delete mRubberBand;
}
void NcWidgetData::updateRubberBandStatus()
{
if ( d->mUseRubberBandOnMove || d->mUseRubberBandOnResize )
{
if ( !mRubberBand )
mRubberBand = new QRubberBand( QRubberBand::Rectangle );
}
else
{
delete mRubberBand;
mRubberBand = 0;
}
}
QWidget* NcWidgetData::widget()
{
return mWidget;
}
void NcWidgetData::handleWidgetEvent( QEvent* event )
{
switch ( event->type() )
{
default: //qDebug() << "Event = " << event;
break;
case QEvent::MouseButtonPress:
handleMousePressEvent( static_cast<QMouseEvent*>( event ) );
break;
case QEvent::MouseButtonRelease:
handleMouseReleaseEvent( static_cast<QMouseEvent*>( event ) );
break;
case QEvent::MouseMove:
handleMouseMoveEvent( static_cast<QMouseEvent*>( event ) );
break;
case QEvent::Leave:
handleLeaveEvent( event );
break;
//Bug fix, hover event is necessary coz child widget does not
//propagate mousemove events. so the cursor remains in edge shape
//even in middle of widget.
case QEvent::HoverMove:
handleHoverMoveEvent( static_cast<QHoverEvent*>( event ) );
break;
//case QEvent::Enter:
//qDebug() << "Enter event";//d->handleEnterEvent( event );
//break;
}
}
void NcWidgetData::updateCursorShape( const QPoint& globalMousePos )
{
if ( mWidget->isFullScreen() || mWidget->isMaximized() )
{
if ( mCursorShapeChanged )
mWidget->unsetCursor();
return;
}
mMoveMousePos.recalculate( globalMousePos, mWidget->frameGeometry() );
if( mMoveMousePos.onTopLeftEdge || mMoveMousePos.onBottomRightEdge )
{
mWidget->setCursor( Qt::SizeFDiagCursor );
mCursorShapeChanged = true;
}
else if( mMoveMousePos.onTopRightEdge || mMoveMousePos.onBottomLeftEdge )
{
mWidget->setCursor( Qt::SizeBDiagCursor );
mCursorShapeChanged = true;
}
else if( mMoveMousePos.onLeftEdge || mMoveMousePos.onRightEdge )
{
mWidget->setCursor( Qt::SizeHorCursor );
mCursorShapeChanged = true;
}
else if( mMoveMousePos.onTopEdge || mMoveMousePos.onBottomEdge )
{
mWidget->setCursor( Qt::SizeVerCursor );
mCursorShapeChanged = true;
}
else
{
if ( mCursorShapeChanged )
{
mWidget->unsetCursor();
mCursorShapeChanged = false;
}
}
}
void NcWidgetData::resizeWidget( const QPoint& globalMousePos )
{
QRect origRect;
if ( d->mUseRubberBandOnResize )
origRect = mRubberBand->frameGeometry();
else
origRect = mWidget->frameGeometry();
int left = origRect.left();
int top = origRect.top();
int right = origRect.right();
int bottom = origRect.bottom();
origRect.getCoords( &left, &top, &right, &bottom );
int minWidth = mWidget->minimumWidth();
int minHeight = mWidget->minimumHeight();
if ( mPressedMousePos.onTopLeftEdge )
{
left = globalMousePos.x();
top = globalMousePos.y();
}
else if ( mPressedMousePos.onBottomLeftEdge )
{
left = globalMousePos.x();
bottom = globalMousePos.y();
}
else if ( mPressedMousePos.onTopRightEdge )
{
right = globalMousePos.x();
top = globalMousePos.y();
}
else if ( mPressedMousePos.onBottomRightEdge )
{
right = globalMousePos.x();
bottom = globalMousePos.y();
}
else if ( mPressedMousePos.onLeftEdge )
{
left = globalMousePos.x();
}
else if ( mPressedMousePos.onRightEdge )
{
right = globalMousePos.x();
}
else if ( mPressedMousePos.onTopEdge )
{
top = globalMousePos.y();
}
else if ( mPressedMousePos.onBottomEdge )
{
bottom = globalMousePos.y();
}
QRect newRect( QPoint(left, top), QPoint(right, bottom) );
if ( newRect.isValid() )
{
if ( minWidth > newRect.width() )
{
//determine what has caused the width change.
if( left != origRect.left() )
newRect.setLeft( origRect.left() );
else
newRect.setRight( origRect.right() );
}
if ( minHeight > newRect.height() )
{
//determine what has caused the height change.
if ( top != origRect.top() )
newRect.setTop( origRect.top() );
else
newRect.setBottom( origRect.bottom() );
}
if ( d->mUseRubberBandOnResize )
{
mRubberBand->setGeometry( newRect );
}
else
{
mWidget->setGeometry( newRect );
}
}
else
{
//qDebug() << "Calculated Rect is not valid" << newRect;
}
}
void NcWidgetData::moveWidget( const QPoint &globalMousePos )
{
//鼠标点击在标题栏,按住不放快速拖动,窗口并没有随着鼠标拖动位置的变化而变化,原因是鼠标当前点的位置并没有落在标题栏中
//在标题栏内点击才可以移动
/*const int width = mWidget->width();
QRect rect( 0, 0, width, 28 );
QPoint pt = mWidget->mapFromGlobal( globalMousePos );
if( !rect.contains( pt ) )
return;*/
if ( d->mUseRubberBandOnMove )
{
mRubberBand->move( globalMousePos - mDragPos );
}
else
{
mWidget->move( globalMousePos - mDragPos );
}
}
void NcWidgetData::handleMousePressEvent( QMouseEvent* event )
{
if ( event->button() == Qt::LeftButton )
{
mLeftButtonPressed = true;
QRect frameRect = mWidget->frameGeometry();
mPressedMousePos.recalculate( event->globalPos(), frameRect );
mDragPos = event->globalPos() - frameRect.topLeft();
if ( mPressedMousePos.onEdges )
{
if ( d->mUseRubberBandOnResize && !mWidget->isFullScreen() )
{
mRubberBand->setGeometry( frameRect );
mRubberBand->show();
}
}
else if ( d->mUseRubberBandOnMove && !mWidget->isFullScreen() )
{
mRubberBand->setGeometry( frameRect );
mRubberBand->show();
}
const int width = mWidget->width();
QRect rect( 5, 5, width-10, 50 );
if ( rect.contains(event->pos()) )
{
mTitlePressed = true;
}
}
}
void NcWidgetData::handleMouseReleaseEvent( QMouseEvent* event )
{
if ( event->button() == Qt::LeftButton )
{
mLeftButtonPressed = false;
mTitlePressed = false;
mPressedMousePos.reset();
if ( mRubberBand && mRubberBand->isVisible() )
{
mRubberBand->hide();
mWidget->setGeometry( mRubberBand->geometry() );
}
}
}
void NcWidgetData::handleMouseMoveEvent( QMouseEvent* event )
{
if ( mLeftButtonPressed )
{
if ( d->mWidgetResizable && mPressedMousePos.onEdges )
{
resizeWidget( event->globalPos() );
}
else if ( d->mWidgetMovable && mTitlePressed )
{
moveWidget( event->globalPos() );
}
}
else if ( d->mWidgetResizable )
{
updateCursorShape( event->globalPos() );
}
}
void NcWidgetData::handleLeaveEvent( QEvent* /*event*/ )
{
if ( !mLeftButtonPressed )
mWidget->unsetCursor();
}
void NcWidgetData::handleHoverMoveEvent( QHoverEvent* event )
{
if ( d->mWidgetResizable )
updateCursorShape( mWidget->mapToGlobal( event->pos() ) );
}
NcFramelessHelper::NcFramelessHelper( QObject* parent )
: QObject( parent ),
d( new NcFramelessHelperImpl )
{
d->mWidgetMovable = true;
d->mWidgetResizable = true;
d->mUseRubberBandOnResize = false;
d->mUseRubberBandOnMove = false;
}
NcFramelessHelper::~NcFramelessHelper()
{
QList<QWidget*> keys = d->mHashWidgetData.keys();
int size = keys.size();
for ( int i = 0; i < size; ++i )
{
delete d->mHashWidgetData.take( keys[i] );
}
delete d;
}
bool NcFramelessHelper::eventFilter( QObject *obj, QEvent *event )
{
QEvent::Type type = event->type();
if ( type == QEvent::MouseMove ||
type == QEvent::HoverMove ||
type == QEvent::MouseButtonPress ||
type == QEvent::MouseButtonRelease ||
type == QEvent::Leave
)
{
NcWidgetData* data = d->mHashWidgetData.value( static_cast<QWidget*>(obj) );
if ( data )
{
data->handleWidgetEvent( event );
}
}
return false;
}
void NcFramelessHelper::activateOn( QWidget* topLevelWidget )
{
if ( d->mHashWidgetData.contains( topLevelWidget ) )
return;
NcWidgetData* data = new NcWidgetData( d, topLevelWidget );
d->mHashWidgetData.insert( topLevelWidget, data );
topLevelWidget->installEventFilter( this );
}
void NcFramelessHelper::removeFrom( QWidget* topLevelWidget )
{
NcWidgetData* data = d->mHashWidgetData.take( topLevelWidget );
if ( data )
{
topLevelWidget->removeEventFilter( this );
delete data;
}
}
void NcFramelessHelper::setWidgetMovable( bool movable )
{
d->mWidgetMovable = movable;
}
bool NcFramelessHelper::isWidgetMovable()
{
return d->mWidgetMovable;
}
void NcFramelessHelper::setWidgetResizable( bool resizable )
{
d->mWidgetResizable = resizable;
}
bool NcFramelessHelper::isWidgetResizable()
{
return d->mWidgetResizable;
}
void NcFramelessHelper::useRubberBandOnMove( bool use )
{
d->mUseRubberBandOnMove = use;
QList<NcWidgetData*> list = d->mHashWidgetData.values();
int size = list.size();
for ( int i = 0; i < size; ++i )
list[i]->updateRubberBandStatus();
}
bool NcFramelessHelper::isUsingRubberBandOnMove()
{
return d->mUseRubberBandOnMove;
}
void NcFramelessHelper::useRubberBandOnResize( bool use )
{
d->mUseRubberBandOnResize = use;
QList<NcWidgetData*> list = d->mHashWidgetData.values();
int size = list.size();
for ( int i = 0; i < size; ++i )
list[i]->updateRubberBandStatus();
}
bool NcFramelessHelper::isUsingRubberBandOnResisze()
{
return d->mUseRubberBandOnResize;
}
void NcFramelessHelper::setBorderWidth( int newBorderWidth )
{
//TODO: Make it non-static.
if ( newBorderWidth >= 0 )
NcCursorPosCalculator::mBorderWidth = newBorderWidth;
}
int NcFramelessHelper::borderWidth()
{
return NcCursorPosCalculator::mBorderWidth;
}

View File

@ -0,0 +1,32 @@
#include "pub_widget/PubWidgetInit.h"
#include "pub_utility_api/I18N.h"
#include "pub_utility_api/FileUtil.h"
#include <QString>
#include <QTranslator>
#include <QApplication>
namespace iot_public
{
bool installTranslator(const std::string& pLanguage)
{
bool res = false;
const std::string strLanguage = pLanguage;
std::string strOmFile = iot_public::CFileUtil::getPathOfResFile( "pub_widget/translate/pub_widget_" + strLanguage + ".qm" );
if( !strOmFile.empty() )
{
res = true;
auto *pTrans = new QTranslator;
res = pTrans->load( strOmFile.c_str());
res = QApplication::installTranslator( pTrans );
}
return res;
}
bool installTranslatorFromConfig()
{
const std::string strLanguage = std::move( iot_public::getCurLanguage());
return installTranslator(strLanguage);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
#include "pub_widget/WorkFrame.h"
WorkFrame::WorkFrame(QWidget *parent) : QFrame(parent)
{
}
WorkFrame::~WorkFrame()
{
}

View File

@ -0,0 +1,53 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TEMPLATE = lib
TARGET = pub_widget
DEFINES += PUB_WIDGET_LIBRARY
win32{
QMAKE_CXXFLAGS -= -Zc:strictStrings
}
# Input
HEADERS += \
../../include/public/pub_widget/widget_global.h \
../../include/public/pub_widget/Widgets.h \
../../include/public/pub_widget/NcFramelessHelper.h \
../../include/public/pub_widget/MainTitle.h \
../../include/public/pub_widget/WorkFrame.h \
../../include/public/pub_widget/MenuFrame.h \
../../include/public/pub_widget/MessageBox.h \
../../include/public/pub_widget/AlertMessageBox.h \
../../include/public/pub_widget/FramelessWindow.hpp \
../../include/public/pub_widget/CustomDialogTitle.h \
../../include/public/pub_widget/CustomDialog.h \
../../include/public/pub_widget/CustomMainWindow.h \
../../include/public/pub_widget/PubWidgetInit.h
SOURCES += \
../../public/pub_widget/MainTitle.cpp \
../../public/pub_widget/Widgets.cpp \
../../public/pub_widget/NcFramelessHelper.cpp \
../../public/pub_widget/MenuFrame.cpp \
../../public/pub_widget/WorkFrame.cpp \
../../public/pub_widget/MessageBox.cpp \
../../public/pub_widget/AlertMessageBox.cpp \
../../public/pub_widget/CustomDialog.cpp \
../../public/pub_widget/CustomDialogTitle.cpp \
../../public/pub_widget/CustomMainWindow.cpp \
../../public/pub_widget/PubWidgetInit.cpp
LIBS += -lpub_utility_api
TRANSLATIONS += pub_widget_en.ts \
pub_widget_fr.ts
#-------------------------------------------------------------------
COMMON_PRI=$$PWD/../../common.pri
exists($$COMMON_PRI) {
include($$COMMON_PRI)
}else {
error("FATAL error: can not find common.pri")
}

View File

@ -7,3 +7,6 @@ CONFIG += ordered
SUBDIRS += pub_logger_api \
pub_utility_api \
pub_sysinfo_api \
pub_excel \
pub_widget \