diff --git a/examples/KReportExampleDataSource.h b/examples/KReportExampleDataSource.h index 9c063254..2671cb37 100644 --- a/examples/KReportExampleDataSource.h +++ b/examples/KReportExampleDataSource.h @@ -1,71 +1,72 @@ /* This file is part of the KDE project Copyright (C) 2015 by Adam Pigg (adam@piggz.co.uk) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KREPORTEXAMPLEDATA_H #define KREPORTEXAMPLEDATA_H #include +#include #include #include #include -class KReportExampleDataSource : public KReportDataSource +class KReportExampleDataSource : public KReportDataSource, public KReportScriptSource { public: KReportExampleDataSource(); ~KReportExampleDataSource() override; QVariant value(const QString &field) const override; QVariant value(int) const override; QStringList fieldNames() const override; QStringList fieldKeys() const override; int fieldNumber(const QString &field) const override; qint64 recordCount() const override; qint64 at() const override; bool moveLast() override; bool moveFirst() override; bool movePrevious() override; bool moveNext() override; bool close() override; bool open() override; QStringList scriptList() const override; QString scriptCode(const QString &script) const override; QStringList dataSourceNames() const override; private: struct Data { int id; QString devName; QString project; QString country; QString mobile; float lat; float lon; QString code; bool projectLead; }; QList m_testData; QStringList m_fieldNames; int m_currentRecord; }; #endif // KREPORTEXAMPLEDATA_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90275c56..9d849b03 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,372 +1,373 @@ # Options simple_option(KREPORT_SCRIPTING "Scripting support using JavaScript language" ON) if(KREPORT_SCRIPTING) find_package(Qt5Qml REQUIRED) set(SCRIPTING_LIBS Qt5::Qml) endif() set(kreport_LIB_SRCS common/kreport_debug.cpp common/kreportplugin_debug.cpp common/KReportItemBase.cpp common/KReportAsyncItemBase.cpp common/KReportSectionData.cpp common/KReportLabelSizeInfo.cpp common/KReportDocument.cpp common/KReportDetailSectionData.cpp common/KReportPluginInterface.cpp common/KReportItemLine.cpp common/KReportRenderObjects.cpp common/KReportPluginManager.cpp common/KReportJsonTrader_p.cpp common/KReportPluginMetaData.cpp common/KReportDataSource.cpp common/KReportUtils.cpp common/KReportPageSize.cpp common/KReportUnit.cpp common/KReportDesign.cpp common/KReportDesign_p.cpp common/KReportLineStyle.cpp common/KReportElement.cpp ${PROJECT_BINARY_DIR}/src/KReportElement_sdc.cpp common/KReportSection.cpp renderer/KReportPrintRenderer_p.cpp renderer/KReportPreRenderer.cpp renderer/KReportAsyncItemManager_p.cpp renderer/KReportScreenRenderer_p.cpp renderer/KReportHTMLTableRenderer_p.cpp renderer/KReportHTMLCSSRenderer_p.cpp #TODO renderer/KReportKSpreadRenderer.cpp #TODO renderer/KReportODTRenderer.cpp #TODO renderer/KOdtFrameReportRenderer.cpp renderer/KReportRendererBase.cpp renderer/KReportPage.cpp renderer/KReportView.cpp renderer/KReportOneRecordDataSource_p.cpp wrtembed/KReportDetailGroupSectionDialog.cpp wrtembed/KReportDesignerItemBase.cpp wrtembed/KReportDesignerItemRectBase.cpp wrtembed/KReportDesignerItemLine.cpp wrtembed/KReportDesignerSection.cpp wrtembed/KReportDesignerSectionDetailGroup.cpp wrtembed/KReportDesignerSectionDetail.cpp wrtembed/KReportDesignerSectionScene.cpp wrtembed/KReportDesignerSectionView.cpp wrtembed/KReportDesigner.cpp wrtembed/KReportPropertiesButton.cpp wrtembed/KReportSectionEditor.cpp wrtembed/KReportRuler_p.cpp wrtembed/KReportZoomHandler_p.cpp wrtembed/KReportZoomMode_p.cpp items/label/KReportItemLabel.cpp items/label/KReportDesignerItemLabel.cpp items/label/KReportLabelPlugin.cpp items/label/KReportBoundedTextItem.cpp items/label/KReportLabelElement.cpp items/label/label.json items/check/KReportItemCheck.cpp items/check/KReportDesignerItemCheckBox.cpp items/check/KReportCheckBoxPlugin.cpp items/check/check.json items/field/KReportItemField.cpp items/field/KReportDesignerItemField.cpp items/field/KReportFieldPlugin.cpp items/field/field.json items/image/KReportItemImage.cpp items/image/KReportDesignerItemImage.cpp items/image/KReportImagePlugin.cpp items/image/image.json items/text/KReportItemText.cpp items/text/KReportDesignerItemText.cpp items/text/KReportTextPlugin.cpp items/text/text.json # non-source: Mainpage.dox Messages.sh ) - + set(kreport_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/common ${CMAKE_CURRENT_SOURCE_DIR}/wrtembed ${CMAKE_CURRENT_SOURCE_DIR}/renderer ) set(kreport_TARGET_INCLUDE_DIRS common renderer wrtembed ) if(KREPORT_SCRIPTING) list(APPEND kreport_LIB_SRCS renderer/scripting/KReportScriptHandler.cpp renderer/scripting/KReportScriptConstants.cpp renderer/scripting/KReportScriptDebug.cpp renderer/scripting/KReportScriptDraw.cpp renderer/scripting/KReportScriptReport.cpp renderer/scripting/KReportScriptSection.cpp renderer/scripting/KReportScriptLine.cpp #renderer/odtframe/KoOdtFrameReportDocument.cpp #renderer/odtframe/KoOdtFrameReportCheckBox.cpp #renderer/odtframe/KoOdtFrameReportImage.cpp #renderer/odtframe/KoOdtFrameReportTextBox.cpp #renderer/odtframe/KoOdtFrameReportLine.cpp #renderer/odtframe/KoOdtFrameReportPicture.cpp #renderer/odtframe/KoOdtFrameReportPrimitive.cpp #renderer/ods/KoSimpleOdsDocument.cpp #renderer/ods/KoSimpleOdsSheet.cpp #renderer/ods/KoSimpleOdsCell.cpp items/label/KReportScriptLabel.cpp items/check/KReportScriptCheck.cpp items/field/KReportScriptField.cpp items/image/KReportScriptImage.cpp items/text/KReportScriptText.cpp ) qt_wrap_cpp(KReport kreport_LIB_SRCS renderer/scripting/KReportGroupTracker.h ) list(APPEND kreport_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/renderer/scripting ) list(APPEND kreport_TARGET_INCLUDE_DIRS renderer/scripting ) endif() qt5_wrap_ui(kreport_LIB_SRCS wrtembed/KReportDetailGroupSectionDialog.ui wrtembed/KReportSectionEditor.ui ) ecm_create_qm_loader(kreport_LIB_SRCS kreport_qt) add_library(KReport SHARED ${kreport_LIB_SRCS}) set_coinstallable_lib_version(KReport) add_library(KReportUtilsPrivate STATIC common/KReportUtils_p.cpp ) - + kdb_create_shared_data_classes( kreport_GENERATED_SHARED_DATA_CLASS_HEADERS # output variable with list of headers NO_PREFIX # subdirectory in which the headers should be generated common/KReportLineStyle.shared.h common/KReportElement.shared.h common/KReportSection.shared.h items/label/KReportLabelElement.shared.h ) kdb_remove_extensions( kreport_GENERATED_SHARED_DATA_CLASS_BASENAMES ${kreport_GENERATED_SHARED_DATA_CLASS_HEADERS} ) generate_export_header(KReport) #qt5_use_modules(KReport Widgets Xml PrintSupport) target_include_directories(KReport PUBLIC "$" INTERFACE "$" PRIVATE ${kreport_TARGET_INCLUDE_DIRS} ) target_link_libraries(KReport PUBLIC Qt5::PrintSupport Qt5::Xml KF5::CoreAddons KPropertyWidgets PRIVATE ${SCRIPTING_LIBS} KReportUtilsPrivate ) target_link_libraries(KReportUtilsPrivate PUBLIC Qt5::Widgets PRIVATE KF5::WidgetsAddons - KF5::ConfigGui + KF5::ConfigGui ) - + ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX KREPORT VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kreport_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KReportConfigVersion.cmake" ) install(TARGETS KReport EXPORT KReportTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) # Create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/${KREPORT_BASE_NAME}") # A place for KReport plugins set(KREPORT_PLUGIN_INSTALL_DIR ${PLUGIN_INSTALL_DIR}/kreport${PROJECT_STABLE_VERSION_MAJOR}) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KReportConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KReportConfig.cmake" INSTALL_DESTINATION "${CMAKECONFIG_INSTALL_DIR}" ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KReportConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KReportConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel) install(EXPORT KReportTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KReportTargets.cmake) ecm_generate_pri_file( BASE_NAME ${KREPORT_BASE_NAME} LIB_NAME ${KREPORT_BASE_NAME} DEPS "widgets" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KREPORT_INCLUDE_INSTALL_DIR} ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) install(FILES kreport_elementplugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) ecm_generate_headers(kreport_FORWARDING_HEADERS REQUIRED_HEADERS kreport_HEADERS ORIGINAL CAMELCASE RELATIVE common HEADER_NAMES KReportPageSize KReportDataSource + KReportScriptSource KReportItemBase KReportItemLine KReportPluginMetaData KReportPluginManager KReportPluginInterface KReportUnit KReportUtils KReportDesign KReportDocument KReportSectionData KReportRenderObjects KReportAsyncItemBase ) ecm_generate_headers(kreport_FORWARDING_HEADERS REQUIRED_HEADERS kreport_HEADERS ORIGINAL CAMELCASE RELATIVE renderer HEADER_NAMES KReportPage KReportRendererBase KReportPreRenderer KReportView ) if(KREPORT_SCRIPTING) ecm_generate_headers(kreport_FORWARDING_HEADERS REQUIRED_HEADERS kreport_HEADERS ORIGINAL CAMELCASE RELATIVE renderer/scripting HEADER_NAMES KReportScriptHandler KReportScriptDraw KReportScriptConstants KReportGroupTracker ) endif() ecm_generate_headers(kreport_FORWARDING_HEADERS REQUIRED_HEADERS kreport_HEADERS ORIGINAL CAMELCASE RELATIVE wrtembed HEADER_NAMES KReportDesignerSectionDetail KReportDesignerSection KReportDesignerItemBase KReportDesignerSectionDetailGroup KReportDesignerItemRectBase KReportDesigner ) ecm_generate_headers(kreport_FORWARDING_HEADERS_FROM_BUILDDIR REQUIRED_HEADERS kreport_HEADERS_FROM_BUILDDIR ORIGINAL CAMELCASE SOURCE_DIR ${PROJECT_BINARY_DIR}/src HEADER_NAMES ${kreport_GENERATED_SHARED_DATA_CLASS_BASENAMES} ) list(APPEND kreport_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/kreport_version.h) install( FILES ${kreport_HEADERS} ${kreport_HEADERS_FROM_BUILDDIR} ${kreport_FORWARDING_HEADERS} ${kreport_FORWARDING_HEADERS_FROM_BUILDDIR} ${PROJECT_BINARY_DIR}/src/kreport_export.h ${PROJECT_BINARY_DIR}/src/config-kreport.h DESTINATION ${KREPORT_INCLUDE_INSTALL_DIR} COMPONENT Devel ) if(BUILD_QCH) kreport_add_qch( KReport_QCH NAME KReport BASE_NAME ${KREPORT_BASE_NAME} VERSION ${PROJECT_VERSION} NAMESPACE org.kde.${KREPORT_BASE_NAME} SOURCES Mainpage.dox ${kreport_HEADERS} ${kreport_HEADERS_FROM_BUILDDIR} LINK_QCHS Qt5Core_QCH Qt5Xml_QCH Qt5Gui_QCH Qt5Widgets_QCH Qt5PrintSupport_QCH KF5CoreAddons_QCH KPropertyCore_QCH KPropertyWidgets_QCH BLANK_MACROS KREPORT_EXPORT KREPORT_DEPRECATED TAGFILE_INSTALL_DESTINATION ${KREPORT_QTQCH_FULL_INSTALL_DIR} QCH_INSTALL_DESTINATION ${KREPORT_QTQCH_FULL_INSTALL_DIR} ) set(kreport_qch_targets KReport_QCH) endif() kreport_install_qch_export( TARGETS ${kreport_qch_targets} FILE KReportQCHTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) add_subdirectory(plugins) add_subdirectory(pics) enable_testing() configure_file(config-kreport.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kreport.h) diff --git a/src/common/KReportDataSource.cpp b/src/common/KReportDataSource.cpp index ab5e1cad..9e4f8295 100644 --- a/src/common/KReportDataSource.cpp +++ b/src/common/KReportDataSource.cpp @@ -1,163 +1,150 @@ /* This file is part of the KDE project * Copyright (C) 2007-2010 by Adam Pigg (adam@piggz.co.uk) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "KReportDataSource.h" #include #define KReportDataSortedFieldPrivateArgs(o) std::tie(o.field, o.order) -class KReportDataSource::SortedField::Private +class KReportDataSource::SortedField::Private { - + public: Private() {} Private(const Private& other) { KReportDataSortedFieldPrivateArgs((*this)) = KReportDataSortedFieldPrivateArgs(other); } QString field; Qt::SortOrder order = Qt::AscendingOrder; }; class KReportDataSource::Private { public: bool dummy = true; }; //==========KReportData::SortedField========== KReportDataSource::SortedField::SortedField() : d(new Private) { } KReportDataSource::SortedField::SortedField(const KReportDataSource::SortedField& other) : d(new Private(*other.d)) { } KReportDataSource::SortedField::~SortedField() { delete d; } KReportDataSource::SortedField & KReportDataSource::SortedField::operator=(const KReportDataSource::SortedField& other) { if (this != &other) { setField(other.field()); setOrder(other.order()); } return *this; } bool KReportDataSource::SortedField::operator==(const KReportDataSource::SortedField& other) const { return KReportDataSortedFieldPrivateArgs((*d)) == KReportDataSortedFieldPrivateArgs((*other.d)); } bool KReportDataSource::SortedField::operator!=(const KReportDataSource::SortedField& other) const { return KReportDataSortedFieldPrivateArgs((*d)) != KReportDataSortedFieldPrivateArgs((*other.d)); } QString KReportDataSource::SortedField::field() const { return d->field; } Qt::SortOrder KReportDataSource::SortedField::order() const { return d->order; } void KReportDataSource::SortedField::setField(const QString& field) { d->field = field; } void KReportDataSource::SortedField::setOrder(Qt::SortOrder order) { d->order = order; } //==========KReportData========== KReportDataSource::KReportDataSource() : d(new Private()) { } KReportDataSource::~KReportDataSource() { delete d; } QStringList KReportDataSource::fieldKeys() const { return fieldNames(); } QString KReportDataSource::sourceName() const { return QString(); } QString KReportDataSource::sourceClass() const { return QString(); } void KReportDataSource::setSorting(const QList &sorting) { Q_UNUSED(sorting); } void KReportDataSource::addCondition(const QString &field, const QVariant &value, const QString& relation) { Q_UNUSED(field); Q_UNUSED(value); Q_UNUSED(relation); } -#ifdef KREPORT_SCRIPTING -QStringList KReportDataSource::scriptList() const -{ - return QStringList(); -} - -QString KReportDataSource::scriptCode(const QString &script) const -{ - Q_UNUSED(script); - return QString(); -} -#endif - QStringList KReportDataSource::dataSourceNames() const { return QStringList(); } QString KReportDataSource::dataSourceCaption(const QString &dataSourceName) const { return dataSourceName; } KReportDataSource* KReportDataSource::create(const QString &source) const { Q_UNUSED(source); return nullptr; } diff --git a/src/common/KReportDataSource.h b/src/common/KReportDataSource.h index 8948471f..01504fed 100644 --- a/src/common/KReportDataSource.h +++ b/src/common/KReportDataSource.h @@ -1,141 +1,129 @@ /* This file is part of the KDE project * Copyright (C) 2007-2010 by Adam Pigg (adam@piggz.co.uk) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef KREPORTDATA_H #define KREPORTDATA_H #include #include #include "kreport_export.h" #include "config-kreport.h" /** @brief Abstraction of report data source */ class KREPORT_EXPORT KReportDataSource { public: KReportDataSource(); virtual ~KReportDataSource(); //! Describes sorting for single field /*! By default the order is ascending. */ class KREPORT_EXPORT SortedField { public: SortedField(); SortedField(const SortedField& other); ~SortedField(); SortedField& operator=(const SortedField &other); bool operator==(const SortedField &other) const; bool operator!=(const SortedField &other) const; void setField(const QString &field); void setOrder(Qt::SortOrder order); QString field() const; Qt::SortOrder order() const; - + private: class Private; Private * const d; }; //! Open the dataset virtual bool open() = 0; //! Close the dataset virtual bool close() = 0; //! Move to the next record virtual bool moveNext() = 0; //! Move to the previous record virtual bool movePrevious() = 0; //! Move to the first record virtual bool moveFirst() = 0; //! Move to the last record virtual bool moveLast() = 0; //! Return the current position in the dataset virtual qint64 at() const = 0; //! Return the total number of records virtual qint64 recordCount() const = 0; //! Return the index number of the field given by nane field virtual int fieldNumber(const QString &field) const = 0; //! Return the list of field names virtual QStringList fieldNames() const = 0; //! Return the list of field keys. Returns fieldNames() by default virtual QStringList fieldKeys() const; //! Return the value of the field at the given position for the current record virtual QVariant value(int pos) const = 0; //! Return the value of the field fir the given name for the current record virtual QVariant value(const QString &field) const = 0; //! Return the name of this source virtual QString sourceName() const; //! @return the class name of this source virtual QString sourceClass() const; - + //! Sets the sorting for the data //! Should be called before open() so that the data source can be edited accordingly //! Default impl does nothing virtual void setSorting(const QList &sorting); //! Adds a condition to the data source virtual void addCondition(const QString &field, const QVariant &value, const QString& relation = QLatin1String("=")); - //! Utility Functions - //! @todo These are probably eligable to be moved into a new class - -#ifdef KREPORT_SCRIPTING - //! Allow the reportdata implementation to return a list of possible scripts - virtual QStringList scriptList() const; - - //! Allow the reportdata implementation to return some script code based on a specific script name - //! as set in the report - virtual QString scriptCode(const QString& script) const; -#endif - //! Return a list of data source names available for this data source //! Works after the source is opened virtual QStringList dataSourceNames() const = 0; //! Return data source caption for specified @a dataSourceName //! It is possibly translated. As such it is suitable for use in GUIs. //! Default implementation just returns @a dataSourceName. virtual QString dataSourceCaption(const QString &dataSourceName) const; //! Creates a new instance with data source. Default implementation returns @c nullptr. //! @a source is implementation-specific identifier. //! Owner of the returned pointer is the caller. virtual KReportDataSource* create(const QString &source) const Q_REQUIRED_RESULT; - + private: Q_DISABLE_COPY(KReportDataSource) class Private; Private * const d; }; #endif diff --git a/src/common/KReportScriptSource.h b/src/common/KReportScriptSource.h new file mode 100644 index 00000000..613111f7 --- /dev/null +++ b/src/common/KReportScriptSource.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + * Copyright (C) 2017 by Adam Pigg (adam@piggz.co.uk) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef KREPORTSCRIPTSOURCE_H +#define KREPORTSCRIPTSOURCE_H + +#include +#include + +#include "kreport_export.h" + +/** @brief Abstraction of report script source +*/ +class KREPORT_EXPORT KReportScriptSource +{ +public: + virtual ~KReportScriptSource(); + + //! Allow the implementation to return a list of possible scripts + virtual QStringList scriptList() const = 0; + + //! Allow the implementation to return some script code based on a specific script name + //! as set in the report + virtual QString scriptCode(const QString& script) const = 0; +}; + +#endif diff --git a/src/renderer/KReportPreRenderer.cpp b/src/renderer/KReportPreRenderer.cpp index f9da9400..442791d5 100644 --- a/src/renderer/KReportPreRenderer.cpp +++ b/src/renderer/KReportPreRenderer.cpp @@ -1,697 +1,705 @@ /* This file is part of the KDE project * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com) * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "KReportPreRenderer.h" #include "KReportPreRenderer_p.h" #include "KReportAsyncItemManager_p.h" #include "KReportOneRecordDataSource_p.h" #include "KReportRenderObjects.h" #include "KReportDataSource.h" #include "KReportItemBase.h" #include "KReportDocument.h" #include "KReportDetailSectionData.h" #include "KReportLabelSizeInfo.h" #include "KReportPageSize.h" #include "KReportUtils_p.h" #ifdef KREPORT_SCRIPTING #include "scripting/KReportScriptHandler.h" #include "scripting/KReportGroupTracker.h" #endif #include #include #include "kreport_debug.h" KReportPreRendererPrivate::KReportPreRendererPrivate(KReportPreRenderer *preRenderer) : m_preRenderer(preRenderer) { m_valid = false; m_document = nullptr; m_reportDocument = nullptr; m_page = nullptr; m_yOffset = 0.0; m_topMargin = m_bottomMargin = 0.0; m_leftMargin = m_rightMargin = 0.0; m_pageCounter = 0; m_maxHeight = m_maxWidth = 0.0; m_oneRecord = new KReportPrivate::OneRecordDataSource(); m_dataSource = nullptr; #ifdef KREPORT_SCRIPTING m_scriptHandler = nullptr; #endif asyncManager = new KReportPrivate::AsyncItemManager(this); connect(asyncManager, SIGNAL(finished()), this, SLOT(asyncItemsFinished())); } KReportPreRendererPrivate::~KReportPreRendererPrivate() { delete m_reportDocument; delete m_document; delete m_oneRecord; m_postProcText.clear(); } void KReportPreRendererPrivate::createNewPage() { //kreportDebug(); if (m_pageCounter > 0) finishCurPage(false); m_pageCounter++; #ifdef KREPORT_SCRIPTING //Update the page count script value m_scriptHandler->setPageNumber(m_pageCounter); m_scriptHandler->newPage(); #endif m_page = new OROPage(nullptr); m_document->addPage(m_page); //! @todo calculate past page bool lastPage = false; m_yOffset = m_topMargin; if (m_pageCounter == 1 && m_reportDocument->m_pageHeaderFirst) renderSection(*(m_reportDocument->m_pageHeaderFirst)); else if (lastPage == true && m_reportDocument->m_pageHeaderLast) renderSection(*(m_reportDocument->m_pageHeaderLast)); else if ((m_pageCounter % 2) == 1 && m_reportDocument->m_pageHeaderOdd) renderSection(*(m_reportDocument->m_pageHeaderOdd)); else if ((m_pageCounter % 2) == 0 && m_reportDocument->m_pageHeaderAny) renderSection(*(m_reportDocument->m_pageHeaderAny)); else if (m_reportDocument->m_pageHeaderAny) renderSection(*(m_reportDocument->m_pageHeaderAny)); } qreal KReportPreRendererPrivate::finishCurPageSize(bool lastPage) { qreal retval = 0.0; if (lastPage && m_reportDocument->m_pageFooterLast) retval = renderSectionSize(* (m_reportDocument->m_pageFooterLast)); else if (m_pageCounter == 1 && m_reportDocument->m_pageFooterFirst) retval = renderSectionSize(* (m_reportDocument->m_pageFooterFirst)); else if ((m_pageCounter % 2) == 1 && m_reportDocument->m_pageFooterOdd) retval = renderSectionSize(* (m_reportDocument->m_pageFooterOdd)); else if ((m_pageCounter % 2) == 0 && m_reportDocument->m_pageFooterEven) retval = renderSectionSize(* (m_reportDocument->m_pageFooterEven)); else if (m_reportDocument->m_pageFooterAny) retval = renderSectionSize(* (m_reportDocument->m_pageFooterAny)); //kreportDebug() << retval; return retval; } qreal KReportPreRendererPrivate::finishCurPage(bool lastPage) { qreal offset = m_maxHeight - m_bottomMargin; qreal retval = 0.0; //kreportDebug() << offset; if (lastPage && m_reportDocument->m_pageFooterLast) { //kreportDebug() << "Last Footer"; m_yOffset = offset - renderSectionSize(* (m_reportDocument->m_pageFooterLast)); retval = renderSection(* (m_reportDocument->m_pageFooterLast)); } else if (m_pageCounter == 1 && m_reportDocument->m_pageFooterFirst) { //kreportDebug() << "First Footer"; m_yOffset = offset - renderSectionSize(* (m_reportDocument->m_pageFooterFirst)); retval = renderSection(* (m_reportDocument->m_pageFooterFirst)); } else if ((m_pageCounter % 2) == 1 && m_reportDocument->m_pageFooterOdd) { //kreportDebug() << "Odd Footer"; m_yOffset = offset - renderSectionSize(* (m_reportDocument->m_pageFooterOdd)); retval = renderSection(* (m_reportDocument->m_pageFooterOdd)); } else if ((m_pageCounter % 2) == 0 && m_reportDocument->m_pageFooterEven) { //kreportDebug() << "Even Footer"; m_yOffset = offset - renderSectionSize(* (m_reportDocument->m_pageFooterEven)); retval = renderSection(* (m_reportDocument->m_pageFooterEven)); } else if (m_reportDocument->m_pageFooterAny) { //kreportDebug() << "Any Footer"; m_yOffset = offset - renderSectionSize(* (m_reportDocument->m_pageFooterAny)); retval = renderSection(* (m_reportDocument->m_pageFooterAny)); } return retval; } void KReportPreRendererPrivate::renderDetailSection(KReportDetailSectionData *detailData) { if (detailData->m_detailSection) { if (m_dataSource/* && !curs->eof()*/) { QStringList keys; QStringList keyValues; QList shownGroups; KReportDetailGroupSectionData * grp = nullptr; bool status = m_dataSource->moveFirst(); int recordCount = m_dataSource->recordCount(); //kreportDebug() << "Record Count:" << recordCount; for (int i = 0; i < (int) detailData->m_groupList.count(); ++i) { grp = detailData->m_groupList[i]; //If the group has a header or footer, then emit a change of group value if(grp->m_groupFooter || grp->m_groupHeader) { // we get here only if group is *shown* shownGroups << i; keys.append(grp->m_column); if (!keys.last().isEmpty()) keyValues.append(m_dataSource->value(m_dataSource->fieldNumber(keys.last())).toString()); else keyValues.append(QString()); //Tell interested parties we're about to render a header emit(enteredGroup(keys.last(), keyValues.last())); } if (grp->m_groupHeader) renderSection(*(grp->m_groupHeader)); } while (status) { const qint64 pos = m_dataSource->at(); //kreportDebug() << "At:" << l << "Y:" << m_yOffset << "Max Height:" << m_maxHeight; if ((renderSectionSize(*detailData->m_detailSection) + finishCurPageSize((pos + 1 == recordCount)) + m_bottomMargin + m_yOffset) >= m_maxHeight) { //kreportDebug() << "Next section is too big for this page"; if (pos > 0) { m_dataSource->movePrevious(); createNewPage(); m_dataSource->moveNext(); } } renderSection(*(detailData->m_detailSection)); if (m_dataSource) status = m_dataSource->moveNext(); if (status == true && keys.count() > 0) { // check to see where it is we need to start int pos = -1; // if it's still -1 by the time we are done then no keyValues changed for (int i = 0; i < keys.count(); ++i) { if (keyValues[i] != m_dataSource->value(m_dataSource->fieldNumber(keys[i])).toString()) { pos = i; break; } } // don't bother if nothing has changed if (pos != -1) { // roll back the query and go ahead if all is good status = m_dataSource->movePrevious(); if (status == true) { // print the footers as needed // any changes made in this for loop need to be duplicated // below where the footers are finished. bool do_break = false; for (int i = shownGroups.count() - 1; i >= 0; i--) { if (do_break) createNewPage(); do_break = false; grp = detailData->m_groupList[shownGroups.at(i)]; if (grp->m_groupFooter) { if (renderSectionSize(*(grp->m_groupFooter)) + finishCurPageSize(false) + m_bottomMargin + m_yOffset >= m_maxHeight) createNewPage(); renderSection(*(grp->m_groupFooter)); } if (KReportDetailGroupSectionData::BreakAfterGroupFooter == grp->m_pagebreak) do_break = true; } // step ahead to where we should be and print the needed headers // if all is good status = m_dataSource->moveNext(); if (do_break) createNewPage(); if (status == true) { for (int i = 0; i < shownGroups.count(); ++i) { grp = detailData->m_groupList[shownGroups.at(i)]; if (grp->m_groupHeader) { if (renderSectionSize(*(grp->m_groupHeader)) + finishCurPageSize(false) + m_bottomMargin + m_yOffset >= m_maxHeight) { m_dataSource->movePrevious(); createNewPage(); m_dataSource->moveNext(); } if (!keys[i].isEmpty()) keyValues[i] = m_dataSource->value(m_dataSource->fieldNumber(keys[i])).toString(); //Tell interested parties thak key values changed renderSection(*(grp->m_groupHeader)); } } } } } } } if (keys.size() > 0 && m_dataSource->movePrevious()) { // finish footers // duplicated changes from above here for (int i = shownGroups.count() - 1; i >= 0; i--) { grp = detailData->m_groupList[shownGroups.at(i)]; if (grp->m_groupFooter) { if (renderSectionSize(*(grp->m_groupFooter)) + finishCurPageSize(false) + m_bottomMargin + m_yOffset >= m_maxHeight) createNewPage(); renderSection(*(grp->m_groupFooter)); emit(exitedGroup(keys[i], keyValues[i])); } } } } if (KReportDetailSectionData::BreakAtEnd == detailData->m_pageBreak) createNewPage(); } } qreal KReportPreRendererPrivate::renderSectionSize(const KReportSectionData & sectionData) { qreal intHeight = POINT_TO_INCH(sectionData.height()) * KReportPrivate::dpiX(); int itemHeight = 0; if (sectionData.objects().count() == 0) return intHeight; QList objects = sectionData.objects(); foreach(KReportItemBase *ob, objects) { QPointF offset(m_leftMargin, m_yOffset); QVariant itemData = m_dataSource->value(ob->itemDataSource()); //ASync objects cannot alter the section height KReportAsyncItemBase *async_ob = qobject_cast(ob); if (!async_ob) { itemHeight = ob->renderSimpleData(nullptr, nullptr, offset, itemData, m_scriptHandler); if (itemHeight > intHeight) { intHeight = itemHeight; } } } return intHeight; } qreal KReportPreRendererPrivate::renderSection(const KReportSectionData & sectionData) { qreal sectionHeight = POINT_TO_INCH(sectionData.height()) * KReportPrivate::dpiX(); int itemHeight = 0; //kreportDebug() << "Name: " << sectionData.name() << " Height: " << sectionHeight // << "Objects: " << sectionData.objects().count(); emit(renderingSection(const_cast(§ionData), m_page, QPointF(m_leftMargin, m_yOffset))); //Create a pre-rendered section for this section and add it to the document OROSection *sec = new OROSection(m_document); sec->setHeight(sectionData.height()); sec->setBackgroundColor(sectionData.backgroundColor()); sec->setType(sectionData.type()); m_document->addSection(sec); //Render section background ORORect* bg = new ORORect(); bg->setPen(QPen(Qt::NoPen)); bg->setBrush(sectionData.backgroundColor()); qreal w = m_page->document()->pageLayout().fullRectPixels(KReportPrivate::dpiX()).width() - m_page->document()->pageLayout().marginsPixels(KReportPrivate::dpiX()).right() - m_leftMargin; bg->setRect(QRectF(m_leftMargin, m_yOffset, w, sectionHeight)); m_page->insertPrimitive(bg, true); QList objects = sectionData.objects(); foreach(KReportItemBase *ob, objects) { QPointF offset(m_leftMargin, m_yOffset); QVariant itemData = m_dataSource->value(ob->itemDataSource()); if (ob->supportsSubQuery()) { itemHeight = ob->renderReportData(m_page, sec, offset, m_dataSource, m_scriptHandler); } else { KReportAsyncItemBase *async_ob = qobject_cast(ob); if (async_ob){ //kreportDebug() << "async object"; asyncManager->addItem(async_ob, m_page, sec, offset, async_ob->realItemData(itemData), m_scriptHandler); } else { //kreportDebug() << "sync object"; itemHeight = ob->renderSimpleData(m_page, sec, offset, itemData, m_scriptHandler); } } if (itemHeight > sectionHeight) { sectionHeight = itemHeight; } } for (int i = 0; i < m_page->primitiveCount(); ++i) { OROPrimitive *prim = m_page->primitive(i); if (OROTextBox *text = dynamic_cast(prim)) { if (text->requiresPostProcessing()) { m_postProcText.append(text); } } } m_yOffset += sectionHeight; return sectionHeight; } #ifdef KREPORT_SCRIPTING void KReportPreRendererPrivate::initEngine() { delete m_scriptHandler; - m_scriptHandler = new KReportScriptHandler(m_dataSource, m_reportDocument); + m_scriptHandler = new KReportScriptHandler(m_dataSource, scriptSource, m_reportDocument); connect(this, SIGNAL(enteredGroup(QString,QVariant)), m_scriptHandler, SLOT(slotEnteredGroup(QString,QVariant))); connect(this, SIGNAL(exitedGroup(QString,QVariant)), m_scriptHandler, SLOT(slotExitedGroup(QString,QVariant))); connect(this, SIGNAL(renderingSection(KReportSectionData*,OROPage*,QPointF)), m_scriptHandler, SLOT(slotEnteredSection(KReportSectionData*,OROPage*,QPointF))); } #endif void KReportPreRendererPrivate::asyncItemsFinished() { //kreportDebug() << "Finished rendering async items"; asyncManager->deleteLater(); emit finishedAllASyncItems(); } bool KReportPreRendererPrivate::generateDocument() { if (!m_dataSource) { m_dataSource = m_oneRecord; } if (!m_valid || !m_reportDocument) { return false; } // Do this check now so we don't have to undo a lot of work later if it fails KReportLabelSizeInfo label; if (m_reportDocument->pageSize() == QLatin1String("Labels")) { label = KReportLabelSizeInfo::find(m_reportDocument->labelType()); if (label.isNull()) { return false; } } //kreportDebug() << "Creating Document"; m_document = new ORODocument(m_reportDocument->title()); m_pageCounter = 0; m_yOffset = 0.0; //kreportDebug() << "Calculating Margins"; if (!label.isNull()) { if (m_reportDocument->pageLayout().orientation() == QPageLayout::Portrait) { m_topMargin = (label.startY() / 100.0); m_bottomMargin = 0; m_rightMargin = 0; m_leftMargin = (label.startX() / 100.0); } else { m_topMargin = (label.startX() / 100.0); m_bottomMargin = 0; m_rightMargin = 0; m_leftMargin = (label.startY() / 100.0); } } else { m_topMargin = m_reportDocument->pageLayout().marginsPoints().top(); m_bottomMargin = m_reportDocument->pageLayout().marginsPoints().bottom(); m_rightMargin = m_reportDocument->pageLayout().marginsPoints().right(); m_leftMargin = m_reportDocument->pageLayout().marginsPoints().left(); //kreportDebug() << "Margins:" << m_topMargin << m_bottomMargin << m_rightMargin << m_leftMargin; } //kreportDebug() << "Calculating Page Size"; QPageLayout layout = m_reportDocument->pageLayout(); // This should reflect the information of the report page size if (m_reportDocument->pageSize() == QLatin1String("Custom")) { m_maxWidth = m_reportDocument->pageLayout().fullRectPoints().width(); m_maxHeight = m_reportDocument->pageLayout().fullRectPoints().height(); } else { if (!label.isNull()) { m_maxWidth = label.width(); m_maxHeight = label.height(); m_reportDocument->pageLayout().setPageSize(QPageSize(KReportPageSize::pageSize(label.paper()))); } else { // lookup the correct size information for the specified size paper QSizeF pageSizePx = m_reportDocument->pageLayout().fullRectPixels(KReportPrivate::dpiX()).size(); m_maxWidth = pageSizePx.width(); m_maxHeight = pageSizePx.height(); } } if (m_reportDocument->pageLayout().orientation() == QPageLayout::Landscape) { qreal tmp = m_maxWidth; m_maxWidth = m_maxHeight; m_maxHeight = tmp; } //kreportDebug() << "Page Size:" << m_maxWidth << m_maxHeight; m_document->setPageLayout(m_reportDocument->pageLayout()); m_dataSource->setSorting(m_reportDocument->m_detailSection->m_sortedFields); if (!m_dataSource->open()) { return false; } #ifdef KREPORT_SCRIPTING initEngine(); connect(m_scriptHandler, SIGNAL(groupChanged(QMap)), m_preRenderer, SIGNAL(groupChanged(QMap))); //Loop through all abjects that have been registered, and register them with the script handler if (m_scriptHandler) { QMapIterator i(m_scriptObjects); while (i.hasNext()) { i.next(); m_scriptHandler->registerScriptObject(i.value(), i.key()); } //execute the script, if it fails, abort and return the empty document if (!m_scriptHandler->trigger()) { m_scriptHandler->displayErrors(); return m_document; } } #endif createNewPage(); if (!label.isNull()) { // Label Print Run // remember the initial margin setting as we will be modifying // the value and restoring it as we move around qreal margin = m_leftMargin; m_yOffset = m_topMargin; qreal w = (label.width() / 100.0); qreal wg = (label.xGap() / 100.0); qreal h = (label.height() / 100.0); qreal hg = (label.yGap() / 100.0); int numCols = label.columns(); int numRows = label.rows(); qreal tmp; // flip the value around if we are printing landscape if (!m_reportDocument->pageLayout().orientation() == QPageLayout::Portrait) { w = (label.height() / 100.0); wg = (label.yGap() / 100.0); h = (label.width() / 100.0); hg = (label.xGap() / 100.0); numCols = label.rows(); numRows = label.columns(); } KReportDetailSectionData * detailData = m_reportDocument->m_detailSection; if (detailData->m_detailSection) { KReportDataSource *mydata = m_dataSource; if (mydata && mydata->recordCount() > 0) { /* && !((query = orqThis->getQuery())->eof()))*/ if (!mydata->moveFirst()) { return false; } int row = 0; int col = 0; do { tmp = m_yOffset; // store the value as renderSection changes it renderSection(*(detailData->m_detailSection)); m_yOffset = tmp; // restore the value that renderSection modified col++; m_leftMargin += w + wg; if (col >= numCols) { m_leftMargin = margin; // reset back to original value col = 0; row++; m_yOffset += h + hg; if (row >= numRows) { m_yOffset = m_topMargin; row = 0; createNewPage(); } } } while (mydata->moveNext()); } } } else { // Normal Print Run if (m_reportDocument->m_reportHeader) { renderSection(*(m_reportDocument->m_reportHeader)); } if (m_reportDocument->m_detailSection) { renderDetailSection(m_reportDocument->m_detailSection); } if (m_reportDocument->m_reportFooter) { if (renderSectionSize(*(m_reportDocument->m_reportFooter)) + finishCurPageSize(true) + m_bottomMargin + m_yOffset >= m_maxHeight) { createNewPage(); } renderSection(*(m_reportDocument->m_reportFooter)); } } finishCurPage(true); #ifdef KREPORT_SCRIPTING // _postProcText contains those text boxes that need to be updated // with information that wasn't available at the time it was added to the document m_scriptHandler->setPageTotal(m_document->pageCount()); for (int i = 0; i < m_postProcText.size(); i++) { OROTextBox * tb = m_postProcText.at(i); m_scriptHandler->setPageNumber(tb->page()->pageNumber() + 1); tb->setText(m_scriptHandler->evaluate(tb->text()).toString()); } #endif asyncManager->startRendering(); #ifdef KREPORT_SCRIPTING m_scriptHandler->displayErrors(); #endif if (!m_dataSource->close()) { return false; } #ifdef KREPORT_SCRIPTING delete m_scriptHandler; m_scriptHandler = nullptr; #endif if (m_dataSource != m_oneRecord) { delete m_dataSource; m_dataSource = nullptr; } m_postProcText.clear(); return true; } //===========================KReportPreRenderer=============================== KReportPreRenderer::KReportPreRenderer(const QDomElement &document) : d(new KReportPreRendererPrivate(this)) { setDocument(document); connect(d, &KReportPreRendererPrivate::finishedAllASyncItems, this, &KReportPreRenderer::finishedAllASyncItems); } KReportPreRenderer::~KReportPreRenderer() { delete d; } void KReportPreRenderer::setName(const QString &n) { d->m_reportDocument->setName(n); } bool KReportPreRenderer::isValid() const { if (d && d->m_valid) return true; return false; } ORODocument* KReportPreRenderer::document() { return d->m_document; } bool KReportPreRenderer::generateDocument() { // delete d->m_document; if (!d->generateDocument()) { delete d->m_document; d->m_document = nullptr; } return d->m_document; } void KReportPreRenderer::setSourceData(KReportDataSource *dataSource) { if (d && dataSource != d->m_dataSource) { delete d->m_dataSource; d->m_dataSource = dataSource; } } +void KReportPreRenderer::setScriptSource(KReportScriptSource *source) +{ + if (d) { + d->scriptSource = source; + } +} + + bool KReportPreRenderer::setDocument(const QDomElement &document) { delete d->m_document; d->m_valid = false; if (document.tagName() != QLatin1String("report:content")) { kreportWarning() << "report schema is invalid"; return false; } d->m_reportDocument = new KReportDocument(document); d->m_valid = d->m_reportDocument->isValid(); return isValid(); } #ifdef KREPORT_SCRIPTING void KReportPreRenderer::registerScriptObject(QObject* obj, const QString& name) { //kreportDebug() << name; d->m_scriptObjects[name] = obj; } KReportScriptHandler *KReportPreRenderer::scriptHandler() { return d->m_scriptHandler; } #endif const KReportDocument* KReportPreRenderer::reportData() const { return d->m_reportDocument; } diff --git a/src/renderer/KReportPreRenderer.h b/src/renderer/KReportPreRenderer.h index 3ec256b3..262175ca 100644 --- a/src/renderer/KReportPreRenderer.h +++ b/src/renderer/KReportPreRenderer.h @@ -1,83 +1,87 @@ /* This file is part of the KDE project * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com) * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef KREPORTPRERENDERER_H #define KREPORTPRERENDERER_H #include "config-kreport.h" #include "kreport_export.h" #include #ifdef KREPORT_SCRIPTING class KReportScriptHandler; +class KReportScriptSource; #else #define KReportScriptHandler void #endif class KReportPreRendererPrivate; class ORODocument; class KReportDataSource; class KReportDocument; class QDomElement; // // ORPreRender // This class takes a report definition and prerenders the result to // an ORODocument that can be used to pass to any number of renderers. // class KREPORT_EXPORT KReportPreRenderer : public QObject { Q_OBJECT public: explicit KReportPreRenderer(const QDomElement& document); ~KReportPreRenderer() override; //! Sets source data to @a data, takes ownership void setSourceData(KReportDataSource* dataSource); + //!Sets the script source to @a source, does NOT take ownership as it may be an application window + void setScriptSource(KReportScriptSource* source); + #ifdef KREPORT_SCRIPTING KReportScriptHandler *scriptHandler(); void registerScriptObject(QObject *obj, const QString &name); #endif bool generateDocument(); ORODocument *document(); /** @brief Set the name of the report so that it can be used internally by the script engine */ void setName(const QString &); bool isValid() const; const KReportDocument *reportData() const; Q_SIGNALS: void groupChanged(const QMap &groupData); void finishedAllASyncItems(); - + private: bool setDocument(const QDomElement &document); private: KReportPreRendererPrivate *const d; }; #endif // KREPORTPRERENDERER_H diff --git a/src/renderer/KReportPreRenderer_p.h b/src/renderer/KReportPreRenderer_p.h index b39168ef..f616fee1 100644 --- a/src/renderer/KReportPreRenderer_p.h +++ b/src/renderer/KReportPreRenderer_p.h @@ -1,101 +1,106 @@ /* This file is part of the KDE project * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com) * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef KREPORTPRERENDERER_P_H #define KREPORTPRERENDERER_P_H #include "config-kreport.h" #include "KReportRenderObjects.h" #include "KReportAsyncItemManager_p.h" #include "KReportDetailSectionData.h" #include +#ifdef KREPORT_SCRIPTING +#include +#endif + namespace KReportPrivate{ class OneRecordDataSource; } class KReportPreRenderer; /*! This class is the private class that houses all the internal variables so we can provide a cleaner interface to the user without presenting to them things that they don't need to see and may change over time. */ class KReportPreRendererPrivate : public QObject { Q_OBJECT public: KReportPreRendererPrivate(KReportPreRenderer *preRenderer); ~KReportPreRendererPrivate() override; KReportPreRenderer * const m_preRenderer; bool m_valid; ORODocument* m_document; OROPage* m_page; KReportDocument* m_reportDocument; qreal m_yOffset; // how far down the current page are we qreal m_topMargin; // value stored in the correct units qreal m_bottomMargin; // -- same as above -- qreal m_leftMargin; // -- same as above -- qreal m_rightMargin; // -- same as above -- qreal m_maxHeight; // -- same as above -- qreal m_maxWidth; // -- same as above -- int m_pageCounter; // what page are we currently on? KReportDataSource* m_dataSource; KReportPrivate::OneRecordDataSource *m_oneRecord; QList m_postProcText; #ifdef KREPORT_SCRIPTING QMap m_scriptObjects; + KReportScriptSource *scriptSource = nullptr; #endif void createNewPage(); qreal finishCurPage(bool lastPage); qreal finishCurPageSize(bool lastPage); void renderDetailSection(KReportDetailSectionData *detailData); qreal renderSection(const KReportSectionData &); qreal renderSectionSize(const KReportSectionData &); ///Scripting Stuff KReportScriptHandler *m_scriptHandler; #ifdef KREPORT_SCRIPTING void initEngine(); #endif //! Generates m_document. Returns true on success. //! @note m_document is not removed on failure, caller should remove it. bool generateDocument(); KReportPrivate::AsyncItemManager* asyncManager; private Q_SLOTS: void asyncItemsFinished(); Q_SIGNALS: void enteredGroup(const QString&, const QVariant&); void exitedGroup(const QString&, const QVariant&); void renderingSection(KReportSectionData*, OROPage*, QPointF); void finishedAllASyncItems(); }; #endif // __KOREPORTPRERENDERER_P_H__ diff --git a/src/renderer/scripting/KReportScriptHandler.cpp b/src/renderer/scripting/KReportScriptHandler.cpp index b7493fd7..0d113e96 100644 --- a/src/renderer/scripting/KReportScriptHandler.cpp +++ b/src/renderer/scripting/KReportScriptHandler.cpp @@ -1,202 +1,223 @@ /* This file is part of the KDE project * Copyright (C) 2007-2008 by Adam Pigg * Copyright (C) 2012 Jarosław Staniek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "KReportScriptHandler.h" +#include "KReportDataSource.h" +#include "KReportScriptSource.h" #include "KReportScriptSection.h" #include "KReportScriptDebug.h" #include "KReportScriptReport.h" #include "KReportScriptDraw.h" #include "KReportScriptConstants.h" #include "KReportSectionData.h" #include "KReportItemBase.h" #include "KReportDocument.h" #include "KReportDetailSectionData.h" #include "KReportRenderObjects.h" #include "kreport_debug.h" #include #include #include + +//Note#: this is here to save creating a new file for this interface +KReportScriptSource::~KReportScriptSource() +{ +} + class Q_DECL_HIDDEN KReportScriptHandler::Private { public: Private(); ~Private(); KReportScriptConstants *constants; KReportScriptDebug *debug; KReportScriptDraw *draw; Scripting::Report *report; const KReportDataSource *reportDataSource; + const KReportScriptSource *scriptSource; QString source; KReportDocument *reportDocument; QJSEngine engine; QJSValue scriptValue; QMap groups; QMap sectionMap; + bool suppressEvaluateErrors = false; }; KReportScriptHandler::Private::Private() : constants(new KReportScriptConstants), debug(new KReportScriptDebug), draw(new KReportScriptDraw) { } KReportScriptHandler::Private::~Private() { } -KReportScriptHandler::KReportScriptHandler(const KReportDataSource* reportDataSource, KReportDocument* reportDocument) : d(new Private()) +KReportScriptHandler::KReportScriptHandler(const KReportDataSource* reportDataSource, KReportScriptSource* scriptSource, KReportDocument* reportDocument) : d(new Private()) { d->reportDocument = reportDocument; d->reportDataSource = reportDataSource; + d->scriptSource = scriptSource; //Add a general report object d->report = new Scripting::Report(d->reportDocument); - + registerScriptObject(d->constants, QLatin1String("constants")); registerScriptObject(d->debug, QLatin1String("debug")); registerScriptObject(d->draw, QLatin1String("draw")); QJSValue r = registerScriptObject(d->report, d->reportDocument->name()); //Add the sections QList secs = d->reportDocument->sections(); foreach(KReportSectionData *sec, secs) { d->sectionMap[sec] = new Scripting::Section(sec); d->sectionMap[sec]->setParent(d->report); d->sectionMap[sec]->setObjectName(sec->name().replace(QLatin1Char('-'), QLatin1Char('_')) .remove(QLatin1String("report:"))); QJSValue s = d->engine.newQObject(d->sectionMap[sec]); r.setProperty(d->sectionMap[sec]->objectName(), s); //kreportDebug() << "Added" << d->sectionMap[sec]->objectName() << "to report" << d->reportData->name(); } - - //kreportDebug() << "Report name is" << d->reportData->name(); } bool KReportScriptHandler::trigger() { - QString code = d->reportDataSource->scriptCode(d->reportDocument->script()); - //kreportDebug() << code; + QString code; + if (d->scriptSource) { + code = d->scriptSource->scriptCode(d->reportDocument->script()); + } if (code.isEmpty()) { return true; } d->scriptValue = d->engine.evaluate(code, d->reportDocument->script()); if (d->scriptValue.isError()) { return false; }/*TODO else { kreportDebug() << "Function Names:" << d->engine->functionNames(); }*/ d->report->eventOnOpen(); return true; } KReportScriptHandler::~KReportScriptHandler() { delete d; } void KReportScriptHandler::newPage() { if (d->report) { d->report->eventOnNewPage(); } } void KReportScriptHandler::slotEnteredGroup(const QString &key, const QVariant &value) { //kreportDebug() << key << value; d->groups[key] = value; emit(groupChanged(d->groups)); } void KReportScriptHandler::slotExitedGroup(const QString &key, const QVariant &value) { Q_UNUSED(value); //kreportDebug() << key << value; d->groups.remove(key); emit(groupChanged(d->groups)); } void KReportScriptHandler::slotEnteredSection(KReportSectionData *section, OROPage* cp, QPointF off) { if (cp) d->draw->setPage(cp); d->draw->setOffset(off); Scripting::Section *ss = d->sectionMap[section]; if (ss) { ss->eventOnRender(); } } QVariant KReportScriptHandler::evaluate(const QString &code) { if (!d->scriptValue.isError()) { QJSValue result = d->engine.evaluate(code); if (!result.isError()) { return result.toVariant(); } else { - QMessageBox::warning(nullptr, tr("Script Error"), d->scriptValue.toString()); + if (!d->suppressEvaluateErrors) { + QMessageBox msgBox; + msgBox.setText(tr("Cannot evaluate script. Error: %1\n\nDo you want to suppress further messages?\n(messages will be restored next time the report is opened)").arg(d->scriptValue.toString())); + msgBox.setDetailedText(tr("Script code:\n%1").arg(code)); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) { + d->suppressEvaluateErrors = true; + } + } } } return QVariant(); } void KReportScriptHandler::displayErrors() { if (d->scriptValue.isError()) { QMessageBox::warning(nullptr, tr("Script Error"), d->scriptValue.toString()); } } //! @todo KEXI3 move to kexi #if 0 QString KReportScriptHandler::where() { QString w; QMap::const_iterator i = d->groups.constBegin(); while (i != d->groups.constEnd()) { w += QLatin1Char('(') + i.key() + QLatin1String(" = '") + i.value().toString() + QLatin1String("') AND "); ++i; } w.chop(4); //kreportDebug() << w; return w; } #endif QJSValue KReportScriptHandler::registerScriptObject(QObject* obj, const QString& name) { QJSValue val; val = d->engine.newQObject(obj); d->engine.globalObject().setProperty(name, val); return val; } void KReportScriptHandler::setPageNumber(int p) { d->constants->setPageNumber(p); } void KReportScriptHandler::setPageTotal(int t) { d->constants->setPageTotal(t); } diff --git a/src/renderer/scripting/KReportScriptHandler.h b/src/renderer/scripting/KReportScriptHandler.h index b33efe0f..c6934739 100644 --- a/src/renderer/scripting/KReportScriptHandler.h +++ b/src/renderer/scripting/KReportScriptHandler.h @@ -1,77 +1,78 @@ /* This file is part of the KDE project * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef KRSCRIPTHANDLER_H #define KRSCRIPTHANDLER_H #include "kreport_export.h" #include "config-kreport.h" #ifdef KREPORT_SCRIPTING #include "KReportScriptConstants.h" #include "KReportDataSource.h" #include class KReportScriptDebug; class KReportScriptDraw; class KReportSectionData; class QJSEngine; class KReportDocument; class OROPage; +class KReportScriptSource; namespace Scripting { class Report; class Section; } class KREPORT_EXPORT KReportScriptHandler : public QObject { Q_OBJECT public: - KReportScriptHandler(const KReportDataSource *reportDataSource, KReportDocument* reportDocument); + KReportScriptHandler(const KReportDataSource *reportDataSource, KReportScriptSource *scriptSource, KReportDocument* reportDocument); ~KReportScriptHandler() override; QVariant evaluate(const QString&); void displayErrors(); QJSValue registerScriptObject(QObject*, const QString&); bool trigger(); public Q_SLOTS: void slotEnteredSection(KReportSectionData*, OROPage*, QPointF); void slotEnteredGroup(const QString&, const QVariant&); void slotExitedGroup(const QString&, const QVariant&); void setPageNumber(int p); void setPageTotal(int t); void newPage(); Q_SIGNALS: void groupChanged(const QMap &groupData); private: //! @todo KEXI3 QString where(); Q_DISABLE_COPY(KReportScriptHandler) class Private; Private * const d; }; #else // !KREPORT_SCRIPTING #define KReportScriptHandler void #endif #endif diff --git a/src/wrtembed/KReportDesigner.cpp b/src/wrtembed/KReportDesigner.cpp index f70981ae..16de7785 100644 --- a/src/wrtembed/KReportDesigner.cpp +++ b/src/wrtembed/KReportDesigner.cpp @@ -1,1529 +1,1542 @@ /* This file is part of the KDE project * Copyright (C) 2001-2007 by OpenMFG, LLC * Copyright (C) 2007-2010 by Adam Pigg * Copyright (C) 2011-2017 Jarosław Staniek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "KReportDesigner.h" #include "KReportDesignerSection.h" #include "KReportDesignerSectionScene.h" #include "KReportDesignerSectionView.h" #include "KReportDesignerSectionDetailGroup.h" #include "KReportPropertiesButton.h" #include "KReportSectionEditor.h" #include "KReportDesignerSectionDetail.h" #include "KReportDesignerItemLine.h" #include "KReportRuler_p.h" #include "KReportZoomHandler_p.h" #include "KReportPageSize.h" #include "KReportUtils_p.h" #include "KReportUtils.h" #include "KReportPluginInterface.h" #include "KReportPluginManager.h" #include "KReportSection.h" #include "KReportPluginMetaData.h" #include "kreport_debug.h" +#ifdef KREPORT_SCRIPTING +#include "KReportScriptSource.h" +#endif #include #include #include #include #include #include #include #include #include #include #include #include #include //! Also add public method for runtime? const char ns[] = "http://kexi-project.org/report/2.0"; static QDomElement propertyToElement(QDomDocument* d, KProperty* p) { QDomElement e = d->createElement(QLatin1String("report:" + p->name().toLower())); e.appendChild(d->createTextNode(p->value().toString())); return e; } // // define and implement the ReportWriterSectionData class // a simple class to hold/hide data in the ReportHandler class // class ReportWriterSectionData { public: ReportWriterSectionData() { selected_x_offset = 0; selected_y_offset = 0; mouseAction = ReportWriterSectionData::MA_None; } virtual ~ReportWriterSectionData() { } enum MouseAction { MA_None = 0, MA_Insert = 1, MA_Grab = 2, MA_MoveStartPoint, MA_MoveEndPoint, MA_ResizeNW = 8, MA_ResizeN, MA_ResizeNE, MA_ResizeE, MA_ResizeSE, MA_ResizeS, MA_ResizeSW, MA_ResizeW }; int selected_x_offset; int selected_y_offset; MouseAction mouseAction; QString itemToInsert; QList copy_list; QList cut_list; }; //! @internal class Q_DECL_HIDDEN KReportDesigner::Private { public: Private(){} ~Private() { delete dataSource; } QGridLayout *grid; KReportRuler *hruler; KReportZoomHandler zoomHandler; QVBoxLayout *vboxlayout; KReportPropertiesButton *pageButton; QGraphicsScene *activeScene = nullptr; ReportWriterSectionData sectionData; KReportDesignerSection *reportHeader = nullptr; KReportDesignerSection *pageHeaderFirst = nullptr; KReportDesignerSection *pageHeaderOdd = nullptr; KReportDesignerSection *pageHeaderEven = nullptr; KReportDesignerSection *pageHeaderLast = nullptr; KReportDesignerSection *pageHeaderAny = nullptr; KReportDesignerSection *pageFooterFirst = nullptr; KReportDesignerSection *pageFooterOdd = nullptr; KReportDesignerSection *pageFooterEven = nullptr; KReportDesignerSection *pageFooterLast = nullptr; KReportDesignerSection *pageFooterAny = nullptr; KReportDesignerSection *reportFooter = nullptr; KReportDesignerSectionDetail *detail = nullptr; //Properties KPropertySet set; KPropertySet *itemSet; KProperty *title; KProperty *pageSize; KProperty *orientation; KProperty *unit; KProperty *customHeight; KProperty *customWidth; KProperty *leftMargin; KProperty *rightMargin; KProperty *topMargin; KProperty *bottomMargin; KProperty *showGrid; KProperty *gridDivisions; KProperty *gridSnap; KProperty *labelType; #ifdef KREPORT_SCRIPTING KProperty *script; #endif //Actions QAction *editCutAction; QAction *editCopyAction; QAction *editPasteAction; QAction *editDeleteAction; QAction *sectionEdit; QAction *parameterEdit; QAction *itemRaiseAction; QAction *itemLowerAction; qreal pressX = -1; qreal pressY = -1; qreal releaseX = -1; qreal releaseY = -1; bool modified = false; // true if this document has been modified, false otherwise QString originalInterpreter; //Value of the script interpreter at load time QString originalScript; //Value of the script at load time KReportDataSource *dataSource = nullptr; +#ifdef KREPORT_SCRIPTING + KReportScriptSource *scriptSource = nullptr; +#endif }; KReportDesigner::KReportDesigner(QWidget * parent) : QWidget(parent), d(new Private()) { KReportPluginManager::self(); // this loads icons early enough createProperties(); createActions(); d->grid = new QGridLayout(this); d->grid->setSpacing(0); d->grid->setMargin(0); d->grid->setColumnStretch(1, 1); d->grid->setRowStretch(1, 1); d->grid->setSizeConstraint(QLayout::SetFixedSize); d->vboxlayout = new QVBoxLayout(); d->vboxlayout->setSpacing(0); d->vboxlayout->setMargin(0); d->vboxlayout->setSizeConstraint(QLayout::SetFixedSize); //Create nice rulers d->hruler = new KReportRuler(this, Qt::Horizontal, d->zoomHandler); d->pageButton = new KReportPropertiesButton(this); d->hruler->setUnit(KReportUnit(KReportUnit::Centimeter)); d->grid->addWidget(d->pageButton, 0, 0); d->grid->addWidget(d->hruler, 0, 1); d->grid->addLayout(d->vboxlayout, 1, 0, 1, 2); d->pageButton->setMaximumSize(QSize(19, 22)); d->pageButton->setMinimumSize(QSize(19, 22)); d->detail = new KReportDesignerSectionDetail(this); d->vboxlayout->insertWidget(0, d->detail); setLayout(d->grid); connect(d->pageButton, SIGNAL(released()), this, SLOT(slotPageButton_Pressed())); emit pagePropertyChanged(d->set); connect(&d->set, SIGNAL(propertyChanged(KPropertySet&,KProperty&)), this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); changeSet(&d->set); } KReportDesigner::~KReportDesigner() { delete d; } KReportDesigner::KReportDesigner(QWidget *parent, const QDomElement &data) : KReportDesigner(parent) { if (data.tagName() != QLatin1String("report:content")) { // arg we got an xml file but not one i know of kreportWarning() << "root element was not "; } //kreportDebug() << data.text(); deleteDetail(); QDomNodeList nlist = data.childNodes(); QDomNode it; for (int i = 0; i < nlist.count(); ++i) { it = nlist.item(i); // at this level all the children we get should be Elements if (it.isElement()) { QString n = it.nodeName().toLower(); //kreportDebug() << n; if (n == QLatin1String("report:title")) { setReportTitle(it.firstChild().nodeValue()); #ifdef KREPORT_SCRIPTING } else if (n == QLatin1String("report:script")) { d->originalInterpreter = it.toElement().attribute(QLatin1String("report:script-interpreter"), QLatin1String("javascript")); if (d->originalInterpreter.isEmpty()) { d->originalInterpreter = QLatin1String("javascript"); } d->originalScript = it.firstChild().nodeValue(); d->script->setValue(d->originalScript); if (d->originalInterpreter != QLatin1String("javascript") && d->originalInterpreter != QLatin1String("qtscript")) { QString msg = tr("This report contains scripts of type \"%1\". " "Only scripts written in JavaScript language are " "supported. To prevent losing the scripts, their type " "and content will not be changed unless you change these scripts." ).arg(d->originalInterpreter); QMessageBox::warning(this, tr("Unsupported Script Type"), msg); } #endif } else if (n == QLatin1String("report:grid")) { d->showGrid->setValue(it.toElement().attribute(QLatin1String("report:grid-visible"), QString::number(1)).toInt() != 0); d->gridSnap->setValue(it.toElement().attribute(QLatin1String("report:grid-snap"), QString::number(1)).toInt() != 0); d->gridDivisions->setValue(it.toElement().attribute(QLatin1String("report:grid-divisions"), QString::number(4)).toInt()); d->unit->setValue(it.toElement().attribute(QLatin1String("report:page-unit"), QLatin1String("cm"))); } //! @todo Load page options else if (n == QLatin1String("report:page-style")) { QString pagetype = it.firstChild().nodeValue(); if (pagetype == QLatin1String("predefined")) { d->pageSize->setValue(it.toElement().attribute(QLatin1String("report:page-size"), QLatin1String("A4"))); } else if (pagetype == QLatin1String("custom")) { d->pageSize->setValue(QLatin1String("custom")); d->customHeight->setValue(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("report:custom-page-height"), QLatin1String("")))); d->customWidth->setValue(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("report:custom-page-widtht"), QLatin1String("")))); } else if (pagetype == QLatin1String("label")) { //! @todo } d->rightMargin->setValue(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("fo:margin-right"), QLatin1String("1.0cm")))); d->leftMargin->setValue(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("fo:margin-left"), QLatin1String("1.0cm")))); d->topMargin->setValue(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("fo:margin-top"), QLatin1String("1.0cm")))); d->bottomMargin->setValue(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("fo:margin-bottom"), QLatin1String("1.0cm")))); d->orientation->setValue(it.toElement().attribute(QLatin1String("report:print-orientation"), QLatin1String("portrait"))); } else if (n == QLatin1String("report:body")) { QDomNodeList sectionlist = it.childNodes(); QDomNode sec; for (int s = 0; s < sectionlist.count(); ++s) { sec = sectionlist.item(s); if (sec.isElement()) { QString sn = sec.nodeName().toLower(); //kreportDebug() << sn; if (sn == QLatin1String("report:section")) { QString sectiontype = sec.toElement().attribute(QLatin1String("report:section-type")); if (section(KReportSectionData::sectionTypeFromString(sectiontype)) == nullptr) { insertSection(KReportSectionData::sectionTypeFromString(sectiontype)); section(KReportSectionData::sectionTypeFromString(sectiontype))->initFromXML(sec); } } else if (sn == QLatin1String("report:detail")) { KReportDesignerSectionDetail * rsd = new KReportDesignerSectionDetail(this); rsd->initFromXML(&sec); setDetail(rsd); } } else { kreportWarning() << "Encountered an unknown Element: " << n; } } } } else { kreportWarning() << "Encountered a child node of root that is not an Element"; } } this->slotPageButton_Pressed(); emit reportDataChanged(); slotPropertyChanged(d->set, *d->unit); // set unit for all items setModified(false); } ///The saving code QDomElement KReportDesigner::document() const { QDomDocument doc; QString saveInterpreter; QDomElement content = doc.createElement(QLatin1String("report:content")); content.setAttribute(QLatin1String("xmlns:report"), QLatin1String(ns)); content.setAttribute(QLatin1String("xmlns:fo"), QLatin1String("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0")); content.setAttribute(QLatin1String("xmlns:svg"), QLatin1String("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0")); doc.appendChild(content); //title content.appendChild(propertyToElement(&doc, d->title)); #ifdef KREPORT_SCRIPTING if (d->originalInterpreter.isEmpty()) { d->originalInterpreter = QLatin1String("javascript"); } saveInterpreter = d->originalInterpreter; if (!d->script->value().toString().isEmpty()) { if (d->script->value().toString() != d->originalScript || d->originalInterpreter == QLatin1String("qtscript") || d->originalInterpreter.isEmpty() ) { //The script has changed so force interpreter to 'javascript'. Also set if was using qtscript saveInterpreter = QLatin1String("javascript"); } } QDomElement scr = propertyToElement(&doc, d->script); scr.setAttribute(QLatin1String("report:script-interpreter"), saveInterpreter); content.appendChild(scr); #endif QDomElement grd = doc.createElement(QLatin1String("report:grid")); KReportUtils::addPropertyAsAttribute(&grd, d->showGrid); KReportUtils::addPropertyAsAttribute(&grd, d->gridDivisions); KReportUtils::addPropertyAsAttribute(&grd, d->gridSnap); KReportUtils::addPropertyAsAttribute(&grd, d->unit); content.appendChild(grd); // pageOptions // -- size QDomElement pagestyle = doc.createElement(QLatin1String("report:page-style")); if (d->pageSize->value().toString() == QLatin1String("Custom")) { pagestyle.appendChild(doc.createTextNode(QLatin1String("custom"))); KReportUtils::setAttribute(&pagestyle, QLatin1String("report:custom-page-width"), d->customWidth->value().toDouble()); KReportUtils::setAttribute(&pagestyle, QLatin1String("report:custom-page-height"), d->customHeight->value().toDouble()); } else if (d->pageSize->value().toString() == QLatin1String("Label")) { pagestyle.appendChild(doc.createTextNode(QLatin1String("label"))); pagestyle.setAttribute(QLatin1String("report:page-label-type"), d->labelType->value().toString()); } else { pagestyle.appendChild(doc.createTextNode(QLatin1String("predefined"))); KReportUtils::addPropertyAsAttribute(&pagestyle, d->pageSize); //pagestyle.setAttribute("report:page-size", d->pageSize->value().toString()); } // -- orientation KReportUtils::addPropertyAsAttribute(&pagestyle, d->orientation); // -- margins: save as points, and not localized KReportUtils::setAttribute(&pagestyle, QLatin1String("fo:margin-top"), d->topMargin->value().toDouble()); KReportUtils::setAttribute(&pagestyle, QLatin1String("fo:margin-bottom"), d->bottomMargin->value().toDouble()); KReportUtils::setAttribute(&pagestyle, QLatin1String("fo:margin-right"), d->rightMargin->value().toDouble()); KReportUtils::setAttribute(&pagestyle, QLatin1String("fo:margin-left"), d->leftMargin->value().toDouble()); content.appendChild(pagestyle); QDomElement body = doc.createElement(QLatin1String("report:body")); QDomElement domsection; for (int i = KReportSectionData::PageHeaderFirst; i <= KReportSectionData::PageFooterAny; ++i) { KReportDesignerSection *sec = section((KReportSectionData::Section)i); if (sec) { domsection = doc.createElement(QLatin1String("report:section")); domsection.setAttribute(QLatin1String("report:section-type"), KReportSectionData::sectionTypeString(KReportSectionData::Section(i))); sec->buildXML(&doc, &domsection); body.appendChild(domsection); } } QDomElement detail = doc.createElement(QLatin1String("report:detail")); d->detail->buildXML(&doc, &detail); body.appendChild(detail); content.appendChild(body); return content; } void KReportDesigner::slotSectionEditor() { KReportSectionEditor se(this); (void)se.exec(); } void KReportDesigner::setDataSource(KReportDataSource* source) { if (d->dataSource == source) { return; } delete d->dataSource; d->dataSource = source; slotPageButton_Pressed(); setModified(true); emit reportDataChanged(); } +#ifdef KREPORT_SCRIPTING +void KReportDesigner::setScriptSource(KReportScriptSource* source) +{ + d->scriptSource = source; +} +#endif + KReportDesignerSection * KReportDesigner::section(KReportSectionData::Section s) const { KReportDesignerSection *sec; switch (s) { case KReportSectionData::PageHeaderAny: sec = d->pageHeaderAny; break; case KReportSectionData::PageHeaderEven: sec = d->pageHeaderEven; break; case KReportSectionData::PageHeaderOdd: sec = d->pageHeaderOdd; break; case KReportSectionData::PageHeaderFirst: sec = d->pageHeaderFirst; break; case KReportSectionData::PageHeaderLast: sec = d->pageHeaderLast; break; case KReportSectionData::PageFooterAny: sec = d->pageFooterAny; break; case KReportSectionData::PageFooterEven: sec = d->pageFooterEven; break; case KReportSectionData::PageFooterOdd: sec = d->pageFooterOdd; break; case KReportSectionData::PageFooterFirst: sec = d->pageFooterFirst; break; case KReportSectionData::PageFooterLast: sec = d->pageFooterLast; break; case KReportSectionData::ReportHeader: sec = d->reportHeader; break; case KReportSectionData::ReportFooter: sec = d->reportFooter; break; default: sec = nullptr; } return sec; } KReportDesignerSection* KReportDesigner::createSection() { return new KReportDesignerSection(this, d->zoomHandler); } void KReportDesigner::removeSection(KReportSectionData::Section s) { KReportDesignerSection* sec = section(s); if (sec) { delete sec; switch (s) { case KReportSectionData::PageHeaderAny: d->pageHeaderAny = nullptr; break; case KReportSectionData::PageHeaderEven: sec = d->pageHeaderEven = nullptr; break; case KReportSectionData::PageHeaderOdd: d->pageHeaderOdd = nullptr; break; case KReportSectionData::PageHeaderFirst: d->pageHeaderFirst = nullptr; break; case KReportSectionData::PageHeaderLast: d->pageHeaderLast = nullptr; break; case KReportSectionData::PageFooterAny: d->pageFooterAny = nullptr; break; case KReportSectionData::PageFooterEven: d->pageFooterEven = nullptr; break; case KReportSectionData::PageFooterOdd: d->pageFooterOdd = nullptr; break; case KReportSectionData::PageFooterFirst: d->pageFooterFirst = nullptr; break; case KReportSectionData::PageFooterLast: d->pageFooterLast = nullptr; break; case KReportSectionData::ReportHeader: d->reportHeader = nullptr; break; case KReportSectionData::ReportFooter: d->reportFooter = nullptr; break; default: sec = nullptr; } setModified(true); adjustSize(); } } void KReportDesigner::insertSection(KReportSectionData::Section s) { KReportDesignerSection* sec = section(s); if (!sec) { int idx = 0; for (int i = 1; i <= s; ++i) { if (section((KReportSectionData::Section)i)) idx++; } if (s > KReportSectionData::ReportHeader) idx++; //kreportDebug() << idx; KReportDesignerSection *rs = createSection(); d->vboxlayout->insertWidget(idx, rs); switch (s) { case KReportSectionData::PageHeaderAny: rs->setTitle(tr("Page Header (Any)")); d->pageHeaderAny = rs; break; case KReportSectionData::PageHeaderEven: rs->setTitle(tr("Page Header (Even)")); d->pageHeaderEven = rs; break; case KReportSectionData::PageHeaderOdd: rs->setTitle(tr("Page Header (Odd)")); d->pageHeaderOdd = rs; break; case KReportSectionData::PageHeaderFirst: rs->setTitle(tr("Page Header (First)")); d->pageHeaderFirst = rs; break; case KReportSectionData::PageHeaderLast: rs->setTitle(tr("Page Header (Last)")); d->pageHeaderLast = rs; break; case KReportSectionData::PageFooterAny: rs->setTitle(tr("Page Footer (Any)")); d->pageFooterAny = rs; break; case KReportSectionData::PageFooterEven: rs->setTitle(tr("Page Footer (Even)")); d->pageFooterEven = rs; break; case KReportSectionData::PageFooterOdd: rs->setTitle(tr("Page Footer (Odd)")); d->pageFooterOdd = rs; break; case KReportSectionData::PageFooterFirst: rs->setTitle(tr("Page Footer (First)")); d->pageFooterFirst = rs; break; case KReportSectionData::PageFooterLast: rs->setTitle(tr("Page Footer (Last)")); d->pageFooterLast = rs; break; case KReportSectionData::ReportHeader: rs->setTitle(tr("Report Header")); d->reportHeader = rs; break; case KReportSectionData::ReportFooter: rs->setTitle(tr("Report Footer")); d->reportFooter = rs; break; //These sections cannot be inserted this way case KReportSectionData::None: case KReportSectionData::GroupHeader: case KReportSectionData::GroupFooter: case KReportSectionData::Detail: break; } rs->show(); setModified(true); adjustSize(); emit pagePropertyChanged(d->set); } } void KReportDesigner::setReportTitle(const QString & str) { if (reportTitle() != str) { d->title->setValue(str); setModified(true); } } KPropertySet* KReportDesigner::propertySet() const { return &d->set; } KPropertySet* KReportDesigner::selectedItemPropertySet() const { return d->itemSet; } KReportDataSource *KReportDesigner::reportDataSource() const { return d->dataSource; } KReportDesignerSectionDetail * KReportDesigner::detailSection() const { return d->detail; } QString KReportDesigner::reportTitle() const { return d->title->value().toString(); } bool KReportDesigner::isModified() const { return d->modified; } void KReportDesigner::setModified(bool modified) { d->modified = modified; if (d->modified) { emit dirty(); } } QStringList KReportDesigner::fieldNames() const { QStringList qs; qs << QString(); if (d->dataSource) qs << d->dataSource->fieldNames(); return qs; } QStringList KReportDesigner::fieldKeys() const { QStringList qs; qs << QString(); if (d->dataSource) qs << d->dataSource->fieldKeys(); return qs; } void KReportDesigner::createProperties() { QStringList keys, strings; KReportDesigner::addMetaProperties(&d->set, tr("Report", "Main report element"), QLatin1String("kreport-report-element")); connect(&d->set, SIGNAL(propertyChanged(KPropertySet&,KProperty&)), this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); d->title = new KProperty("title", QLatin1String("Report"), tr("Title"), tr("Report Title")); keys.clear(); keys = KReportPageSize::pageFormatKeys(); strings = KReportPageSize::pageFormatNames(); QString defaultKey = KReportPageSize::pageSizeKey(KReportPageSize::defaultSize()); d->pageSize = new KProperty("page-size", keys, strings, defaultKey, tr("Page Size")); keys.clear(); strings.clear(); keys << QLatin1String("portrait") << QLatin1String("landscape"); strings << tr("Portrait") << tr("Landscape"); d->orientation = new KProperty("print-orientation", keys, strings, QLatin1String("portrait"), tr("Page Orientation")); keys.clear(); strings.clear(); strings = KReportUnit::listOfUnitNameForUi(KReportUnit::HidePixel); QString unit; foreach(const QString &un, strings) { unit = un.mid(un.indexOf(QLatin1String("(")) + 1, 2); keys << unit; } d->unit = new KProperty("page-unit", keys, strings, QLatin1String("cm"), tr("Page Unit")); d->showGrid = new KProperty("grid-visible", true, tr("Show Grid")); d->gridSnap = new KProperty("grid-snap", true, tr("Snap to Grid")); d->gridDivisions = new KProperty("grid-divisions", 4, tr("Grid Divisions")); d->leftMargin = new KProperty("margin-left", KReportUnit(KReportUnit::Centimeter).fromUserValue(1.0), tr("Left Margin"), tr("Left Margin"), KProperty::Double); d->rightMargin = new KProperty("margin-right", KReportUnit(KReportUnit::Centimeter).fromUserValue(1.0), tr("Right Margin"), tr("Right Margin"), KProperty::Double); d->topMargin = new KProperty("margin-top", KReportUnit(KReportUnit::Centimeter).fromUserValue(1.0), tr("Top Margin"), tr("Top Margin"), KProperty::Double); d->bottomMargin = new KProperty("margin-bottom", KReportUnit(KReportUnit::Centimeter).fromUserValue(1.0), tr("Bottom Margin"), tr("Bottom Margin"), KProperty::Double); d->leftMargin->setOption("unit", QLatin1String("cm")); d->rightMargin->setOption("unit", QLatin1String("cm")); d->topMargin->setOption("unit", QLatin1String("cm")); d->bottomMargin->setOption("unit", QLatin1String("cm")); d->set.addProperty(d->title); d->set.addProperty(d->pageSize); d->set.addProperty(d->orientation); d->set.addProperty(d->unit); d->set.addProperty(d->gridSnap); d->set.addProperty(d->showGrid); d->set.addProperty(d->gridDivisions); d->set.addProperty(d->leftMargin); d->set.addProperty(d->rightMargin); d->set.addProperty(d->topMargin); d->set.addProperty(d->bottomMargin); #ifdef KREPORT_SCRIPTING d->script = new KProperty("script", QStringList(), QStringList(), QString(), tr("Object Script")); d->set.addProperty(d->script); #endif // KProperty* _customHeight; // KProperty* _customWidth; } /** @brief Handle property changes */ void KReportDesigner::slotPropertyChanged(KPropertySet &s, KProperty &p) { setModified(true); emit pagePropertyChanged(s); if (p.name() == "page-unit") { d->hruler->setUnit(pageUnit()); QString newstr = d->set.property("page-unit").value().toString(); d->set.property("margin-left").setOption("unit", newstr); d->set.property("margin-right").setOption("unit", newstr); d->set.property("margin-top").setOption("unit", newstr); d->set.property("margin-bottom").setOption("unit", newstr); } } void KReportDesigner::slotPageButton_Pressed() { #ifdef KREPORT_SCRIPTING - if (d->dataSource) { - QStringList sl = d->dataSource->scriptList(); - sl.prepend(QLatin1String("")); + if (d->scriptSource) { + QStringList sl = d->scriptSource->scriptList(); + sl.prepend(QString()); d->script->setListData(sl, sl); } changeSet(&d->set); #endif } QSize KReportDesigner::sizeHint() const { int w = 0; int h = 0; if (d->pageFooterAny) h += d->pageFooterAny->sizeHint().height(); if (d->pageFooterEven) h += d->pageFooterEven->sizeHint().height(); if (d->pageFooterFirst) h += d->pageFooterFirst->sizeHint().height(); if (d->pageFooterLast) h += d->pageFooterLast->sizeHint().height(); if (d->pageFooterOdd) h += d->pageFooterOdd->sizeHint().height(); if (d->pageHeaderAny) h += d->pageHeaderAny->sizeHint().height(); if (d->pageHeaderEven) h += d->pageHeaderEven->sizeHint().height(); if (d->pageHeaderFirst) h += d->pageHeaderFirst->sizeHint().height(); if (d->pageHeaderLast) h += d->pageHeaderLast->sizeHint().height(); if (d->pageHeaderOdd) h += d->pageHeaderOdd->sizeHint().height(); if (d->reportHeader) h += d->reportHeader->sizeHint().height(); if (d->reportFooter) { h += d->reportFooter->sizeHint().height(); } if (d->detail) { h += d->detail->sizeHint().height(); w += d->detail->sizeHint().width(); } h += d->hruler->height(); return QSize(w, h); } int KReportDesigner::pageWidthPx() const { QPageLayout layout = QPageLayout( QPageSize(KReportPageSize::pageSize(d->set.property("page-size").value().toString())), d->set.property("print-orientation").value().toString() == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0)); QSize pageSizePx = layout.fullRectPixels(KReportPrivate::dpiX()).size(); int width = pageSizePx.width(); width = width - POINT_TO_INCH(d->set.property("margin-left").value().toDouble()) * KReportPrivate::dpiX(); width = width - POINT_TO_INCH(d->set.property("margin-right").value().toDouble()) * KReportPrivate::dpiX(); return width; } void KReportDesigner::resizeEvent(QResizeEvent * event) { Q_UNUSED(event); d->hruler->setRulerLength(pageWidthPx()); } void KReportDesigner::setDetail(KReportDesignerSectionDetail *rsd) { if (!d->detail) { int idx = 0; if (d->pageHeaderFirst) idx++; if (d->pageHeaderOdd) idx++; if (d->pageHeaderEven) idx++; if (d->pageHeaderLast) idx++; if (d->pageHeaderAny) idx++; if (d->reportHeader) idx++; d->detail = rsd; d->vboxlayout->insertWidget(idx, d->detail); } } void KReportDesigner::deleteDetail() { delete d->detail; d->detail = nullptr; } KReportUnit KReportDesigner::pageUnit() const { QString u; bool found; u = d->unit->value().toString(); KReportUnit unit = KReportUnit::fromSymbol(u, &found); if (!found) { unit = KReportUnit(KReportUnit::Centimeter); } return unit; } void KReportDesigner::setGridOptions(bool vis, int div) { d->showGrid->setValue(QVariant(vis)); d->gridDivisions->setValue(div); } // // methods for the sectionMouse*Event() // void KReportDesigner::sectionContextMenuEvent(KReportDesignerSectionScene * s, QGraphicsSceneContextMenuEvent * e) { Q_UNUSED(s); QMenu pop; bool itemsSelected = selectionCount() > 0; if (itemsSelected) { //! @todo KF5 use KStandardAction QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cut"), this); connect(a, SIGNAL(triggered()), this, SLOT(slotEditCut())); pop.addAction(a); //! @todo KF5 use KStandardAction a = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("Copy"), this); connect(a, SIGNAL(triggered()), this, SLOT(slotEditCopy())); pop.addAction(a); } if (!d->sectionData.copy_list.isEmpty()) { QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("Paste"), this); connect(a, SIGNAL(triggered()), this, SLOT(slotEditPaste())); pop.addAction(a); } if (itemsSelected) { pop.addSeparator(); //! @todo KF5 use KStandard* //const KGuiItem del = KStandardGuiItem::del(); //a->setToolTip(del.toolTip()); //a->setShortcut(QKeySequence(QKeySequence::Delete)); QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), tr("Delete"), this); connect(a, SIGNAL(triggered()), SLOT(slotEditDelete())); pop.addAction(a); } if (!pop.actions().isEmpty()) { pop.exec(e->screenPos()); } } void KReportDesigner::sectionMousePressEvent(KReportDesignerSectionView * v, QMouseEvent * e) { Q_UNUSED(v); d->pressX = e->pos().x(); d->pressY = e->pos().y(); } void KReportDesigner::sectionMouseReleaseEvent(KReportDesignerSectionView * v, QMouseEvent * e) { e->accept(); d->releaseX = e->pos().x(); d->releaseY = e->pos().y(); if (e->button() == Qt::LeftButton) { QPointF pos(d->pressX, d->pressY); QPointF end(d->releaseX, d->releaseY); if (d->releaseY >= v->scene()->height()) { d->releaseY = v->scene()->height(); end.setY(v->scene()->height()); } if (d->releaseX >= v->scene()->width()) { d->releaseX = v->scene()->width(); end.setX(v->scene()->width()); } if (d->sectionData.mouseAction == ReportWriterSectionData::MA_Insert) { QGraphicsItem * item = nullptr; QString classString; QString iconName; if (d->sectionData.itemToInsert == QLatin1String("org.kde.kreport.line")) { item = new KReportDesignerItemLine(v->designer(), v->scene(), pos, end); classString = tr("Line", "Report line element"); iconName = QLatin1String("kreport-line-element"); } else { KReportPluginManager* pluginManager = KReportPluginManager::self(); KReportPluginInterface *plug = pluginManager->plugin(d->sectionData.itemToInsert); if (plug) { QObject *obj = plug->createDesignerInstance(v->designer(), v->scene(), pos); if (obj) { item = dynamic_cast(obj); classString = plug->metaData()->name(); iconName = plug->metaData()->iconName(); } } else { kreportWarning() << "attempted to insert an unknown item"; } } if (item) { item->setVisible(true); item->setSelected(true); KReportItemBase* baseReportItem = dynamic_cast(item); if (baseReportItem) { baseReportItem->setUnit(pageUnit()); KPropertySet *set = baseReportItem->propertySet(); KReportDesigner::addMetaProperties(set, classString, iconName); changeSet(set); if (v && v->designer()) { v->designer()->setModified(true); } emit itemInserted(d->sectionData.itemToInsert); } } d->sectionData.mouseAction = ReportWriterSectionData::MA_None; d->sectionData.itemToInsert.clear(); unsetSectionCursor(); } } } unsigned int KReportDesigner::selectionCount() const { if (activeScene()) return activeScene()->selectedItems().count(); else return 0; } void KReportDesigner::changeSet(KPropertySet *s) { //Set the checked state of the report properties button if (s == &d->set) d->pageButton->setCheckState(Qt::Checked); else d->pageButton->setCheckState(Qt::Unchecked); d->itemSet = s; emit propertySetChanged(); } // // Actions // void KReportDesigner::slotItem(const QString &entity) { //kreportDebug() << entity; d->sectionData.mouseAction = ReportWriterSectionData::MA_Insert; d->sectionData.itemToInsert = entity; setSectionCursor(QCursor(Qt::CrossCursor)); } void KReportDesigner::slotEditDelete() { QGraphicsItem * item = nullptr; bool modified = false; while (selectionCount() > 0) { item = activeScene()->selectedItems().value(0); if (item) { QGraphicsScene * scene = item->scene(); delete item; scene->update(); d->sectionData.mouseAction = ReportWriterSectionData::MA_None; modified = true; } } activeScene()->selectedItems().clear(); /*! @todo temporary: clears cut and copy lists to make sure we do not crash if weve deleted something in the list should really check if an item is in the list first and remove it. */ d->sectionData.cut_list.clear(); d->sectionData.copy_list.clear(); if (modified) { setModified(true); } } void KReportDesigner::slotEditCut() { if (selectionCount() > 0) { //First delete any items that are curerntly in the list //so as not to leak memory qDeleteAll(d->sectionData.cut_list); d->sectionData.cut_list.clear(); QGraphicsItem * item = activeScene()->selectedItems().first(); bool modified = false; if (item) { d->sectionData.copy_list.clear(); foreach(QGraphicsItem *item, activeScene()->selectedItems()) { d->sectionData.cut_list.append(dynamic_cast(item)); d->sectionData.copy_list.append(dynamic_cast(item)); } foreach(QGraphicsItem *item, activeScene()->selectedItems()) { activeScene()->removeItem(item); activeScene()->update(); modified = true; } d->sectionData.selected_x_offset = 10; d->sectionData.selected_y_offset = 10; } if (modified) { setModified(true); } } } void KReportDesigner::slotEditCopy() { if (selectionCount() < 1) return; QGraphicsItem * item = activeScene()->selectedItems().first(); if (item) { d->sectionData.copy_list.clear(); foreach(QGraphicsItem *item, activeScene()->selectedItems()) { d->sectionData.copy_list.append(dynamic_cast(item)); } d->sectionData.selected_x_offset = 10; d->sectionData.selected_y_offset = 10; } } void KReportDesigner::slotEditPaste() { // call the editPaste function passing it a reportsection slotEditPaste(activeScene()); } void KReportDesigner::slotEditPaste(QGraphicsScene * canvas) { // paste a new item of the copy we have in the specified location if (!d->sectionData.copy_list.isEmpty()) { QList activeItems = canvas->selectedItems(); QGraphicsItem *activeItem = nullptr; if (activeItems.count() == 1) { activeItem = activeItems.first(); } canvas->clearSelection(); d->sectionData.mouseAction = ReportWriterSectionData::MA_None; //! @todo this code sucks :) //! The setPos calls only work AFTER the name has been set ?!?!? foreach(KReportDesignerItemBase *item, d->sectionData.copy_list) { KReportItemBase *obj = dynamic_cast(item); const QString type = obj ? obj->typeName() : QLatin1String("object"); //kreportDebug() << type; KReportDesignerItemBase *ent = item->clone(); KReportItemBase *new_obj = dynamic_cast(ent); if (new_obj) { new_obj->setEntityName(suggestEntityName(type)); if (activeItem) { new_obj->setPosition(KReportItemBase::positionFromScene(QPointF(activeItem->x() + 10, activeItem->y() + 10))); } else { new_obj->setPosition(KReportItemBase::positionFromScene(QPointF(0, 0))); } changeSet(new_obj->propertySet()); } QGraphicsItem *pasted_ent = dynamic_cast(ent); if (pasted_ent) { pasted_ent->setSelected(true); canvas->addItem(pasted_ent); pasted_ent->show(); d->sectionData.mouseAction = ReportWriterSectionData::MA_Grab; setModified(true); } } } } void KReportDesigner::slotRaiseSelected() { dynamic_cast(activeScene())->raiseSelected(); } void KReportDesigner::slotLowerSelected() { dynamic_cast(activeScene())->lowerSelected(); } QGraphicsScene* KReportDesigner::activeScene() const { return d->activeScene; } void KReportDesigner::setActiveScene(QGraphicsScene* a) { if (d->activeScene && d->activeScene != a) d->activeScene->clearSelection(); d->activeScene = a; //Trigger an update so that the last scene redraws its title; update(); } QString KReportDesigner::suggestEntityName(const QString &name) const { KReportDesignerSection *sec; int itemCount = 0; //Count items in the main sections for (int i = 1; i <= KReportSectionData::PageFooterAny; i++) { sec = section((KReportSectionData::Section) i); if (sec) { const QGraphicsItemList l = sec->items(); itemCount += l.count(); } } if (d->detail) { //Count items in the group headers/footers for (int i = 0; i < d->detail->groupSectionCount(); i++) { sec = d->detail->groupSection(i)->groupHeader(); if (sec) { const QGraphicsItemList l = sec->items(); itemCount += l.count(); } sec = d->detail->groupSection(i)->groupFooter(); if (sec) { const QGraphicsItemList l = sec->items(); itemCount += l.count(); } } sec = d->detail->detailSection(); if (sec) { const QGraphicsItemList l = sec->items(); itemCount += l.count(); } } while (!isEntityNameUnique(name + QString::number(itemCount))) { itemCount++; } return name + QString::number(itemCount); } bool KReportDesigner::isEntityNameUnique(const QString &name, KReportItemBase* ignore) const { KReportDesignerSection *sec; bool unique = true; //Check items in the main sections for (int i = 1; i <= KReportSectionData::PageFooterAny; i++) { sec = section((KReportSectionData::Section)i); if (sec) { const QGraphicsItemList l = sec->items(); for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) { KReportItemBase* itm = dynamic_cast(*it); if (itm && itm->entityName() == name && itm != ignore) { unique = false; break; } } if (!unique) break; } } //Count items in the group headers/footers if (unique && d->detail) { for (int i = 0; i < d->detail->groupSectionCount(); ++i) { sec = d->detail->groupSection(i)->groupHeader(); if (sec) { const QGraphicsItemList l = sec->items(); for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) { KReportItemBase* itm = dynamic_cast(*it); if (itm && itm->entityName() == name && itm != ignore) { unique = false; break; } } } sec = d->detail->groupSection(i)->groupFooter(); if (unique && sec) { const QGraphicsItemList l = sec->items(); for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) { KReportItemBase* itm = dynamic_cast(*it); if (itm && itm->entityName() == name && itm != ignore) { unique = false; break; } } } } } if (unique && d->detail) { sec = d->detail->detailSection(); if (sec) { const QGraphicsItemList l = sec->items(); for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) { KReportItemBase* itm = dynamic_cast(*it); if (itm && itm->entityName() == name && itm != ignore) { unique = false; break; } } } } return unique; } static bool actionPriortyLessThan(QAction* act1, QAction* act2) { if (act1->data().toInt() > 0 && act2->data().toInt() > 0) { return act1->data().toInt() < act2->data().toInt(); } return false; } QList KReportDesigner::itemActions(QActionGroup* group) { KReportPluginManager* manager = KReportPluginManager::self(); QList actList = manager->createActions(group); //! @todo make line a real plugin so this isn't needed: QAction *act = new QAction(QIcon::fromTheme(QLatin1String("kreport-line-element")), tr("Line"), group); act->setObjectName(QLatin1String("org.kde.kreport.line")); act->setData(9); act->setCheckable(true); actList << act; qSort(actList.begin(), actList.end(), actionPriortyLessThan); int i = 0; /*! @todo maybe this is a bit hackish It finds the first plugin based on the priority in userdata The lowest oriority a plugin can have is 10 And inserts a separator before it. */ bool sepInserted = false; foreach(QAction *a, actList) { ++i; if (!sepInserted && a->data().toInt() >= 10) { QAction *sep = new QAction(QLatin1String("separator"), group); sep->setSeparator(true); actList.insert(i-1, sep); sepInserted = true; } if (group) { group->addAction(a); } } return actList; } QList< QAction* > KReportDesigner::designerActions() { QList al; QAction *sep = new QAction(QString(), this); sep->setSeparator(true); al << d->editCutAction << d->editCopyAction << d->editPasteAction << d->editDeleteAction << sep << d->sectionEdit << sep << d->itemLowerAction << d->itemRaiseAction; return al; } void KReportDesigner::createActions() { d->editCutAction = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cu&t"), this); d->editCutAction->setObjectName(QLatin1String("edit_cut")); d->editCutAction->setToolTip(tr("Cut selection to clipboard")); d->editCutAction->setShortcuts(KStandardShortcut::cut()); d->editCutAction->setProperty("iconOnly", true); d->editCopyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("&Copy"), this); d->editCopyAction->setObjectName(QLatin1String("edit_copy")); d->editCopyAction->setToolTip(tr("Copy selection to clipboard")); d->editCopyAction->setShortcuts(KStandardShortcut::copy()); d->editCopyAction->setProperty("iconOnly", true); d->editPasteAction = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("&Paste"), this); d->editPasteAction->setObjectName(QLatin1String("edit_paste")); d->editPasteAction->setToolTip(tr("Paste clipboard content")); d->editPasteAction->setShortcuts(KStandardShortcut::paste()); d->editPasteAction->setProperty("iconOnly", true); const KGuiItem del = KStandardGuiItem::del(); d->editDeleteAction = new QAction(del.icon(), del.text(), this); d->editDeleteAction->setObjectName(QLatin1String("edit_delete")); d->editDeleteAction->setToolTip(del.toolTip()); d->editDeleteAction->setWhatsThis(del.whatsThis()); d->editDeleteAction->setProperty("iconOnly", true); d->sectionEdit = new QAction(tr("Edit Sections"), this); d->sectionEdit->setObjectName(QLatin1String("section_edit")); d->itemRaiseAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-up")), tr("Raise"), this); d->itemRaiseAction->setObjectName(QLatin1String("item_raise")); d->itemLowerAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-down")), tr("Lower"), this); d->itemLowerAction->setObjectName(QLatin1String("item_lower")); //Edit Actions connect(d->editCutAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCut())); connect(d->editCopyAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCopy())); connect(d->editPasteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditPaste())); connect(d->editDeleteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditDelete())); connect(d->sectionEdit, SIGNAL(triggered(bool)), this, SLOT(slotSectionEditor())); //Raise/Lower connect(d->itemRaiseAction, SIGNAL(triggered(bool)), this, SLOT(slotRaiseSelected())); connect(d->itemLowerAction, SIGNAL(triggered(bool)), this, SLOT(slotLowerSelected())); } void KReportDesigner::setSectionCursor(const QCursor& c) { if (d->pageFooterAny) d->pageFooterAny->setSectionCursor(c); if (d->pageFooterEven) d->pageFooterEven->setSectionCursor(c); if (d->pageFooterFirst) d->pageFooterFirst->setSectionCursor(c); if (d->pageFooterLast) d->pageFooterLast->setSectionCursor(c); if (d->pageFooterOdd) d->pageFooterOdd->setSectionCursor(c); if (d->pageHeaderAny) d->pageHeaderAny->setSectionCursor(c); if (d->pageHeaderEven) d->pageHeaderEven->setSectionCursor(c); if (d->pageHeaderFirst) d->pageHeaderFirst->setSectionCursor(c); if (d->pageHeaderLast) d->pageHeaderLast->setSectionCursor(c); if (d->pageHeaderOdd) d->pageHeaderOdd->setSectionCursor(c); if (d->detail) d->detail->setSectionCursor(c); } void KReportDesigner::unsetSectionCursor() { if (d->pageFooterAny) d->pageFooterAny->unsetSectionCursor(); if (d->pageFooterEven) d->pageFooterEven->unsetSectionCursor(); if (d->pageFooterFirst) d->pageFooterFirst->unsetSectionCursor(); if (d->pageFooterLast) d->pageFooterLast->unsetSectionCursor(); if (d->pageFooterOdd) d->pageFooterOdd->unsetSectionCursor(); if (d->pageHeaderAny) d->pageHeaderAny->unsetSectionCursor(); if (d->pageHeaderEven) d->pageHeaderEven->unsetSectionCursor(); if (d->pageHeaderFirst) d->pageHeaderFirst->unsetSectionCursor(); if (d->pageHeaderLast) d->pageHeaderLast->unsetSectionCursor(); if (d->pageHeaderOdd) d->pageHeaderOdd->unsetSectionCursor(); if (d->detail) d->detail->unsetSectionCursor(); } qreal KReportDesigner::countSelectionHeight() const { if (d->releaseY == -1 || d->pressY == -1) { return -1; } return qAbs(d->releaseY - d->pressY); } qreal KReportDesigner::countSelectionWidth() const { if (d->releaseX == -1 || d->pressX == -1) { return -1; } return qAbs(d->releaseX - d->pressX); } qreal KReportDesigner::getSelectionPressX() const { return d->pressX; } qreal KReportDesigner::getSelectionPressY() const { return d->pressY; } QPointF KReportDesigner::getPressPoint() const { return QPointF(d->pressX, d->pressY); } QPointF KReportDesigner::getReleasePoint() const { return QPointF(d->releaseX, d->releaseY); } void KReportDesigner::plugItemActions(const QList &actList) { foreach(QAction *a, actList) { connect(a, SIGNAL(triggered(bool)), this, SLOT(slotItemTriggered(bool))); } } void KReportDesigner::slotItemTriggered(bool checked) { if (!checked) { return; } QObject *theSender = sender(); if (!theSender) { return; } slotItem(theSender->objectName()); } void KReportDesigner::addMetaProperties(KPropertySet* set, const QString &classString, const QString &iconName) { Q_ASSERT(set); KProperty *prop; set->addProperty(prop = new KProperty("this:classString", classString)); prop->setVisible(false); set->addProperty(prop = new KProperty("this:iconName", iconName)); prop->setVisible(false); } diff --git a/src/wrtembed/KReportDesigner.h b/src/wrtembed/KReportDesigner.h index d2b31be2..fee140bf 100644 --- a/src/wrtembed/KReportDesigner.h +++ b/src/wrtembed/KReportDesigner.h @@ -1,349 +1,360 @@ /* This file is part of the KDE project * Copyright (C) 2001-2007 by OpenMFG, LLC * Copyright (C) 2007-2008 by Adam Pigg * Copyright (C) 2011-2017 Jarosław Staniek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef KREPORTDESIGNER_H #define KREPORTDESIGNER_H #include #include "KReportDocument.h" #include "KReportDataSource.h" class KProperty; class KPropertySet; class KReportItemBase; class QGraphicsScene; class QActionGroup; class QGraphicsSceneContextMenuEvent; class QString; class KReportDesignerSectionDetail; class KReportDesignerSection; class KReportUnit; class KReportDesignerSectionScene; class KReportDesignerSectionView; class QAction; +#ifdef KREPORT_SCRIPTING +class KReportScriptSource; +#endif + // // Class ReportDesigner // The ReportDesigner is the main widget for designing a report // class KREPORT_EXPORT KReportDesigner : public QWidget { Q_OBJECT public: /** @brief Constructor that create a blank designer @param widget QWidget parent */ explicit KReportDesigner(QWidget *parent = nullptr); /** @brief Constructor that create a designer, and loads the report described in the QDomElement @param widget QWidget parent @param element Report structure XML element */ KReportDesigner(QWidget *parent, const QDomElement &data); /** @brief Desctructor */ ~KReportDesigner() override; /** @brief Sets the report data The report data interface contains functions to retrieve data and information about the fields. - @param kodata Pointer to KReportDataSource instance, ownership is transferred + @param source Pointer to KReportDataSource instance, ownership is transferred */ void setDataSource(KReportDataSource* source); +#ifdef KREPORT_SCRIPTING + /** + @brief Sets the script source for the designer + The script source contains function to return scripts supplied by the parent application + @param source Pointer to KReportScriptSource instance, ownership is NOT transferred as it may be an application window + */ + void setScriptSource(KReportScriptSource *source); +#endif + /** @brief Return a pointer to the reports data @return Pointer to report data */ KReportDataSource *reportDataSource() const; /** @brief Return a pointer to the section specified @param section KReportSectionData::Section enum value of the section to return @return Pointer to report section object, or 0 if no section exists */ KReportDesignerSection* section(KReportSectionData::Section) const; /** @brief Creates new section @return Pointer to a new report section section object, ownership is transferred to the caller */ KReportDesignerSection* createSection() Q_REQUIRED_RESULT; /** @brief Deletes the section specified @param section KReportSectionData::Section enum value of the section to return */ void removeSection(KReportSectionData::Section); /** @brief Create a new section and insert it into the report @param section KReportSectionData::Section enum value of the section to return */ void insertSection(KReportSectionData::Section); /** @brief Return a pointer to the detail section. The detail section contains the actual detail section and related group sections @return Pointer to detail section */ KReportDesignerSectionDetail* detailSection() const; /** @brief Sets the title of the reportData @param title Report Title */ void setReportTitle(const QString &); /** @brief Sets the parameters for the display of the background gridpoints @param visible Grid visibility @param divisions Number of minor divisions between major points */ void setGridOptions(bool visible, int divisions); /** @brief Return the title of the report */ QString reportTitle() const; /** @brief Return an XML description of the report @return QDomElement describing the report definition */ QDomElement document() const; /** @brief Return true if the design has been modified @return modified status */ bool isModified() const; /** @return a list of field names in the selected KReportData */ QStringList fieldNames() const; /** @return a list of field keys in the selected KReportData The keys can be used to reference the names */ QStringList fieldKeys() const; /** @brief Calculate the width of the page in pixels given the paper size, orientation, dpi and margin @return integer value of width in pixels */ int pageWidthPx() const; /** @return the scene (section) that is currently active */ QGraphicsScene* activeScene() const; /** @brief Sets the active Scene @param scene The scene to make active */ void setActiveScene(QGraphicsScene* scene); /** @return the property set for the general report properties */ KPropertySet* propertySet() const; /** @brief Give a hint on the size of the widget */ QSize sizeHint() const override; /** @brief Return the current unit assigned to the report */ KReportUnit pageUnit() const; /** @brief Handle the context menu event for a report section @param scene The associated scene (section) */ void sectionContextMenuEvent(KReportDesignerSectionScene *s, QGraphicsSceneContextMenuEvent * e); /** @brief Handle the mouse release event for a report section */ void sectionMouseReleaseEvent(KReportDesignerSectionView *v, QMouseEvent * e); void sectionMousePressEvent(KReportDesignerSectionView *v, QMouseEvent * e); /** @brief Sets the property set for the currently selected item @param set Property set of item */ void changeSet(KPropertySet *); /** @brief Return the property set for the curently selected item */ KPropertySet* selectedItemPropertySet() const; /** @brief Sets the modified status, defaulting to true for modified @param modified Modified status */ void setModified(bool modified); /** @brief Return a unique name that can be used by the entity @param entity Name of entity */ QString suggestEntityName(const QString &name) const; /** @brief Checks if the supplied name is unique among all entities */ bool isEntityNameUnique(const QString &name, KReportItemBase *ignore = nullptr) const; /** @brief Returns a list of actions that represent the entities that can be inserted into the report. Actions are created as children of @a group and belong to the group. @return list of actions */ static QList itemActions(QActionGroup* group = nullptr); /** @brief Populates the toolbar with actions that can be applied to the report Actions are created as children of @a group and belong to the group. @return list of actions */ QList designerActions(); /** @return X position of mouse when mouse press occurs */ qreal getSelectionPressX() const; /** @return Y position of mouse when mouse press occurs */ qreal getSelectionPressY() const; /** @return difference between X position of mouse release and press */ qreal countSelectionWidth() const; /** @return difference between Y position of mouse release and press */ qreal countSelectionHeight() const; /** @return point that contains X,Y coordinates of mouse press */ QPointF getPressPoint() const; /** @return point that contains X,Y coordinates of mouse press */ QPointF getReleasePoint() const; void plugItemActions(const QList &actList); /** * @brief Adds meta-properties to the property set @a set for consumption by property editor * - "this:classString" - user-visible translated name of element type, e.g. tr("Label") * - "this:iconName" - name of user-visible icon, e.g. "kreport-label-element" * * All the properties are set to invisible. * @see propertySet() */ static void addMetaProperties(KPropertySet* set, const QString &classString, const QString &iconName); public Q_SLOTS: void slotEditDelete(); void slotEditCut(); void slotEditCopy(); void slotEditPaste(); void slotEditPaste(QGraphicsScene *); void slotItem(const QString&); void slotSectionEditor(); void slotRaiseSelected(); void slotLowerSelected(); private: - void init(); - /** @brief Sets the detail section to the given section */ void setDetail(KReportDesignerSectionDetail *rsd); /** @brief Deletes the detail section */ void deleteDetail(); void resizeEvent(QResizeEvent * event) override; //Properties void createProperties(); unsigned int selectionCount() const; void setSectionCursor(const QCursor&); void unsetSectionCursor(); void createActions(); private Q_SLOTS: void slotPropertyChanged(KPropertySet &s, KProperty &p); /** @brief When the 'page' button in the top left is pressed, change the property set to the reports properties. */ void slotPageButton_Pressed(); void slotItemTriggered(bool checked); Q_SIGNALS: void pagePropertyChanged(KPropertySet &s); void propertySetChanged(); void dirty(); void reportDataChanged(); void itemInserted(const QString& entity); private: Q_DISABLE_COPY(KReportDesigner) class Private; Private * const d; }; #endif