mirror of
https://github.com/fralx/LimeReport.git
synced 2025-03-28 13:13:44 +03:00
Merge tag '1.6.7' into develop
Finish 1.6.7
This commit is contained in:
commit
40073d6eb3
@ -3,15 +3,17 @@ cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
set(LIMEREPORT_VERSION_MAJOR 1)
|
||||
set(LIMEREPORT_VERSION_MINOR 6)
|
||||
set(LIMEREPORT_VERSION_RELEASE 6)
|
||||
set(LIMEREPORT_VERSION_RELEASE 8)
|
||||
|
||||
option(ENABLE_ZINT "Enable libzint build for barcode support" OFF)
|
||||
option(LIMEREPORT_STATIC "Build LimeReport as static library" OFF)
|
||||
option(USE_QT6 "Use Qt6" OFF)
|
||||
|
||||
find_package(
|
||||
QT NAMES Qt6 Qt5
|
||||
COMPONENTS Core Widgets Sql Network Xml Svg Qml PrintSupport REQUIRED
|
||||
)
|
||||
if(USE_QT6)
|
||||
find_package(QT NAMES Qt6)
|
||||
else()
|
||||
find_package(QT NAMES Qt5)
|
||||
endif(USE_QT6)
|
||||
find_package(
|
||||
Qt${QT_VERSION_MAJOR}
|
||||
COMPONENTS Core Widgets Sql Network Xml Svg Qml PrintSupport REQUIRED
|
||||
@ -36,7 +38,7 @@ endif()
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(designer EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(demo_r1 EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(demo_r1 EXCLUDE_FROM_ALL)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
@ -78,6 +80,7 @@ ${PROJECT_NAME}/items/editors/lrtextalignmenteditorwidget.cpp
|
||||
${PROJECT_NAME}/items/lrabstractlayout.cpp
|
||||
${PROJECT_NAME}/items/lralignpropitem.cpp
|
||||
${PROJECT_NAME}/items/lrchartitem.cpp
|
||||
${PROJECT_NAME}/items/lrchartaxiseditor.cpp
|
||||
${PROJECT_NAME}/items/lrchartitemeditor.cpp
|
||||
${PROJECT_NAME}/items/lrhorizontallayout.cpp
|
||||
${PROJECT_NAME}/items/lrimageitem.cpp
|
||||
@ -189,6 +192,7 @@ ${PROJECT_NAME}/items/editors/lrtextalignmenteditorwidget.h
|
||||
${PROJECT_NAME}/items/lrabstractlayout.h
|
||||
${PROJECT_NAME}/items/lralignpropitem.h
|
||||
${PROJECT_NAME}/items/lrchartitem.h
|
||||
${PROJECT_NAME}/items/lrchartaxiseditor.h
|
||||
${PROJECT_NAME}/items/lrchartitemeditor.h
|
||||
${PROJECT_NAME}/items/lreditableimageitemintf.h
|
||||
${PROJECT_NAME}/items/lrhorizontallayout.h
|
||||
@ -285,6 +289,7 @@ ${PROJECT_NAME}/databrowser/lrsqleditdialog.ui
|
||||
${PROJECT_NAME}/databrowser/lrvariabledialog.ui
|
||||
${PROJECT_NAME}/dialogdesigner/templates/Dialog.ui
|
||||
${PROJECT_NAME}/items/lrchartitemeditor.ui
|
||||
${PROJECT_NAME}/items/lrchartaxiseditor.ui
|
||||
${PROJECT_NAME}/items/lrimageitemeditor.ui
|
||||
${PROJECT_NAME}/items/lrtextitemeditor.ui
|
||||
${PROJECT_NAME}/lraboutdialog.ui
|
||||
@ -340,6 +345,8 @@ set(GLOBAL_HEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config.h
|
||||
)
|
||||
|
||||
set(PROJECT_NAME ${PROJECT_NAME}-qt${QT_VERSION_MAJOR})
|
||||
|
||||
if (LIMEREPORT_STATIC)
|
||||
message(STATUS "STATIC LIBRARY")
|
||||
add_library(${PROJECT_NAME} STATIC ${EXTRA_FILES} ${LIMEREPORT_SOURCES})
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
## Official LimeReport web site [http://limereport.ru](http://limereport.ru)
|
||||
|
||||
## Donation [](https://www.paypal.me/arinalex)
|
||||
|
||||
## Features
|
||||
|
||||
* Multi-platform support
|
||||
|
@ -141,7 +141,7 @@ RCC_DIR = $${ARCH_DIR}/$${BUILD_TYPE}/rcc
|
||||
|
||||
LIMEREPORT_VERSION_MAJOR = 1
|
||||
LIMEREPORT_VERSION_MINOR = 6
|
||||
LIMEREPORT_VERSION_RELEASE = 0
|
||||
LIMEREPORT_VERSION_RELEASE = 8
|
||||
|
||||
LIMEREPORT_VERSION = '$${LIMEREPORT_VERSION_MAJOR}.$${LIMEREPORT_VERSION_MINOR}.$${LIMEREPORT_VERSION_RELEASE}'
|
||||
DEFINES *= LIMEREPORT_VERSION_STR=\\\"$${LIMEREPORT_VERSION}\\\"
|
||||
|
@ -18,6 +18,6 @@ target_link_libraries(demo_r1 PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::PrintSupport
|
||||
Qt${QT_VERSION_MAJOR}::Qml
|
||||
Qt${QT_VERSION_MAJOR}::Sql
|
||||
${PROJECT_NAME}
|
||||
${PROJECT_NAME}-qt${QT_VERSION_MAJOR}
|
||||
)
|
||||
|
||||
|
@ -14,5 +14,7 @@ target_include_directories(LRDesigner PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
target_link_libraries(LRDesigner PUBLIC
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
${PROJECT_NAME}
|
||||
Qt${QT_VERSION_MAJOR}::PrintSupport
|
||||
Qt${QT_VERSION_MAJOR}::Qml
|
||||
${PROJECT_NAME}-qt${QT_VERSION_MAJOR}
|
||||
)
|
||||
|
@ -104,7 +104,7 @@ namespace Const{
|
||||
QString extractClassName(QString className);
|
||||
QString escapeSimbols(const QString& value);
|
||||
QString replaceHTMLSymbols(const QString &value);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QVector<QString> normalizeCaptures(const QRegularExpressionMatch ®);
|
||||
#else
|
||||
QVector<QString> normalizeCaptures(const QRegExp ®);
|
||||
@ -157,6 +157,16 @@ namespace Const{
|
||||
#else
|
||||
typedef QStyleOptionViewItem StyleOptionViewItem;
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression getRegEx(QString expression);
|
||||
QRegularExpression getVariableRegEx();
|
||||
QRegularExpression getFieldRegEx();
|
||||
QRegularExpression getScriptRegEx();
|
||||
QRegularExpression getGroupFunctionRegEx(QString functionName);
|
||||
QRegularExpression getGroupFunctionNameRegEx(QString functionName);
|
||||
QRegularExpression getNamedVariableRegEx(QString variableName);
|
||||
#endif
|
||||
|
||||
|
||||
class Enums
|
||||
{
|
||||
|
@ -36,7 +36,11 @@ namespace LimeReport {
|
||||
DataBrowserTree::DataBrowserTree(QWidget *parent) :
|
||||
QTreeWidget(parent){}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
||||
QMimeData *DataBrowserTree::mimeData(const QList<QTreeWidgetItem *> &items) const
|
||||
#else
|
||||
QMimeData *DataBrowserTree::mimeData(const QList<QTreeWidgetItem *> items) const
|
||||
#endif
|
||||
{
|
||||
QMimeData* result = QTreeWidget::mimeData(items);
|
||||
if (items.at(0)->type()==Row){
|
||||
|
@ -42,7 +42,11 @@ public:
|
||||
enum NodeType{Connection, Table, Row, Category, Variable, ExternalVariable};
|
||||
explicit DataBrowserTree(QWidget *parent = 0);
|
||||
protected:
|
||||
QMimeData* mimeData(const QList<QTreeWidgetItem *> items) const;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
||||
virtual QMimeData *mimeData(const QList<QTreeWidgetItem *> &items) const;
|
||||
#else
|
||||
virtual QMimeData *mimeData(const QList<QTreeWidgetItem*> items) const;
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -28,20 +28,18 @@
|
||||
* GNU General Public License for more details. *
|
||||
****************************************************************************/
|
||||
#include "lrsqleditdialog.h"
|
||||
#include "ui_lrsqleditdialog.h"
|
||||
#include "lrreportengine_p.h"
|
||||
#include "ui_lrsqleditdialog.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QSqlDatabase>
|
||||
#include <QMessageBox>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
namespace LimeReport{
|
||||
namespace LimeReport {
|
||||
|
||||
SQLEditDialog::SQLEditDialog(QWidget *parent, LimeReport::DataSourceManager *dataSources, SQLDialogMode dialogMode) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::SQLEditDialog),m_datasources(dataSources),m_dialogMode(dialogMode), m_oldDatasourceName(""),
|
||||
m_settings(0), m_ownedSettings(false)
|
||||
{
|
||||
SQLEditDialog::SQLEditDialog(QWidget *parent, LimeReport::DataSourceManager *dataSources, SQLDialogMode dialogMode)
|
||||
: QDialog(parent), ui(new Ui::SQLEditDialog), m_datasources(dataSources), m_dialogMode(dialogMode),
|
||||
m_oldDatasourceName(""), m_settings(0), m_ownedSettings(false) {
|
||||
ui->setupUi(this);
|
||||
m_masterDatasources = new QCompleter(this);
|
||||
ui->leMaster->setCompleter(m_masterDatasources);
|
||||
@ -54,72 +52,72 @@ SQLEditDialog::SQLEditDialog(QWidget *parent, LimeReport::DataSourceManager *dat
|
||||
ui->rbSubQuery->setVisible(false);
|
||||
ui->leMaster->setVisible(false);
|
||||
ui->lbMaster->setVisible(false);
|
||||
ui->fieldsMap->setHorizontalHeaderItem(0,new QTableWidgetItem("master"));
|
||||
ui->fieldsMap->setHorizontalHeaderItem(1,new QTableWidgetItem("detail"));
|
||||
ui->fieldsMap->setHorizontalHeaderItem(0, new QTableWidgetItem("master"));
|
||||
ui->fieldsMap->setHorizontalHeaderItem(1, new QTableWidgetItem("detail"));
|
||||
|
||||
#ifdef HAVE_QT5
|
||||
ui->fieldsMap->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
#else
|
||||
ui->fieldsMap->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
|
||||
#endif
|
||||
|
||||
ui->pnlChildDatasource->setVisible(false);
|
||||
connect(ui->pbPreview, SIGNAL(pressed()), this, SLOT(slotPreviewData()));
|
||||
connect(ui->pbHidePreview, SIGNAL(pressed()), this, SLOT(slotHidePreview()));
|
||||
}
|
||||
|
||||
SQLEditDialog::~SQLEditDialog()
|
||||
{
|
||||
SQLEditDialog::~SQLEditDialog() {
|
||||
delete ui;
|
||||
if (m_settings && m_ownedSettings)
|
||||
delete m_settings;
|
||||
}
|
||||
|
||||
QSettings *SQLEditDialog::settings(){
|
||||
if (m_settings){
|
||||
QSettings *SQLEditDialog::settings() {
|
||||
if (m_settings) {
|
||||
return m_settings;
|
||||
} else {
|
||||
m_settings = new QSettings("LimeReport",QCoreApplication::applicationName());
|
||||
m_settings = new QSettings("LimeReport", QCoreApplication::applicationName());
|
||||
m_ownedSettings = true;
|
||||
return m_settings;
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::setSettings(QSettings *value, bool owned){
|
||||
if (m_settings && m_ownedSettings) delete m_settings;
|
||||
void SQLEditDialog::setSettings(QSettings *value, bool owned) {
|
||||
if (m_settings && m_ownedSettings)
|
||||
delete m_settings;
|
||||
m_settings = value;
|
||||
m_ownedSettings = owned;
|
||||
}
|
||||
|
||||
void SQLEditDialog::accept()
|
||||
{
|
||||
void SQLEditDialog::accept() {
|
||||
SQLEditResult result;
|
||||
|
||||
if (ui->tabWidget->currentIndex() == 1){
|
||||
if (ui->tabWidget->currentIndex() == 1) {
|
||||
result.resultMode = SQLEditResult::CSVText;
|
||||
} else if (!ui->cbSubdetail->isChecked()){
|
||||
result.resultMode=SQLEditResult::Query;
|
||||
} else if (!ui->cbSubdetail->isChecked()) {
|
||||
result.resultMode = SQLEditResult::Query;
|
||||
} else {
|
||||
if (ui->rbSubQuery->isChecked()) result.resultMode = SQLEditResult::SubQuery;
|
||||
else result.resultMode=SQLEditResult::SubProxy;
|
||||
if (ui->rbSubQuery->isChecked())
|
||||
result.resultMode = SQLEditResult::SubQuery;
|
||||
else
|
||||
result.resultMode = SQLEditResult::SubProxy;
|
||||
}
|
||||
|
||||
result.connectionName = ConnectionDesc::connectionNameForReport(ui->cbbConnection->currentText());
|
||||
result.datasourceName=ui->leDatasourceName->text();
|
||||
result.datasourceName = ui->leDatasourceName->text();
|
||||
result.sql = ui->sqlText->toPlainText();
|
||||
result.csv = ui->csvText->toPlainText();
|
||||
result.dialogMode = m_dialogMode;
|
||||
result.oldDatasourceName = m_oldDatasourceName;
|
||||
result.subdetail = ui->cbSubdetail->isChecked();
|
||||
result.masterDatasource=ui->leMaster->text();
|
||||
result.childDataSource=ui->leChild->text();
|
||||
result.masterDatasource = ui->leMaster->text();
|
||||
result.childDataSource = ui->leChild->text();
|
||||
result.separator = ui->leSeparator->text();
|
||||
result.firstRowIsHeader = ui->cbUseFirstRowAsHeader->isChecked();
|
||||
|
||||
if (ui->fieldsMap->rowCount() > 0){
|
||||
for(int i=0; i< ui->fieldsMap->rowCount(); ++i){
|
||||
if (ui->fieldsMap->rowCount() > 0) {
|
||||
for (int i = 0; i < ui->fieldsMap->rowCount(); ++i) {
|
||||
LimeReport::FieldsCorrelation fieldsCorrelation;
|
||||
fieldsCorrelation.master = ui->fieldsMap->item(i,0) ? ui->fieldsMap->item(i,0)->data(Qt::DisplayRole).toString() : "";
|
||||
fieldsCorrelation.detail = ui->fieldsMap->item(i,1) ? ui->fieldsMap->item(i,1)->data(Qt::DisplayRole).toString() : "";
|
||||
fieldsCorrelation.master =
|
||||
ui->fieldsMap->item(i, 0) ? ui->fieldsMap->item(i, 0)->data(Qt::DisplayRole).toString() : "";
|
||||
fieldsCorrelation.detail =
|
||||
ui->fieldsMap->item(i, 1) ? ui->fieldsMap->item(i, 1)->data(Qt::DisplayRole).toString() : "";
|
||||
result.fieldMap.append(fieldsCorrelation);
|
||||
}
|
||||
}
|
||||
@ -128,87 +126,83 @@ void SQLEditDialog::accept()
|
||||
check();
|
||||
emit signalSqlEditingFinished(result);
|
||||
QDialog::accept();
|
||||
}catch(LimeReport::ReportError &exception){
|
||||
QMessageBox::critical(this,tr("Error"),exception.what());
|
||||
} catch (LimeReport::ReportError &exception) {
|
||||
QMessageBox::critical(this, tr("Error"), exception.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::showEvent(QShowEvent *)
|
||||
{
|
||||
void SQLEditDialog::showEvent(QShowEvent *) {
|
||||
ui->lblInfo->setVisible(false);
|
||||
initConnections();
|
||||
readSettings();
|
||||
}
|
||||
|
||||
void SQLEditDialog::closeEvent(QCloseEvent *)
|
||||
{
|
||||
writeSetting();
|
||||
}
|
||||
void SQLEditDialog::closeEvent(QCloseEvent *) { writeSetting(); }
|
||||
|
||||
void SQLEditDialog::hideEvent(QHideEvent *)
|
||||
{
|
||||
writeSetting();
|
||||
}
|
||||
void SQLEditDialog::hideEvent(QHideEvent *) { writeSetting(); }
|
||||
|
||||
void SQLEditDialog::check()
|
||||
{
|
||||
if (ui->leDatasourceName->text().isEmpty()) throw LimeReport::ReportError(tr("Datasource Name is empty!"));
|
||||
if (ui->sqlText->toPlainText().isEmpty() && (!ui->rbProxy) ) throw LimeReport::ReportError(tr("SQL is empty!"));
|
||||
if (m_dialogMode==AddMode){
|
||||
if (m_datasources->containsDatasource(ui->leDatasourceName->text())){
|
||||
throw LimeReport::ReportError(QString(tr("Datasource with name: \"%1\" already exists!")).arg(ui->leDatasourceName->text()));
|
||||
void SQLEditDialog::check() {
|
||||
if (ui->leDatasourceName->text().isEmpty())
|
||||
throw LimeReport::ReportError(tr("Datasource Name is empty!"));
|
||||
if (ui->sqlText->toPlainText().isEmpty() && (!ui->rbProxy))
|
||||
throw LimeReport::ReportError(tr("SQL is empty!"));
|
||||
if (m_dialogMode == AddMode) {
|
||||
if (m_datasources->containsDatasource(ui->leDatasourceName->text())) {
|
||||
throw LimeReport::ReportError(
|
||||
QString(tr("Datasource with name: \"%1\" already exists!")).arg(ui->leDatasourceName->text()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::initConnections()
|
||||
{
|
||||
foreach(QString connectionName, QSqlDatabase::connectionNames()){
|
||||
ui->cbbConnection->addItem(QIcon(":/databrowser/images/plug-connect.png"),ConnectionDesc::connectionNameForUser(connectionName));
|
||||
void SQLEditDialog::initConnections() {
|
||||
foreach (QString connectionName, QSqlDatabase::connectionNames()) {
|
||||
ui->cbbConnection->addItem(QIcon(":/databrowser/images/plug-connect.png"),
|
||||
ConnectionDesc::connectionNameForUser(connectionName));
|
||||
}
|
||||
|
||||
foreach(QString connectionName, m_datasources->connectionNames()){
|
||||
connectionName = (connectionName.compare(QSqlDatabase::defaultConnection)==0) ?
|
||||
tr("defaultConnection") : connectionName;
|
||||
if (ui->cbbConnection->findText(connectionName,Qt::MatchExactly )==-1)
|
||||
ui->cbbConnection->addItem(QIcon(":/databrowser/images/plug-disconnect.png"),ConnectionDesc::connectionNameForUser(connectionName));
|
||||
foreach (QString connectionName, m_datasources->connectionNames()) {
|
||||
connectionName =
|
||||
(connectionName.compare(QSqlDatabase::defaultConnection) == 0) ? tr("defaultConnection") : connectionName;
|
||||
if (ui->cbbConnection->findText(connectionName, Qt::MatchExactly) == -1)
|
||||
ui->cbbConnection->addItem(QIcon(":/databrowser/images/plug-disconnect.png"),
|
||||
ConnectionDesc::connectionNameForUser(connectionName));
|
||||
}
|
||||
|
||||
ui->cbbConnection->setCurrentIndex(ui->cbbConnection->findText(m_defaultConnection));
|
||||
if (!m_oldDatasourceName.isEmpty()){
|
||||
ui->cbbConnection->setCurrentIndex(ui->cbbConnection->findText(ConnectionDesc::connectionNameForUser(m_datasources->connectionName(m_oldDatasourceName))));
|
||||
if (!m_oldDatasourceName.isEmpty()) {
|
||||
ui->cbbConnection->setCurrentIndex(ui->cbbConnection->findText(
|
||||
ConnectionDesc::connectionNameForUser(m_datasources->connectionName(m_oldDatasourceName))));
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::setDataSources(LimeReport::DataSourceManager *dataSources, QString datasourceName)
|
||||
{
|
||||
m_datasources=dataSources;
|
||||
if (!datasourceName.isEmpty()){
|
||||
void SQLEditDialog::setDataSources(LimeReport::DataSourceManager *dataSources, QString datasourceName) {
|
||||
m_datasources = dataSources;
|
||||
if (!datasourceName.isEmpty()) {
|
||||
ui->cbSubdetail->setEnabled(true);
|
||||
m_oldDatasourceName=datasourceName;
|
||||
m_oldDatasourceName = datasourceName;
|
||||
ui->leDatasourceName->setText(datasourceName);
|
||||
ui->sqlText->setText(dataSources->queryText(datasourceName));
|
||||
if (dataSources->isQuery(datasourceName)){
|
||||
if (dataSources->isQuery(datasourceName)) {
|
||||
initQueryMode();
|
||||
}
|
||||
if (dataSources->isSubQuery(datasourceName)){
|
||||
if (dataSources->isSubQuery(datasourceName)) {
|
||||
initSubQueryMode();
|
||||
ui->leMaster->setText(dataSources->subQueryByName(datasourceName)->master());
|
||||
}
|
||||
if (dataSources->isProxy(datasourceName)){
|
||||
if (dataSources->isProxy(datasourceName)) {
|
||||
initProxyMode();
|
||||
LimeReport::ProxyDesc* proxyDesc = dataSources->proxyByName(datasourceName);
|
||||
LimeReport::ProxyDesc *proxyDesc = dataSources->proxyByName(datasourceName);
|
||||
ui->leChild->setText(proxyDesc->child());
|
||||
ui->leMaster->setText(proxyDesc->master());
|
||||
int curIndex=0;
|
||||
foreach(LimeReport::FieldMapDesc* fields, *proxyDesc->fieldsMap()){
|
||||
ui->fieldsMap->setRowCount(curIndex+1);
|
||||
ui->fieldsMap->setItem(curIndex,0,new QTableWidgetItem(fields->master()));
|
||||
ui->fieldsMap->setItem(curIndex,1,new QTableWidgetItem(fields->detail()));
|
||||
int curIndex = 0;
|
||||
foreach (LimeReport::FieldMapDesc *fields, *proxyDesc->fieldsMap()) {
|
||||
ui->fieldsMap->setRowCount(curIndex + 1);
|
||||
ui->fieldsMap->setItem(curIndex, 0, new QTableWidgetItem(fields->master()));
|
||||
ui->fieldsMap->setItem(curIndex, 1, new QTableWidgetItem(fields->detail()));
|
||||
curIndex++;
|
||||
}
|
||||
}
|
||||
if (dataSources->isCSV(datasourceName)){
|
||||
if (dataSources->isCSV(datasourceName)) {
|
||||
ui->csvText->setPlainText(dataSources->csvByName(datasourceName)->csvText());
|
||||
ui->leSeparator->setText(dataSources->csvByName(datasourceName)->separator());
|
||||
ui->cbUseFirstRowAsHeader->setChecked(dataSources->csvByName(datasourceName)->firstRowIsHeader());
|
||||
@ -217,59 +211,55 @@ void SQLEditDialog::setDataSources(LimeReport::DataSourceManager *dataSources, Q
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::setDefaultConnection(QString defaultConnection)
|
||||
{
|
||||
void SQLEditDialog::setDefaultConnection(QString defaultConnection) {
|
||||
m_defaultConnection = ConnectionDesc::connectionNameForUser(defaultConnection);
|
||||
}
|
||||
|
||||
void SQLEditDialog::slotDataSourceNameEditing()
|
||||
{
|
||||
if (m_dialogMode==AddMode){
|
||||
QPalette palette=ui->leDatasourceName->palette();
|
||||
if (m_datasources->containsDatasource(ui->leDatasourceName->text())){
|
||||
palette.setColor(QPalette::Text,Qt::red);
|
||||
void SQLEditDialog::slotDataSourceNameEditing() {
|
||||
if (m_dialogMode == AddMode) {
|
||||
QPalette palette = ui->leDatasourceName->palette();
|
||||
if (m_datasources->containsDatasource(ui->leDatasourceName->text())) {
|
||||
palette.setColor(QPalette::Text, Qt::red);
|
||||
ui->leDatasourceName->setPalette(palette);
|
||||
ui->lblInfo->setText(QString(tr("Datasource with name %1 already exist")).arg(ui->leDatasourceName->text()));
|
||||
ui->lblInfo->setText(
|
||||
QString(tr("Datasource with name %1 already exist")).arg(ui->leDatasourceName->text()));
|
||||
ui->lblInfo->setVisible(true);
|
||||
} else {
|
||||
palette.setColor(QPalette::Text,QApplication::palette().text().color());
|
||||
palette.setColor(QPalette::Text, QApplication::palette().text().color());
|
||||
ui->leDatasourceName->setPalette(palette);
|
||||
ui->lblInfo->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::on_cbSubdetail_clicked(bool checked)
|
||||
{
|
||||
if (checked){
|
||||
m_masterDatasources->setModel(new QStringListModel(m_datasources->dataSourceNames(),m_datasources));
|
||||
void SQLEditDialog::on_cbSubdetail_clicked(bool checked) {
|
||||
if (checked) {
|
||||
m_masterDatasources->setModel(new QStringListModel(m_datasources->dataSourceNames(), m_datasources));
|
||||
}
|
||||
ui->leMaster->setEnabled(checked);
|
||||
ui->rbProxy->setEnabled(checked);
|
||||
ui->rbSubQuery->setEnabled(checked);
|
||||
if ((checked)&&(ui->rbProxy->isChecked())) initProxyMode();
|
||||
if ((checked)&&(ui->rbSubQuery->isChecked())) initSubQueryMode();
|
||||
if (!checked) initQueryMode();
|
||||
if ((checked) && (ui->rbProxy->isChecked()))
|
||||
initProxyMode();
|
||||
if ((checked) && (ui->rbSubQuery->isChecked()))
|
||||
initSubQueryMode();
|
||||
if (!checked)
|
||||
initQueryMode();
|
||||
}
|
||||
|
||||
void SQLEditDialog::on_rbProxy_clicked(bool checked)
|
||||
{
|
||||
if (checked) initProxyMode();
|
||||
void SQLEditDialog::on_rbProxy_clicked(bool checked) {
|
||||
if (checked)
|
||||
initProxyMode();
|
||||
}
|
||||
|
||||
void SQLEditDialog::on_rbSubQuery_clicked(bool checked)
|
||||
{
|
||||
if (checked) initSubQueryMode();
|
||||
void SQLEditDialog::on_rbSubQuery_clicked(bool checked) {
|
||||
if (checked)
|
||||
initSubQueryMode();
|
||||
}
|
||||
|
||||
void SQLEditDialog::on_pbAddField_clicked()
|
||||
{
|
||||
ui->fieldsMap->setRowCount(ui->fieldsMap->rowCount()+1);
|
||||
}
|
||||
void SQLEditDialog::on_pbAddField_clicked() { ui->fieldsMap->setRowCount(ui->fieldsMap->rowCount() + 1); }
|
||||
|
||||
|
||||
void SQLEditDialog::initQueryMode()
|
||||
{
|
||||
void SQLEditDialog::initQueryMode() {
|
||||
ui->gbSQL->setVisible(true);
|
||||
ui->gbFieldsMap->setVisible(false);
|
||||
ui->pnlChildDatasource->setVisible(false);
|
||||
@ -278,12 +268,11 @@ void SQLEditDialog::initQueryMode()
|
||||
ui->cbSubdetail->setChecked(false);
|
||||
ui->leMaster->setVisible(false);
|
||||
ui->lbMaster->setVisible(false);
|
||||
//ui->tabWidget->removeTab(1);
|
||||
// ui->tabWidget->removeTab(1);
|
||||
ui->tabWidget->addTab(ui->csvTab, tr("CSV"));
|
||||
}
|
||||
|
||||
void SQLEditDialog::initSubQueryMode()
|
||||
{
|
||||
void SQLEditDialog::initSubQueryMode() {
|
||||
ui->gbSQL->setVisible(true);
|
||||
ui->gbFieldsMap->setVisible(false);
|
||||
ui->pnlChildDatasource->setVisible(false);
|
||||
@ -297,8 +286,7 @@ void SQLEditDialog::initSubQueryMode()
|
||||
ui->tabWidget->removeTab(1);
|
||||
}
|
||||
|
||||
void SQLEditDialog::initProxyMode()
|
||||
{
|
||||
void SQLEditDialog::initProxyMode() {
|
||||
ui->gbSQL->setVisible(false);
|
||||
ui->gbFieldsMap->setVisible(true);
|
||||
ui->pnlChildDatasource->setVisible(true);
|
||||
@ -313,23 +301,17 @@ void SQLEditDialog::initProxyMode()
|
||||
ui->tabWidget->removeTab(1);
|
||||
}
|
||||
|
||||
void SQLEditDialog::initCSVMode()
|
||||
{
|
||||
ui->tabWidget->setCurrentWidget(ui->csvTab);
|
||||
}
|
||||
void SQLEditDialog::initCSVMode() { ui->tabWidget->setCurrentWidget(ui->csvTab); }
|
||||
|
||||
void SQLEditDialog::slotPreviewData()
|
||||
{
|
||||
if (ui->cbbConnection->currentText().isEmpty()){
|
||||
QMessageBox::critical(this,tr("Attention"),tr("Connection is not specified"));
|
||||
void SQLEditDialog::slotPreviewData() {
|
||||
if (ui->cbbConnection->currentText().isEmpty()) {
|
||||
QMessageBox::critical(this, tr("Attention"), tr("Connection is not specified"));
|
||||
return;
|
||||
}
|
||||
m_previewModel = m_datasources->previewSQL(
|
||||
ConnectionDesc::connectionNameForReport(ui->cbbConnection->currentText()),
|
||||
ui->sqlText->toPlainText(),
|
||||
ui->leMaster->text()
|
||||
);
|
||||
if (m_previewModel){
|
||||
m_previewModel =
|
||||
m_datasources->previewSQL(ConnectionDesc::connectionNameForReport(ui->cbbConnection->currentText()),
|
||||
ui->sqlText->toPlainText(), ui->leMaster->text());
|
||||
if (m_previewModel) {
|
||||
ui->tvPreview->setModel(m_previewModel.data());
|
||||
ui->gbDataPreview->setVisible(true);
|
||||
ui->pbPreview->setText(tr("Refresh"));
|
||||
@ -337,49 +319,37 @@ void SQLEditDialog::slotPreviewData()
|
||||
} else {
|
||||
if (ui->gbDataPreview->isVisible())
|
||||
hidePreview();
|
||||
QMessageBox::critical(this,tr("Attention"),m_datasources->lastError());
|
||||
QMessageBox::critical(this, tr("Attention"), m_datasources->lastError());
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::slotHidePreview()
|
||||
{
|
||||
hidePreview();
|
||||
}
|
||||
void SQLEditDialog::slotHidePreview() { hidePreview(); }
|
||||
|
||||
void SQLEditDialog::writeSetting()
|
||||
{
|
||||
if (settings()!=0){
|
||||
void SQLEditDialog::writeSetting() {
|
||||
if (settings() != 0) {
|
||||
settings()->beginGroup("SQLEditor");
|
||||
settings()->setValue("Geometry",saveGeometry());
|
||||
settings()->setValue("Geometry", saveGeometry());
|
||||
settings()->endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void SQLEditDialog::readSettings()
|
||||
{
|
||||
if (settings()==0) return;
|
||||
void SQLEditDialog::readSettings() {
|
||||
if (settings() == 0)
|
||||
return;
|
||||
settings()->beginGroup("SQLEditor");
|
||||
QVariant v = settings()->value("Geometry");
|
||||
if (v.isValid()){
|
||||
if (v.isValid()) {
|
||||
restoreGeometry(v.toByteArray());
|
||||
}
|
||||
settings()->endGroup();
|
||||
}
|
||||
|
||||
void SQLEditDialog::hidePreview()
|
||||
{
|
||||
void SQLEditDialog::hidePreview() {
|
||||
ui->gbDataPreview->setVisible(false);
|
||||
ui->pbPreview->setText(tr("Preview"));
|
||||
ui->pbHidePreview->setVisible(false);
|
||||
}
|
||||
|
||||
void SQLEditDialog::on_pbDelField_clicked()
|
||||
{
|
||||
ui->fieldsMap->removeRow(ui->fieldsMap->currentRow());
|
||||
}
|
||||
void SQLEditDialog::on_pbDelField_clicked() { ui->fieldsMap->removeRow(ui->fieldsMap->currentRow()); }
|
||||
|
||||
} // namespace LimeReport
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -30,6 +30,7 @@ SOURCES += \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lrcontentpropitem.cpp \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lrmarginpropitem.cpp \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lrseriespropitem.cpp \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lraxispropitem.cpp \
|
||||
$$REPORT_PATH/objectinspector/editors/lrtextitempropertyeditor.cpp \
|
||||
$$REPORT_PATH/objectinspector/editors/lrcomboboxeditor.cpp \
|
||||
$$REPORT_PATH/objectinspector/editors/lrcheckboxeditor.cpp \
|
||||
@ -80,6 +81,7 @@ HEADERS += \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lrcolorpropitem.h \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lrmarginpropitem.h \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lrseriespropitem.h \
|
||||
$$REPORT_PATH/objectinspector/propertyItems/lraxispropitem.h \
|
||||
$$REPORT_PATH/objectinspector/editors/lrtextitempropertyeditor.h \
|
||||
$$REPORT_PATH/objectinspector/editors/lrcomboboxeditor.h \
|
||||
$$REPORT_PATH/objectinspector/editors/lrcheckboxeditor.h \
|
||||
|
@ -70,7 +70,12 @@ void LinesChart::drawDesignMode(QPainter* painter, qreal hStep, qreal vStep, qre
|
||||
|
||||
qreal LinesChart::calculatePos(const AxisData &data, qreal value, qreal rectSize) const
|
||||
{
|
||||
return (data.rangeMax() - value) / data.delta() * rectSize;
|
||||
if (data.type() == AxisData::XAxis || (data.reverseDirection() && data.rangeMin() >= 0)) {
|
||||
// Not flipping for minimum less than 0 because lower number is at the bottom.
|
||||
return (1 - (data.rangeMax() - value) / data.delta()) * rectSize;
|
||||
} else {
|
||||
return (data.rangeMax() - value) / data.delta() * rectSize;
|
||||
}
|
||||
}
|
||||
|
||||
void LinesChart::paintSeries(QPainter *painter, SeriesItem *series, QRectF barsRect)
|
||||
|
@ -143,7 +143,7 @@ void PieChart::paintChartLegend(QPainter *painter, QRectF legendRect)
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF PieChart::calcChartLegendSize(const QFont &font)
|
||||
QSizeF PieChart::calcChartLegendSize(const QFont &font, qreal)
|
||||
{
|
||||
QFontMetrics fm(font);
|
||||
|
||||
|
@ -8,7 +8,7 @@ namespace LimeReport{
|
||||
class PieChart : public AbstractChart{
|
||||
public:
|
||||
PieChart(ChartItem* chartItem):AbstractChart(chartItem){}
|
||||
QSizeF calcChartLegendSize(const QFont &font);
|
||||
QSizeF calcChartLegendSize(const QFont &font, qreal maxWidth = 0);
|
||||
void paintChart(QPainter *painter, QRectF chartRect);
|
||||
void paintChartLegend(QPainter *painter, QRectF legendRect);
|
||||
protected:
|
||||
|
@ -71,8 +71,6 @@ void VerticalBarChart::paintVerticalBars(QPainter *painter, QRectF barsRect)
|
||||
qreal hStep = (barsRect.width() / valuesCount()) / (barSeriesCount == 0 ? 1 : barSeriesCount);
|
||||
qreal topShift = (delta - (maxValue() - minValue())) * vStep + barsRect.top();
|
||||
|
||||
qDebug() << "vStep" << vStep << "hStep" << hStep;
|
||||
|
||||
if (!m_chartItem->series().isEmpty() && (m_chartItem->itemMode() != DesignMode)){
|
||||
int curSeries = 0;
|
||||
foreach (SeriesItem* series, m_chartItem->series()) {
|
||||
|
@ -48,7 +48,6 @@ void AbstractLayout::setLayoutType(const LayoutType& layoutType)
|
||||
|
||||
void AbstractLayout::addChild(BaseDesignIntf* item, bool updateSize)
|
||||
{
|
||||
|
||||
placeItemInLayout(item);
|
||||
|
||||
m_children.append(item);
|
||||
@ -57,22 +56,7 @@ void AbstractLayout::addChild(BaseDesignIntf* item, bool updateSize)
|
||||
item->setFixedPos(true);
|
||||
item->setPossibleResizeDirectionFlags(ResizeRight | ResizeBottom);
|
||||
|
||||
connect(
|
||||
item, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(slotOnChildDestroy(QObject*))
|
||||
);
|
||||
connect(
|
||||
item,SIGNAL(geometryChanged(QObject*,QRectF,QRectF)),
|
||||
this,SLOT(slotOnChildGeometryChanged(QObject*,QRectF,QRectF))
|
||||
);
|
||||
connect(
|
||||
item, SIGNAL(itemVisibleHasChanged(BaseDesignIntf*)),
|
||||
this, SLOT(slotOnChildVisibleHasChanged(BaseDesignIntf*))
|
||||
);
|
||||
connect(
|
||||
item, SIGNAL(itemSelectedHasBeenChanged(BaseDesignIntf*,bool)),
|
||||
this, SLOT(slotOnChildSelectionHasChanged(BaseDesignIntf*,bool))
|
||||
);
|
||||
connectToLayout(item);
|
||||
|
||||
if (updateSize){
|
||||
relocateChildren();
|
||||
@ -80,19 +64,23 @@ void AbstractLayout::addChild(BaseDesignIntf* item, bool updateSize)
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractLayout::removeChild(BaseDesignIntf *item)
|
||||
{
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
m_children.removeAll(item);
|
||||
disconnectFromLayout(item);
|
||||
}
|
||||
|
||||
void AbstractLayout::restoreChild(BaseDesignIntf* item)
|
||||
{
|
||||
if (m_children.contains(item)) return;
|
||||
|
||||
m_isRelocating=true;
|
||||
|
||||
insertItemInLayout(item);
|
||||
|
||||
connect(item,SIGNAL(destroyed(QObject*)),this,SLOT(slotOnChildDestroy(QObject*)));
|
||||
connect(item,SIGNAL(geometryChanged(QObject*,QRectF,QRectF)),
|
||||
this,SLOT(slotOnChildGeometryChanged(QObject*,QRectF,QRectF)));
|
||||
connect(item, SIGNAL(itemAlignChanged(BaseDesignIntf*,ItemAlign,ItemAlign)),
|
||||
this, SLOT(slotOnChildItemAlignChanged(BaseDesignIntf*,ItemAlign,ItemAlign)));
|
||||
connectToLayout(item);
|
||||
|
||||
item->setFixedPos(true);
|
||||
item->setPossibleResizeDirectionFlags(ResizeRight | ResizeBottom);
|
||||
@ -267,6 +255,54 @@ void AbstractLayout::rebuildChildrenIfNeeded(){
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractLayout::connectToLayout(BaseDesignIntf *item)
|
||||
{
|
||||
connect(
|
||||
item, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(slotOnChildDestroy(QObject*))
|
||||
);
|
||||
connect(
|
||||
item,SIGNAL(geometryChanged(QObject*,QRectF,QRectF)),
|
||||
this,SLOT(slotOnChildGeometryChanged(QObject*,QRectF,QRectF))
|
||||
);
|
||||
connect(
|
||||
item, SIGNAL(itemVisibleHasChanged(BaseDesignIntf*)),
|
||||
this, SLOT(slotOnChildVisibleHasChanged(BaseDesignIntf*))
|
||||
);
|
||||
connect(
|
||||
item, SIGNAL(itemSelectedHasBeenChanged(BaseDesignIntf*,bool)),
|
||||
this, SLOT(slotOnChildSelectionHasChanged(BaseDesignIntf*,bool))
|
||||
);
|
||||
connect(
|
||||
item, SIGNAL(itemAlignChanged(BaseDesignIntf*, const ItemAlign&, const ItemAlign&)),
|
||||
this, SLOT(slotOnChildItemAlignChanged(BaseDesignIntf*,const ItemAlign&,const ItemAlign&))
|
||||
);
|
||||
}
|
||||
|
||||
void AbstractLayout::disconnectFromLayout(BaseDesignIntf *item)
|
||||
{
|
||||
disconnect(
|
||||
item, SIGNAL(destroyed(QObject*)),
|
||||
this, SLOT(slotOnChildDestroy(QObject*))
|
||||
);
|
||||
disconnect(
|
||||
item,SIGNAL(geometryChanged(QObject*,QRectF,QRectF)),
|
||||
this,SLOT(slotOnChildGeometryChanged(QObject*,QRectF,QRectF))
|
||||
);
|
||||
disconnect(
|
||||
item, SIGNAL(itemVisibleHasChanged(BaseDesignIntf*)),
|
||||
this, SLOT(slotOnChildVisibleHasChanged(BaseDesignIntf*))
|
||||
);
|
||||
disconnect(
|
||||
item, SIGNAL(itemSelectedHasBeenChanged(BaseDesignIntf*,bool)),
|
||||
this, SLOT(slotOnChildSelectionHasChanged(BaseDesignIntf*,bool))
|
||||
);
|
||||
disconnect(
|
||||
item, SIGNAL(itemAlignChanged(BaseDesignIntf*, const ItemAlign&, const ItemAlign&)),
|
||||
this, SLOT(slotOnChildItemAlignChanged(BaseDesignIntf*,const ItemAlign&,const ItemAlign&))
|
||||
);
|
||||
}
|
||||
|
||||
BaseDesignIntf *AbstractLayout::findNext(BaseDesignIntf *item)
|
||||
{
|
||||
rebuildChildrenIfNeeded();
|
||||
@ -288,7 +324,7 @@ BaseDesignIntf *AbstractLayout::findPrior(BaseDesignIntf *item)
|
||||
void AbstractLayout::slotOnChildDestroy(QObject* child)
|
||||
{
|
||||
m_children.removeAll(static_cast<BaseDesignIntf*>(child));
|
||||
if (m_children.count()<2){
|
||||
if (m_children.count() < 2 && !static_cast<LayoutDesignIntf*>(child)){
|
||||
beforeDelete();
|
||||
} else {
|
||||
relocateChildren();
|
||||
@ -316,7 +352,7 @@ void AbstractLayout::slotOnChildGeometryChanged(QObject* item, QRectF newGeometr
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractLayout::slotOnChildItemAlignChanged(BaseDesignIntf* item, const BaseDesignIntf::ItemAlign&, const BaseDesignIntf::ItemAlign&)
|
||||
void AbstractLayout::slotOnChildItemAlignChanged(BaseDesignIntf* item, const ItemAlign&, const ItemAlign&)
|
||||
{
|
||||
item->setPossibleResizeDirectionFlags(ResizeBottom | ResizeRight);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ public:
|
||||
void setLayoutType(const LayoutType& layoutType);
|
||||
|
||||
void addChild(BaseDesignIntf *item,bool updateSize=true);
|
||||
void removeChild(BaseDesignIntf *item);
|
||||
void restoreChild(BaseDesignIntf *item);
|
||||
bool isEmpty() const;
|
||||
void paintChild(BaseDesignIntf* child, QPointF parentPos, QPainter* painter);
|
||||
@ -52,6 +53,8 @@ protected:
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||
void updateItemSize(DataSourceManager* dataManager, RenderPass pass, int maxHeight);
|
||||
void rebuildChildrenIfNeeded();
|
||||
void connectToLayout(BaseDesignIntf* item);
|
||||
void disconnectFromLayout(BaseDesignIntf* item);
|
||||
private:
|
||||
virtual void sortChildren() = 0;
|
||||
virtual void divideSpace() = 0;
|
||||
|
142
limereport/items/lrchartaxiseditor.cpp
Normal file
142
limereport/items/lrchartaxiseditor.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include "lrchartaxiseditor.h"
|
||||
|
||||
#include "ui_lrchartaxiseditor.h"
|
||||
#include "lraxisdata.h"
|
||||
|
||||
#include "lrbasedesignintf.h"
|
||||
|
||||
ChartAxisEditor::ChartAxisEditor(LimeReport::ChartItem *item, LimeReport::PageDesignIntf *page, bool isXAxis, QSettings *settings, QWidget *parent):
|
||||
QWidget(parent), ui(new Ui::ChartAxisEditor), m_chartItem(item), m_page(page),
|
||||
m_settings(settings), m_isXAxis(isXAxis)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
readSetting();
|
||||
init();
|
||||
}
|
||||
|
||||
ChartAxisEditor::~ChartAxisEditor()
|
||||
{
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
writeSetting();
|
||||
#endif
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QSettings* ChartAxisEditor::settings()
|
||||
{
|
||||
if (m_settings){
|
||||
return m_settings;
|
||||
}
|
||||
m_settings = new QSettings("LimeReport",QCoreApplication::applicationName());
|
||||
return m_settings;
|
||||
}
|
||||
|
||||
void ChartAxisEditor::readSetting()
|
||||
{
|
||||
if (settings() == 0) return;
|
||||
|
||||
settings()->beginGroup("ChartAxisEditor");
|
||||
QVariant v = settings()->value("Geometry");
|
||||
if (v.isValid()) {
|
||||
restoreGeometry(v.toByteArray());
|
||||
}
|
||||
|
||||
settings()->endGroup();
|
||||
}
|
||||
|
||||
void ChartAxisEditor::writeSetting()
|
||||
{
|
||||
if (settings() == 0) {
|
||||
return;
|
||||
}
|
||||
settings()->beginGroup("ChartAxisEditor");
|
||||
settings()->setValue("Geometry",saveGeometry());
|
||||
settings()->endGroup();
|
||||
}
|
||||
|
||||
void ChartAxisEditor::init()
|
||||
{
|
||||
ui->gbAxis->setTitle(m_isXAxis ? QObject::tr("X Axis") : QObject::tr("Y Axis"));
|
||||
ui->direction_checkbox->setVisible(!m_isXAxis);
|
||||
|
||||
LimeReport::AxisData *axisData = m_isXAxis ? m_chartItem->xAxisData() : m_chartItem->yAxisData();
|
||||
|
||||
ui->minimumSpinBox->setValue(axisData->manualMinimum());
|
||||
ui->maximumSpinBox->setValue(axisData->manualMaximum());
|
||||
ui->stepSpinBox->setValue(axisData->manualStep());
|
||||
|
||||
ui->minimumCheckBox->setChecked(axisData->isMinimumAutomatic());
|
||||
ui->maximumCheckBox->setChecked(axisData->isMaximumAutomatic());
|
||||
ui->stepCheckBox->setChecked(axisData->isStepAutomatic());
|
||||
|
||||
ui->direction_checkbox->setChecked(axisData->reverseDirection());
|
||||
|
||||
const bool isScaleCalcEnabled = axisData->calculateAxisScale();
|
||||
ui->enableScaleCalculation_checkbox->setChecked(isScaleCalcEnabled);
|
||||
on_enableScaleCalculation_checkbox_stateChanged(isScaleCalcEnabled);
|
||||
}
|
||||
|
||||
void ChartAxisEditor::on_minimumCheckBox_stateChanged(int arg1)
|
||||
{
|
||||
const bool isAutomatic = (bool)arg1;
|
||||
ui->minimumSpinBox->setEnabled(!isAutomatic);
|
||||
}
|
||||
|
||||
void ChartAxisEditor::on_maximumCheckBox_stateChanged(int arg1)
|
||||
{
|
||||
const bool isAutomatic = (bool)arg1;
|
||||
ui->maximumSpinBox->setEnabled(!isAutomatic);
|
||||
}
|
||||
|
||||
void ChartAxisEditor::on_stepCheckBox_stateChanged(int arg1)
|
||||
{
|
||||
const bool isAutomatic = (bool)arg1;
|
||||
ui->stepSpinBox->setEnabled(!isAutomatic);
|
||||
}
|
||||
|
||||
void ChartAxisEditor::on_pushButtonOk_clicked()
|
||||
{
|
||||
LimeReport::AxisData *axisData = m_isXAxis ? m_chartItem->xAxisData() : m_chartItem->yAxisData();
|
||||
if (!m_isXAxis) {
|
||||
axisData->setReverseDirection(ui->direction_checkbox->isChecked());
|
||||
}
|
||||
|
||||
axisData->setIsStepAutomatic(ui->stepCheckBox->isChecked());
|
||||
axisData->setManualStep(ui->stepSpinBox->value());
|
||||
axisData->setIsMinimumAutomatic(ui->minimumCheckBox->isChecked());
|
||||
axisData->setManualMinimum(ui->minimumSpinBox->value());
|
||||
axisData->setIsMaximumAutomatic(ui->maximumCheckBox->isChecked());
|
||||
axisData->setManualMaximum(ui->maximumSpinBox->value());
|
||||
|
||||
axisData->setCalculateAxisScale(ui->enableScaleCalculation_checkbox->isChecked());
|
||||
|
||||
if (m_chartItem->itemMode() == LimeReport::DesignMode) {
|
||||
axisData->updateForDesignMode();
|
||||
} else {
|
||||
axisData->update();
|
||||
}
|
||||
m_chartItem->update();
|
||||
close();
|
||||
}
|
||||
|
||||
void ChartAxisEditor::on_enableScaleCalculation_checkbox_stateChanged(int arg1)
|
||||
{
|
||||
const bool isEnabled = (bool)arg1;
|
||||
ui->minimumCheckBox->setEnabled(isEnabled);
|
||||
ui->maximumCheckBox->setEnabled(isEnabled);
|
||||
ui->stepCheckBox->setEnabled(isEnabled);
|
||||
|
||||
ui->minimumSpinBox->setEnabled(!ui->minimumCheckBox->isChecked() && isEnabled);
|
||||
ui->maximumSpinBox->setEnabled(!ui->maximumCheckBox->isChecked() && isEnabled);
|
||||
ui->stepSpinBox->setEnabled(!ui->stepCheckBox->isChecked() && isEnabled);
|
||||
|
||||
ui->minimumCheckBox->setEnabled(isEnabled);
|
||||
ui->maximumCheckBox->setEnabled(isEnabled);
|
||||
ui->stepCheckBox->setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
void ChartAxisEditor::on_cancelButton_clicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
41
limereport/items/lrchartaxiseditor.h
Normal file
41
limereport/items/lrchartaxiseditor.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef CHARTAXISEDITOR_H
|
||||
#define CHARTAXISEDITOR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "lrchartitem.h"
|
||||
|
||||
namespace Ui {
|
||||
class ChartAxisEditor;
|
||||
}
|
||||
|
||||
class ChartAxisEditor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ChartAxisEditor(LimeReport::ChartItem* item, LimeReport::PageDesignIntf* page, bool isXAxis,
|
||||
QSettings* settings=0, QWidget *parent = 0);
|
||||
~ChartAxisEditor();
|
||||
|
||||
QSettings *settings();
|
||||
private slots:
|
||||
void on_minimumCheckBox_stateChanged(int arg1);
|
||||
void on_maximumCheckBox_stateChanged(int arg1);
|
||||
void on_stepCheckBox_stateChanged(int arg1);
|
||||
void on_pushButtonOk_clicked();
|
||||
void on_enableScaleCalculation_checkbox_stateChanged(int arg1);
|
||||
|
||||
void on_cancelButton_clicked();
|
||||
|
||||
private:
|
||||
void readSetting();
|
||||
void writeSetting();
|
||||
void init();
|
||||
|
||||
Ui::ChartAxisEditor *ui;
|
||||
LimeReport::ChartItem* m_chartItem;
|
||||
LimeReport::PageDesignIntf* m_page;
|
||||
QSettings* m_settings;
|
||||
bool m_isXAxis;
|
||||
};
|
||||
|
||||
#endif // CHARTAXISEDITOR_H
|
212
limereport/items/lrchartaxiseditor.ui
Executable file
212
limereport/items/lrchartaxiseditor.ui
Executable file
@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ChartAxisEditor</class>
|
||||
<widget class="QWidget" name="ChartAxisEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>380</width>
|
||||
<height>268</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Axis editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbAxis">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Axis</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="direction_checkbox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reverse direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableScaleCalculation_checkbox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable scale calculation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="stepLabel">
|
||||
<property name="text">
|
||||
<string>Step</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="maximumLabel">
|
||||
<property name="text">
|
||||
<string>Maximum</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QDoubleSpinBox" name="minimumSpinBox">
|
||||
<property name="showGroupSeparator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="minimumLabel">
|
||||
<property name="text">
|
||||
<string>Minimum</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QCheckBox" name="stepCheckBox">
|
||||
<property name="text">
|
||||
<string>Automatic</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QCheckBox" name="minimumCheckBox">
|
||||
<property name="text">
|
||||
<string>Automatic</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QCheckBox" name="maximumCheckBox">
|
||||
<property name="text">
|
||||
<string>Automatic</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QDoubleSpinBox" name="stepSpinBox">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9999999.990000000223517</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QDoubleSpinBox" name="maximumSpinBox">
|
||||
<property name="minimum">
|
||||
<double>-9999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonOk">
|
||||
<property name="text">
|
||||
<string>Ok</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<slots>
|
||||
<slot>slotAddSeries()</slot>
|
||||
<slot>slotDeleteSeries()</slot>
|
||||
</slots>
|
||||
</ui>
|
@ -8,6 +8,7 @@
|
||||
#include "lrpagedesignintf.h"
|
||||
#include "lrreportengine_p.h"
|
||||
#include "lrdatadesignintf.h"
|
||||
#include "lrchartaxiseditor.h"
|
||||
|
||||
#include "charts/lrpiechart.h"
|
||||
#include "charts/lrverticalbarchart.h"
|
||||
@ -141,13 +142,18 @@ void SeriesItem::setPreferredType(const SeriesItemPreferredType& type)
|
||||
|
||||
ChartItem::ChartItem(QObject *owner, QGraphicsItem *parent)
|
||||
: ItemDesignIntf(xmlTag, owner, parent), m_legendBorder(true),
|
||||
m_legendAlign(LegendAlignCenter), m_titleAlign(TitleAlignCenter),
|
||||
m_legendAlign(LegendAlignRightCenter), m_titleAlign(TitleAlignCenter),
|
||||
m_chartType(Pie), m_labelsField(""), m_isEmpty(true),
|
||||
m_showLegend(true), m_drawPoints(true), m_seriesLineWidth(4),
|
||||
m_horizontalAxisOnTop(false), m_gridChartLines(AllLines)
|
||||
m_horizontalAxisOnTop(false), m_gridChartLines(AllLines),
|
||||
m_legendStyle(LegendPoints)
|
||||
{
|
||||
m_xAxisData = new AxisData(AxisData::XAxis, this);
|
||||
m_xAxisData->setReverseDirection(true);
|
||||
m_yAxisData = new AxisData(AxisData::YAxis, this);
|
||||
m_labels<<"First"<<"Second"<<"Thrid";
|
||||
m_chart = new PieChart(this);
|
||||
m_chart->setTitleFont(font());
|
||||
}
|
||||
|
||||
ChartItem::~ChartItem()
|
||||
@ -182,20 +188,36 @@ void ChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
painter->setRenderHint(QPainter::Antialiasing,true);
|
||||
painter->setRenderHint(QPainter::TextAntialiasing,true);
|
||||
qreal borderMargin = (rect().height()*0.01>10)?(10):(rect().height()*0.01);
|
||||
qreal maxTitleHeight = rect().height()*0.2;
|
||||
qreal maxTitleHeight = rect().height()*0.5;
|
||||
|
||||
QFont tmpFont = painter->font();
|
||||
|
||||
qreal titleOffset = !m_title.isEmpty()?(((painter->fontMetrics().height()+borderMargin*2)<maxTitleHeight)?
|
||||
(painter->fontMetrics().height()+borderMargin*2):
|
||||
(maxTitleHeight)):0;
|
||||
qreal titleOffset = 0;
|
||||
if (!m_title.isEmpty()) {
|
||||
QFontMetrics fm(titleFont());
|
||||
const qreal titleHeight = fm.boundingRect(rect().toRect(), Qt::TextWordWrap,chartTitle()).height() + borderMargin * 2;
|
||||
titleOffset = std::min(titleHeight, maxTitleHeight);
|
||||
}
|
||||
|
||||
QRectF titleRect = QRectF(borderMargin,borderMargin,rect().width()-borderMargin*2,titleOffset);
|
||||
QRectF legendRect = QRectF(0,0,0,0);
|
||||
if (m_showLegend)
|
||||
const QRectF titleRect = QRectF(borderMargin,borderMargin,rect().width()-borderMargin*2,titleOffset);
|
||||
QRectF legendRect = QRectF(0, 0, 0, 0);
|
||||
QRectF diagramRect = rect().adjusted(borderMargin, titleOffset + borderMargin,
|
||||
-(borderMargin * 2), -borderMargin);
|
||||
if (m_showLegend) {
|
||||
legendRect = m_chart->calcChartLegendRect(painter->font(), rect(), false, borderMargin, titleOffset);
|
||||
QRectF diagramRect = rect().adjusted(borderMargin,titleOffset+borderMargin,
|
||||
-(legendRect.width()+borderMargin*2),-borderMargin);
|
||||
switch(legendAlign()) {
|
||||
case LegendAlignRightTop:
|
||||
case LegendAlignRightBottom:
|
||||
case LegendAlignRightCenter:
|
||||
diagramRect.adjust(0, 0, -legendRect.width(), 0);
|
||||
break;
|
||||
case LegendAlignBottomLeft:
|
||||
case LegendAlignBottomCenter:
|
||||
case LegendAlignBottomRight:
|
||||
diagramRect.adjust(0, 0, 0, -(legendRect.height() + borderMargin * 2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
paintChartTitle(painter, titleRect);
|
||||
if (m_showLegend)
|
||||
@ -206,6 +228,47 @@ void ChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
ItemDesignIntf::paint(painter,option,widget);
|
||||
}
|
||||
|
||||
QObject *ChartItem::xAxisSettings()
|
||||
{
|
||||
return m_xAxisData;
|
||||
}
|
||||
|
||||
void ChartItem::setYAxisSettings(QObject *axis)
|
||||
{
|
||||
AxisData *data = dynamic_cast<AxisData*>(axis);
|
||||
if (data) {
|
||||
m_yAxisData->copy(data);
|
||||
}
|
||||
}
|
||||
|
||||
QObject *ChartItem::yAxisSettings()
|
||||
{
|
||||
return m_yAxisData;
|
||||
}
|
||||
|
||||
void ChartItem::setXAxisSettings(QObject *axis)
|
||||
{
|
||||
AxisData *data = static_cast<AxisData*>(axis);
|
||||
if (data) {
|
||||
m_xAxisData->copy(data);
|
||||
}
|
||||
}
|
||||
|
||||
AxisData *ChartItem::xAxisData()
|
||||
{
|
||||
return m_xAxisData;
|
||||
}
|
||||
|
||||
AxisData *ChartItem::yAxisData()
|
||||
{
|
||||
return m_yAxisData;
|
||||
}
|
||||
|
||||
void ChartItem::showAxisEditorDialog(bool isXAxis)
|
||||
{
|
||||
showDialog(new ChartAxisEditor(this, page(), isXAxis, settings()));
|
||||
}
|
||||
|
||||
BaseDesignIntf *ChartItem::createSameTypeItem(QObject *owner, QGraphicsItem *parent)
|
||||
{
|
||||
ChartItem* result = new ChartItem(owner,parent);
|
||||
@ -271,10 +334,7 @@ void ChartItem::fillLabels(IDataSource *dataSource)
|
||||
|
||||
QWidget *ChartItem::defaultEditor()
|
||||
{
|
||||
QSettings* l_settings = (page()->settings() != 0) ?
|
||||
page()->settings() :
|
||||
(page()->reportEditor()!=0) ? page()->reportEditor()->settings() : 0;
|
||||
QWidget* editor = new ChartItemEditor(this, page(), l_settings);
|
||||
QWidget* editor = new ChartItemEditor(this, page(), settings());
|
||||
editor->setAttribute(Qt::WA_DeleteOnClose);
|
||||
return editor;
|
||||
}
|
||||
@ -284,6 +344,18 @@ bool ChartItem::isNeedUpdateSize(RenderPass pass) const
|
||||
return pass == FirstPass && m_isEmpty;
|
||||
}
|
||||
|
||||
QSettings *ChartItem::settings()
|
||||
{
|
||||
PageDesignIntf *page = this->page();
|
||||
if (page->settings()) {
|
||||
return page->settings();
|
||||
}
|
||||
if (page->reportEditor()) {
|
||||
return page->reportEditor()->settings();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ChartItem::showLegend() const
|
||||
{
|
||||
return m_showLegend;
|
||||
@ -329,6 +401,7 @@ void ChartItem::setChartType(const ChartType &chartType)
|
||||
if (m_chartType != chartType){
|
||||
ChartType oldValue = m_chartType;
|
||||
m_chartType = chartType;
|
||||
QFont oldTitleFont = m_chart->titleFont();
|
||||
delete m_chart;
|
||||
switch (m_chartType) {
|
||||
case Pie:
|
||||
@ -347,6 +420,7 @@ void ChartItem::setChartType(const ChartType &chartType)
|
||||
m_chart = new GridLinesChart(this);
|
||||
break;
|
||||
}
|
||||
m_chart->setTitleFont(oldTitleFont);
|
||||
notify("chartType",oldValue,m_chartType);
|
||||
update();
|
||||
}
|
||||
@ -365,13 +439,16 @@ void ChartItem::setDatasource(const QString &datasource)
|
||||
void ChartItem::paintChartTitle(QPainter *painter, QRectF titleRect)
|
||||
{
|
||||
painter->save();
|
||||
QFont tmpFont = painter->font();
|
||||
QFontMetrics fm(tmpFont);
|
||||
while ((fm.height()>titleRect.height() || fm.boundingRect(m_title).width()>titleRect.width())
|
||||
&& tmpFont.pixelSize()>1) {
|
||||
QFont tmpFont = transformToSceneFont(titleFont());
|
||||
QRect titleBoundingRect = QFontMetrics(tmpFont).boundingRect(rect().toRect(), Qt::TextWordWrap, chartTitle());
|
||||
|
||||
while ((titleBoundingRect.height() > titleRect.height() || titleBoundingRect.width() > titleRect.width())
|
||||
&& tmpFont.pixelSize() > 1)
|
||||
{
|
||||
tmpFont.setPixelSize(tmpFont.pixelSize()-1);
|
||||
fm = QFontMetrics(tmpFont);
|
||||
titleBoundingRect = QFontMetrics(tmpFont).boundingRect(rect().toRect(), Qt::TextWordWrap, chartTitle());
|
||||
}
|
||||
|
||||
painter->setFont(tmpFont);
|
||||
Qt::AlignmentFlag align = Qt::AlignCenter;
|
||||
switch (m_titleAlign) {
|
||||
@ -385,7 +462,7 @@ void ChartItem::paintChartTitle(QPainter *painter, QRectF titleRect)
|
||||
align = Qt::AlignRight;
|
||||
break;
|
||||
}
|
||||
painter->drawText(titleRect, align, m_title);
|
||||
painter->drawText(titleRect, align | Qt::TextWordWrap, m_title);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
@ -405,6 +482,22 @@ void ChartItem::setLegendAlign(const LegendAlign &legendAlign)
|
||||
}
|
||||
}
|
||||
|
||||
ChartItem::LegendStyle ChartItem::legendStyle() const
|
||||
{
|
||||
return m_legendStyle;
|
||||
}
|
||||
|
||||
void ChartItem::setLegendStyle(const LegendStyle &legendStyle)
|
||||
{
|
||||
if (m_legendStyle == legendStyle) {
|
||||
return;
|
||||
}
|
||||
LegendStyle oldValue = m_legendStyle;
|
||||
m_legendStyle = legendStyle;
|
||||
notify("legendStyle", oldValue, m_legendStyle);
|
||||
update();
|
||||
}
|
||||
|
||||
bool ChartItem::drawLegendBorder() const
|
||||
{
|
||||
return m_legendBorder;
|
||||
@ -527,6 +620,33 @@ void ChartItem::setGridChartLines(GridChartLines flags)
|
||||
notify("gridChartLines",QVariant(oldValue),QVariant(flags));
|
||||
}
|
||||
|
||||
void ChartItem::setCharItemFont(QFont value)
|
||||
{
|
||||
if (font() == value) {
|
||||
return;
|
||||
}
|
||||
QFont oldValue = font();
|
||||
setFont(value);
|
||||
if (!isLoading()) update();
|
||||
notify("font",oldValue,value);
|
||||
}
|
||||
|
||||
QFont ChartItem::titleFont() const
|
||||
{
|
||||
return m_chart->titleFont();
|
||||
}
|
||||
|
||||
void ChartItem::setTitleFont(QFont value)
|
||||
{
|
||||
if (m_chart->titleFont() == value){
|
||||
return;
|
||||
}
|
||||
QFont oldValue = value;
|
||||
m_chart->setTitleFont(value);
|
||||
if (!isLoading()) update();
|
||||
notify("titleFont", oldValue, value);
|
||||
}
|
||||
|
||||
AbstractChart::AbstractChart(ChartItem *chartItem)
|
||||
:m_chartItem(chartItem)
|
||||
{
|
||||
@ -535,54 +655,110 @@ AbstractChart::AbstractChart(ChartItem *chartItem)
|
||||
|
||||
QRectF AbstractChart::calcChartLegendRect(const QFont &font, const QRectF &parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset)
|
||||
{
|
||||
QSizeF legendSize = calcChartLegendSize(font);
|
||||
const QSizeF legendSize = calcChartLegendSize(font, parentRect.width() * 0.9);
|
||||
qreal legendTopMargin = 0;
|
||||
qreal legendBottomMargin = 0;
|
||||
qreal legendLeftMargin = 0;
|
||||
|
||||
bool isVertical = true;
|
||||
switch (m_chartItem->legendAlign()) {
|
||||
case ChartItem::LegendAlignTop:
|
||||
legendTopMargin = titleOffset+borderMargin;
|
||||
legendBottomMargin = parentRect.height()-(legendSize.height()+titleOffset);
|
||||
case ChartItem::LegendAlignRightTop:
|
||||
legendTopMargin = titleOffset + borderMargin;
|
||||
legendBottomMargin = parentRect.height() - (legendSize.height() + titleOffset);
|
||||
isVertical = true;
|
||||
break;
|
||||
case ChartItem::LegendAlignCenter:
|
||||
legendTopMargin = titleOffset+(parentRect.height()-titleOffset-legendSize.height())/2;
|
||||
legendBottomMargin = (parentRect.height()-titleOffset-legendSize.height())/2;
|
||||
case ChartItem::LegendAlignRightCenter:
|
||||
legendTopMargin = titleOffset + (parentRect.height() - titleOffset - legendSize.height()) / 2;
|
||||
legendBottomMargin = (parentRect.height() - titleOffset - legendSize.height()) / 2;
|
||||
isVertical = true;
|
||||
break;
|
||||
case ChartItem::LegendAlignBottom:
|
||||
legendTopMargin = parentRect.height()-(legendSize.height()+titleOffset);
|
||||
legendBottomMargin = borderMargin;
|
||||
case ChartItem::LegendAlignRightBottom:
|
||||
legendTopMargin = parentRect.height() - (legendSize.height() + titleOffset);
|
||||
legendBottomMargin = borderMargin;
|
||||
isVertical = true;
|
||||
break;
|
||||
case ChartItem::LegendAlignBottomLeft:
|
||||
legendLeftMargin = QFontMetrics(font).height() / 2;
|
||||
isVertical = false;
|
||||
break;
|
||||
case ChartItem::LegendAlignBottomCenter:
|
||||
legendLeftMargin = (parentRect.width() - legendSize.width()) / 2;
|
||||
isVertical = false;
|
||||
break;
|
||||
case ChartItem::LegendAlignBottomRight:
|
||||
legendLeftMargin = parentRect.width() - legendSize.width() - QFontMetrics(font).height() / 2;
|
||||
isVertical = false;
|
||||
break;
|
||||
}
|
||||
|
||||
qreal rightOffset = !takeAllRect?((legendSize.width()>parentRect.width()/2-borderMargin)?
|
||||
(parentRect.width()/2):
|
||||
(parentRect.width()-legendSize.width())):0;
|
||||
if (isVertical) {
|
||||
qreal rightOffset = !takeAllRect ? ((legendSize.width() > parentRect.width() / 2 - borderMargin) ?
|
||||
(parentRect.width() / 2) :
|
||||
(parentRect.width() - legendSize.width())) : 0;
|
||||
return parentRect.adjusted(
|
||||
rightOffset,
|
||||
(legendSize.height()>(parentRect.height()-titleOffset))?(titleOffset):(legendTopMargin),
|
||||
-borderMargin,
|
||||
(legendSize.height()>(parentRect.height()-titleOffset))?(0):(-legendBottomMargin)
|
||||
);
|
||||
} else {
|
||||
const qreal verticalOffset = borderMargin * 2;
|
||||
return parentRect.adjusted(
|
||||
legendLeftMargin,
|
||||
(parentRect.height()) - (legendSize.height() + verticalOffset),
|
||||
-(parentRect.width() - (legendSize.width() + legendLeftMargin)),
|
||||
-verticalOffset
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
QRectF legendRect = parentRect.adjusted(
|
||||
rightOffset,
|
||||
(legendSize.height()>(parentRect.height()-titleOffset))?(titleOffset):(legendTopMargin),
|
||||
-borderMargin,
|
||||
(legendSize.height()>(parentRect.height()-titleOffset))?(0):(-legendBottomMargin)
|
||||
);
|
||||
|
||||
return legendRect;
|
||||
QFont AbstractChart::titleFont()
|
||||
{
|
||||
return m_titleFont;
|
||||
}
|
||||
|
||||
void AbstractChart::setTitleFont(const QFont &value)
|
||||
{
|
||||
m_titleFont = value;
|
||||
}
|
||||
|
||||
void AbstractChart::prepareLegendToPaint(QRectF &legendRect, QPainter *painter)
|
||||
{
|
||||
QFont tmpFont = painter->font();
|
||||
QSizeF legendSize = calcChartLegendSize(tmpFont);
|
||||
|
||||
if ((legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width())){
|
||||
while ( (legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width())
|
||||
&& tmpFont.pixelSize()>1)
|
||||
switch(m_chartItem->legendAlign()) {
|
||||
case ChartItem::LegendAlignBottomLeft:
|
||||
case ChartItem::LegendAlignBottomCenter:
|
||||
case ChartItem::LegendAlignBottomRight: {
|
||||
const qreal maxWidth = legendRect.width() * 0.95;
|
||||
qreal legendWidth = std::accumulate(m_legendColumnWidths.cbegin(), m_legendColumnWidths.cend(), 0.0);
|
||||
if (legendWidth < maxWidth) {
|
||||
return;
|
||||
}
|
||||
while ( (legendWidth > maxWidth) && tmpFont.pixelSize() > 1) {
|
||||
tmpFont.setPixelSize(tmpFont.pixelSize() - 1);
|
||||
calcChartLegendSize(tmpFont, legendRect.width());
|
||||
legendWidth = std::accumulate(m_legendColumnWidths.cbegin(), m_legendColumnWidths.cend(), 0.0);
|
||||
}
|
||||
painter->setFont(tmpFont);
|
||||
break;
|
||||
}
|
||||
case ChartItem::LegendAlignRightTop:
|
||||
case ChartItem::LegendAlignRightCenter:
|
||||
case ChartItem::LegendAlignRightBottom:
|
||||
QSizeF legendSize = calcChartLegendSize(tmpFont, legendRect.width());
|
||||
if ((legendSize.height() <= legendRect.height() && legendSize.width() <= legendRect.width())) {
|
||||
return;
|
||||
}
|
||||
while ((legendSize.height() > legendRect.height() || legendSize.width() > legendRect.width())
|
||||
&& tmpFont.pixelSize() > 1)
|
||||
{
|
||||
tmpFont.setPixelSize(tmpFont.pixelSize()-1);
|
||||
painter->setFont(tmpFont);
|
||||
legendSize = calcChartLegendSize(tmpFont);
|
||||
tmpFont.setPixelSize(tmpFont.pixelSize() - 1);
|
||||
legendSize = calcChartLegendSize(tmpFont, legendRect.width());
|
||||
}
|
||||
painter->setFont(tmpFont);
|
||||
legendRect = calcChartLegendRect(tmpFont, legendRect, true, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -602,56 +778,58 @@ AbstractSeriesChart::AbstractSeriesChart(ChartItem *chartItem)
|
||||
|
||||
qreal AbstractSeriesChart::maxValue()
|
||||
{
|
||||
return m_yAxisData.maxValue();
|
||||
return m_chartItem->yAxisData()->maxValue();
|
||||
}
|
||||
|
||||
qreal AbstractSeriesChart::minValue()
|
||||
{
|
||||
return m_yAxisData.minValue();
|
||||
return m_chartItem->yAxisData()->minValue();
|
||||
}
|
||||
|
||||
AxisData AbstractSeriesChart::yAxisData()
|
||||
AxisData &AbstractSeriesChart::xAxisData() const
|
||||
{
|
||||
return m_yAxisData;
|
||||
return *m_chartItem->xAxisData();
|
||||
}
|
||||
|
||||
AxisData AbstractSeriesChart::xAxisData()
|
||||
AxisData &AbstractSeriesChart::yAxisData() const
|
||||
{
|
||||
return m_xAxisData;
|
||||
return *m_chartItem->yAxisData();
|
||||
}
|
||||
|
||||
void AbstractSeriesChart::updateMinAndMaxValues()
|
||||
{
|
||||
qreal maxYValue = 0;
|
||||
qreal minYValue = 0;
|
||||
qreal maxXValue = 0;
|
||||
qreal minXValue = 0;
|
||||
if (m_chartItem->itemMode() == DesignMode) {
|
||||
maxYValue = 40;
|
||||
maxXValue = 40;
|
||||
} else {
|
||||
for (SeriesItem* series : m_chartItem->series()){
|
||||
for (qreal value : series->data()->values()){
|
||||
minYValue = std::min(minYValue, value);
|
||||
maxYValue = std::max(maxYValue, value);
|
||||
}
|
||||
if (series->data()->xAxisValues().isEmpty()) {
|
||||
// Grid plot starts from 0 on x axis so x range must be decresed by 1
|
||||
const bool startingFromZero = m_chartItem->chartType() == ChartItem::GridLines;
|
||||
const qreal valuesCount = this->valuesCount() - (startingFromZero ? 1 : 0);
|
||||
minXValue = std::min(0.0, minXValue);
|
||||
maxXValue = std::max(valuesCount, maxXValue);
|
||||
} else {
|
||||
for (qreal value : series->data()->xAxisValues()){
|
||||
minXValue = std::min(value, minXValue);
|
||||
maxXValue = std::max(value, maxXValue);
|
||||
}
|
||||
m_chartItem->xAxisData()->updateForDesignMode();
|
||||
m_chartItem->yAxisData()->updateForDesignMode();
|
||||
return;
|
||||
}
|
||||
|
||||
qreal maxYValue = 0;
|
||||
qreal minYValue = std::numeric_limits<qreal>::max();
|
||||
qreal maxXValue = 0;
|
||||
qreal minXValue = std::numeric_limits<qreal>::max();
|
||||
|
||||
for (SeriesItem* series : m_chartItem->series()){
|
||||
for (qreal value : series->data()->values()){
|
||||
minYValue = std::min(minYValue, value);
|
||||
maxYValue = std::max(maxYValue, value);
|
||||
}
|
||||
if (series->data()->xAxisValues().isEmpty()) {
|
||||
// Grid plot starts from 0 on x axis so x range must be decresed by 1
|
||||
const bool startingFromZero = m_chartItem->chartType() == ChartItem::GridLines;
|
||||
const qreal valuesCount = this->valuesCount() - (startingFromZero ? 1 : 0);
|
||||
minXValue = std::min(0.0, minXValue);
|
||||
maxXValue = std::max(valuesCount, maxXValue);
|
||||
} else {
|
||||
for (qreal value : series->data()->xAxisValues()){
|
||||
minXValue = std::min(value, minXValue);
|
||||
maxXValue = std::max(value, maxXValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_yAxisData = AxisData(minYValue, maxYValue);
|
||||
m_xAxisData = AxisData(minXValue, maxXValue);
|
||||
m_chartItem->xAxisData()->update(minXValue, maxXValue);
|
||||
m_chartItem->yAxisData()->update(minYValue, maxYValue);
|
||||
}
|
||||
|
||||
qreal AbstractSeriesChart::hPadding(QRectF chartRect)
|
||||
@ -676,28 +854,54 @@ int AbstractSeriesChart::seriesCount()
|
||||
return m_chartItem->series().count();
|
||||
}
|
||||
|
||||
QSizeF AbstractSeriesChart::calcChartLegendSize(const QFont &font)
|
||||
QSizeF AbstractSeriesChart::calcChartLegendSize(const QFont &font, const qreal maxWidth)
|
||||
{
|
||||
QFontMetrics fm(font);
|
||||
|
||||
qreal cw = 0;
|
||||
qreal maxWidth = 0;
|
||||
|
||||
if (!m_chartItem->series().isEmpty()){
|
||||
foreach(SeriesItem* series, m_chartItem->series()){
|
||||
cw += fm.height();
|
||||
if (maxWidth<fm.boundingRect(series->name()).width())
|
||||
maxWidth = fm.boundingRect(series->name()).width()+10;
|
||||
switch(m_chartItem->legendAlign()) {
|
||||
case ChartItem::LegendAlignBottomLeft:
|
||||
case ChartItem::LegendAlignBottomCenter:
|
||||
case ChartItem::LegendAlignBottomRight: {
|
||||
const qreal seriesCount = m_chartItem->series().isEmpty() ? m_designLabels.size() : m_chartItem->series().size();
|
||||
const qreal indicatorWidth = fm.height() * 1.5;
|
||||
m_legendColumnWidths.clear();
|
||||
while (!calculateLegendColumnWidths(indicatorWidth, maxWidth, fm)) {
|
||||
// Nothing to do here
|
||||
}
|
||||
} else {
|
||||
foreach(QString label, m_designLabels){
|
||||
cw += fm.height();
|
||||
if (maxWidth<fm.boundingRect(label).width())
|
||||
maxWidth = fm.boundingRect(label).width()+10;
|
||||
if (m_legendColumnWidths.isEmpty()) {
|
||||
m_legendColumnWidths.append(0);
|
||||
}
|
||||
const qreal columnCount = m_legendColumnWidths.size();
|
||||
const qreal rowCount = std::ceil(seriesCount / columnCount);
|
||||
QSizeF legendSize(std::accumulate(m_legendColumnWidths.cbegin(), m_legendColumnWidths.cend(), 0.0) + fm.height() / 2,
|
||||
(rowCount + 1) * fm.height());
|
||||
if (legendSize.width() > maxWidth) {
|
||||
legendSize.setWidth(maxWidth);
|
||||
}
|
||||
return legendSize;
|
||||
}
|
||||
cw += fm.height();
|
||||
return QSizeF(maxWidth+fm.height()*2,cw);
|
||||
default: {
|
||||
qreal cw = 0;
|
||||
qreal maxWidth = 0;
|
||||
|
||||
if (m_chartItem->series().isEmpty()) {
|
||||
foreach(QString label, m_designLabels){
|
||||
cw += fm.height();
|
||||
if (maxWidth<fm.boundingRect(label).width())
|
||||
maxWidth = fm.boundingRect(label).width()+10;
|
||||
}
|
||||
} else {
|
||||
foreach(SeriesItem* series, m_chartItem->series()){
|
||||
cw += fm.height();
|
||||
if (maxWidth<fm.boundingRect(series->name()).width())
|
||||
maxWidth = fm.boundingRect(series->name()).width()+10;
|
||||
}
|
||||
}
|
||||
cw += fm.height();
|
||||
return QSizeF(maxWidth+fm.height()*2,cw);
|
||||
}
|
||||
}
|
||||
return QSizeF();
|
||||
}
|
||||
|
||||
bool AbstractSeriesChart::verticalLabels(QPainter* painter, QRectF labelsRect)
|
||||
@ -829,7 +1033,7 @@ void AbstractSeriesChart::paintGrid(QPainter *painter, QRectF gridRect)
|
||||
painter->save();
|
||||
|
||||
const AxisData &yAxisData = this->yAxisData();
|
||||
const AxisData &xAxisData = this->xAxisData();
|
||||
AxisData &xAxisData = this->xAxisData();
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing,false);
|
||||
|
||||
@ -874,20 +1078,19 @@ void AbstractSeriesChart::paintGrid(QPainter *painter, QRectF gridRect)
|
||||
if (m_chartItem->horizontalAxisOnTop()) {
|
||||
painter->drawLine(x, gridRect.top() - gridOffset.height(),
|
||||
x, (drawFullLine ? gridRect.bottom() : gridRect.top()));
|
||||
painter->drawText(QRectF(x - painter->fontMetrics().width(text) / 2,
|
||||
painter->drawText(QRectF(x - painter->fontMetrics().boundingRect(text).width() / 2,
|
||||
gridRect.top() - (fontHeight + gridOffset.height()),
|
||||
hStep, fontHeight),
|
||||
text);
|
||||
} else {
|
||||
painter->drawLine(x, gridRect.bottom() + gridOffset.height(),
|
||||
x, (drawFullLine ? gridRect.top() : gridRect.bottom()));
|
||||
painter->drawText(QRectF(x - painter->fontMetrics().width(text) / 2,
|
||||
painter->drawText(QRectF(x - painter->fontMetrics().boundingRect(text).width() / 2,
|
||||
gridRect.bottom() + halfFontHeight * 0 + gridOffset.height(),
|
||||
hStep, fontHeight),
|
||||
text);
|
||||
}
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
@ -973,7 +1176,12 @@ QString AbstractSeriesChart::axisLabel(int i, const AxisData &axisData)
|
||||
{
|
||||
const qreal min = axisData.rangeMin();
|
||||
const qreal step = axisData.step();
|
||||
qreal value = min + i * step;
|
||||
qreal value = 0;
|
||||
if (axisData.type() == AxisData::YAxis && axisData.reverseDirection() && min >= 0) {
|
||||
value = min + (axisData.segmentCount() - i) * step;
|
||||
} else {
|
||||
value = min + i * step;
|
||||
}
|
||||
if (std::floor(step) == step) {
|
||||
return QString::number(value);
|
||||
}
|
||||
@ -981,48 +1189,128 @@ QString AbstractSeriesChart::axisLabel(int i, const AxisData &axisData)
|
||||
return QString::number(round(value * 100.0) / 100.0);
|
||||
}
|
||||
|
||||
bool AbstractSeriesChart::calculateLegendColumnWidths(qreal indicatorWidth, qreal maxWidth, const QFontMetrics &fm)
|
||||
{
|
||||
// This method is called in the loop, because to handle case when we get
|
||||
// 3 small series names in first row and then in second row small name and long name.
|
||||
// In this case we need to set maximum column count to 2 and iterate from the start to recalculate
|
||||
// all the sizes
|
||||
qreal currentRowWidth = 0;
|
||||
int currentColumn = 0;
|
||||
// During first iteration it is updated when moving to second row
|
||||
// After first iteration some column width are already calculated and are set as max,
|
||||
// because all rows need to have same column count (except last one)
|
||||
int maxColumnCount = m_legendColumnWidths.size();
|
||||
if (m_chartItem->series().isEmpty()) {
|
||||
for (int i=0 ; i < m_designLabels.size() ; ++i) {
|
||||
const qreal itemWidth = (qreal)(fm.boundingRect(m_designLabels[i]).width()) + indicatorWidth;
|
||||
if (!calculateLegendSingleColumnWidth(currentRowWidth, currentColumn, maxColumnCount, itemWidth, maxWidth)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0 ; i < m_chartItem->series().size() ; ++i) {
|
||||
SeriesItem* series = m_chartItem->series().at(i);
|
||||
const qreal itemWidth = (qreal)(fm.boundingRect(series->name()).width()) + indicatorWidth;
|
||||
if (!calculateLegendSingleColumnWidth(currentRowWidth, currentColumn, maxColumnCount, itemWidth, maxWidth)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractSeriesChart::calculateLegendSingleColumnWidth(qreal ¤tRowWidth, int ¤tColumn, int &maxColumnCount,
|
||||
const qreal itemWidth, const qreal maxRowWidth)
|
||||
{
|
||||
const bool maxColumnCountDefined = maxColumnCount > 0;
|
||||
// Check if there is enough space for current item in the row
|
||||
const bool isEnoughSpaceInRowForItem = currentRowWidth + itemWidth > maxRowWidth;
|
||||
// Check if it is last column already
|
||||
const bool lastColumnReached = (maxColumnCountDefined && currentColumn >= maxColumnCount);
|
||||
if (isEnoughSpaceInRowForItem || lastColumnReached) {
|
||||
// Move to next row
|
||||
currentColumn = 0;
|
||||
// Set column count when moving to second row (next rows cannot have more columns)
|
||||
if (!maxColumnCountDefined) {
|
||||
maxColumnCount = currentColumn + 1;
|
||||
}
|
||||
currentRowWidth = itemWidth;
|
||||
} else {
|
||||
// Add next column in the row
|
||||
currentRowWidth += itemWidth;
|
||||
}
|
||||
|
||||
// Add new column or update already existing column width
|
||||
if (currentColumn >= m_legendColumnWidths.size()) {
|
||||
// Append new column
|
||||
m_legendColumnWidths.append(itemWidth);
|
||||
} else if (m_legendColumnWidths.at(currentColumn) < itemWidth) {
|
||||
// Update size if item in column is bigger than items in same column in previous rows
|
||||
m_legendColumnWidths[currentColumn] = itemWidth;
|
||||
// After any updating column size we must recheck if all columns fit in the max row width
|
||||
qreal rowWidth = itemWidth;
|
||||
for (int c = 1 ; c < m_legendColumnWidths.size() ; c++) {
|
||||
rowWidth += m_legendColumnWidths.at(c);
|
||||
// When column widths exceed max row width remove columns at the end
|
||||
if (rowWidth > maxRowWidth) {
|
||||
m_legendColumnWidths.remove(c, m_legendColumnWidths.size() - c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Return back and re-iterate from start to make sure everything fits
|
||||
return false;
|
||||
}
|
||||
++currentColumn;
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<qreal> AbstractChart::legendColumnWidths() const
|
||||
{
|
||||
return m_legendColumnWidths;
|
||||
}
|
||||
|
||||
void AbstractBarChart::paintChartLegend(QPainter *painter, QRectF legendRect)
|
||||
{
|
||||
prepareLegendToPaint(legendRect, painter);
|
||||
int indicatorSize = painter->fontMetrics().height()/2;
|
||||
painter->setPen(Qt::black);
|
||||
painter->setRenderHint(QPainter::Antialiasing,false);
|
||||
if (m_chartItem->drawLegendBorder())
|
||||
painter->drawRect(legendRect);
|
||||
painter->setRenderHint(QPainter::Antialiasing,true);
|
||||
QRectF indicatorsRect = legendRect.adjusted(painter->fontMetrics().height()/2,painter->fontMetrics().height()/2,0,0);
|
||||
|
||||
const qreal halfFontSize = painter->fontMetrics().height() / 2;
|
||||
int indicatorSize = halfFontSize;
|
||||
const QRectF indicatorsRect = legendRect.adjusted(halfFontSize, halfFontSize, 0, 0);
|
||||
|
||||
bool isHorizontal = false;
|
||||
switch(m_chartItem->legendAlign()) {
|
||||
case ChartItem::LegendAlignBottomLeft:
|
||||
case ChartItem::LegendAlignBottomCenter:
|
||||
case ChartItem::LegendAlignBottomRight:
|
||||
isHorizontal = true;
|
||||
break;
|
||||
default:
|
||||
isHorizontal = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_chartItem->series().isEmpty()){
|
||||
qreal cw = 0;
|
||||
foreach(SeriesItem* series, m_chartItem->series()){
|
||||
QString label = series->name();
|
||||
painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label);
|
||||
painter->setBrush(series->color());
|
||||
painter->drawEllipse(
|
||||
indicatorsRect.adjusted(
|
||||
0,
|
||||
cw+indicatorSize/2,
|
||||
-(indicatorsRect.width()-indicatorSize),
|
||||
-(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2))
|
||||
)
|
||||
);
|
||||
cw += painter->fontMetrics().height();
|
||||
for (int i = 0 ; i < m_chartItem->series().size() ; ++i) {
|
||||
SeriesItem* series = m_chartItem->series().at(i);
|
||||
if (isHorizontal) {
|
||||
drawHorizontalLegendItem(painter, i, series->name(), indicatorSize, indicatorsRect, series->color());
|
||||
} else {
|
||||
drawVerticalLegendItem(painter, i, series->name(), indicatorSize, indicatorsRect, series->color());
|
||||
}
|
||||
}
|
||||
} else if (m_chartItem->itemMode() == DesignMode){
|
||||
qreal cw = 0;
|
||||
for (int i=0;i<m_designLabels.size();++i){
|
||||
QString label = m_designLabels.at(i);
|
||||
painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label);
|
||||
painter->setBrush(color_map[i]);
|
||||
painter->drawEllipse(
|
||||
indicatorsRect.adjusted(
|
||||
0,
|
||||
cw+indicatorSize/2,
|
||||
-(indicatorsRect.width()-indicatorSize),
|
||||
-(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2))
|
||||
)
|
||||
);
|
||||
cw += painter->fontMetrics().height();
|
||||
} else if (m_chartItem->itemMode() == DesignMode) {
|
||||
for (int i = 0 ; i < m_designLabels.size() ; ++i){
|
||||
if (isHorizontal) {
|
||||
drawHorizontalLegendItem(painter, i, m_designLabels.at(i), indicatorSize, indicatorsRect, color_map[i]);
|
||||
} else {
|
||||
drawVerticalLegendItem(painter, i, m_designLabels.at(i), indicatorSize, indicatorsRect, color_map[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1058,4 +1346,66 @@ QRectF AbstractBarChart::horizontalLabelsRect(QPainter *painter, QRectF labelsRe
|
||||
return labelsRect.adjusted(0, (labelsRect.height() - maxWidth), 0, 0);
|
||||
}
|
||||
|
||||
void AbstractBarChart::drawVerticalLegendItem(QPainter *painter, int i, const QString &text, int indicatorSize,
|
||||
const QRectF &indicatorsRect, const QColor &indicatorColor)
|
||||
{
|
||||
const qreal y = i * painter->fontMetrics().height();
|
||||
painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize * 1.5, y, 0, 0),text);
|
||||
switch(m_chartItem->legendStyle()) {
|
||||
case ChartItem::LegendPoints: {
|
||||
painter->setBrush(indicatorColor);
|
||||
painter->drawEllipse(
|
||||
indicatorsRect.adjusted(
|
||||
0,
|
||||
y+indicatorSize/2,
|
||||
-(indicatorsRect.width()-indicatorSize),
|
||||
-(indicatorsRect.height()-(y+indicatorSize+indicatorSize/2))
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ChartItem::LegendLines: {
|
||||
const QPen tmpPen = painter->pen();
|
||||
QPen indicatorPen(indicatorColor);
|
||||
indicatorPen.setWidth(4);
|
||||
painter->setPen(indicatorPen);
|
||||
const QPointF linePos = QPointF(indicatorsRect.left(), indicatorsRect.top() + y + painter->fontMetrics().height()/2);
|
||||
painter->drawLine(linePos, linePos + QPointF(indicatorSize, 0));
|
||||
painter->setPen(tmpPen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractBarChart::drawHorizontalLegendItem(QPainter *painter, int i, const QString &text,
|
||||
int indicatorSize, const QRectF &indicatorsRect, const QColor &indicatorColor)
|
||||
{
|
||||
const QVector<qreal> &columnWidths = legendColumnWidths();
|
||||
if (columnWidths.isEmpty())
|
||||
return;
|
||||
const int column = i % columnWidths.size();
|
||||
const int row = std::floor(i / columnWidths.size());
|
||||
const qreal halfTextSize = painter->fontMetrics().height() / 2;
|
||||
|
||||
const qreal x = indicatorsRect.x() + std::accumulate(columnWidths.cbegin(), columnWidths.cbegin() + column, 0.0);
|
||||
const qreal y = indicatorsRect.y() + (row + 1) * painter->fontMetrics().height();
|
||||
painter->drawText(QPointF(x + indicatorSize * 1.5, y), text);
|
||||
switch(m_chartItem->legendStyle()) {
|
||||
case ChartItem::LegendPoints: {
|
||||
painter->setBrush(indicatorColor);
|
||||
painter->drawEllipse(x, y - halfTextSize, indicatorSize, indicatorSize);
|
||||
break;
|
||||
}
|
||||
case ChartItem::LegendLines: {
|
||||
const QPen tmpPen = painter->pen();
|
||||
QPen indicatorPen(indicatorColor);
|
||||
indicatorPen.setWidth(4);
|
||||
painter->setPen(indicatorPen);
|
||||
painter->drawLine(x, y - halfTextSize * 0.7, x + indicatorSize, y - halfTextSize * 0.7);
|
||||
painter->setPen(tmpPen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace LimeReport
|
||||
|
@ -76,28 +76,36 @@ public:
|
||||
virtual ~AbstractChart(){}
|
||||
virtual void paintChart(QPainter *painter, QRectF rect) = 0;
|
||||
virtual void paintChartLegend(QPainter *painter, QRectF legendRect) =0;
|
||||
virtual QSizeF calcChartLegendSize(const QFont &font) = 0;
|
||||
virtual QSizeF calcChartLegendSize(const QFont &font, qreal maxWidth = 0) = 0;
|
||||
virtual QRectF calcChartLegendRect(const QFont& font, const QRectF& parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset);
|
||||
|
||||
QFont titleFont();
|
||||
void setTitleFont(const QFont &value);
|
||||
protected:
|
||||
QVector<qreal> legendColumnWidths() const;
|
||||
virtual void prepareLegendToPaint(QRectF& legendRect, QPainter *painter);
|
||||
protected:
|
||||
// Title font must be placed here instead of CharItem, becuase
|
||||
// it would cause crash when creating CharItem object on embedded
|
||||
QFont m_titleFont;
|
||||
ChartItem* m_chartItem;
|
||||
QList<QString> m_designLabels;
|
||||
QVector<qreal> m_legendColumnWidths;
|
||||
};
|
||||
|
||||
class AbstractSeriesChart: public AbstractChart{
|
||||
public:
|
||||
AbstractSeriesChart(ChartItem* chartItem);
|
||||
protected:
|
||||
AxisData yAxisData();
|
||||
AxisData xAxisData();
|
||||
AxisData &xAxisData() const;
|
||||
AxisData &yAxisData() const;
|
||||
qreal maxValue();
|
||||
qreal minValue();
|
||||
void updateMinAndMaxValues();
|
||||
int valuesCount();
|
||||
int seriesCount();
|
||||
bool verticalLabels(QPainter* painter, QRectF labelsRect);
|
||||
QSizeF calcChartLegendSize(const QFont &font);
|
||||
QSizeF calcChartLegendSize(const QFont &font, qreal maxWidth);
|
||||
qreal* designValues(){ return m_designValues;}
|
||||
virtual qreal hPadding(QRectF chartRect);
|
||||
virtual qreal vPadding(QRectF chartRect);
|
||||
@ -114,7 +122,9 @@ protected:
|
||||
virtual QString axisLabel(int i, const AxisData &axisData);
|
||||
|
||||
private:
|
||||
AxisData m_yAxisData, m_xAxisData;
|
||||
bool calculateLegendColumnWidths(qreal indicatorWidth, qreal maxWidth, const QFontMetrics &fm);
|
||||
bool calculateLegendSingleColumnWidth(qreal ¤tRowWidth, int ¤tColumn, int &maxColumnCount,
|
||||
const qreal itemWidth, const qreal maxRowWidth);
|
||||
qreal m_designValues [9];
|
||||
};
|
||||
|
||||
@ -125,20 +135,30 @@ public:
|
||||
protected:
|
||||
QRectF verticalLabelsRect(QPainter* painter, QRectF horizontalLabelsRect);
|
||||
virtual QRectF horizontalLabelsRect(QPainter* painter, QRectF horizontalLabelsRect);
|
||||
private:
|
||||
void drawVerticalLegendItem(QPainter *painter, int i, const QString &text,
|
||||
int indicatorSize, const QRectF &indicatorsRect, const QColor &indicatorColor);
|
||||
void drawHorizontalLegendItem(QPainter *painter, int i, const QString &text,
|
||||
int indicatorSize, const QRectF &indicatorsRect, const QColor &indicatorColor);
|
||||
};
|
||||
|
||||
class ChartItem : public LimeReport::ItemDesignIntf
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QObject* xAxisSettings READ xAxisSettings WRITE setXAxisSettings)
|
||||
Q_PROPERTY(QObject* yAxisSettings READ yAxisSettings WRITE setYAxisSettings)
|
||||
Q_PROPERTY(ACollectionProperty series READ fakeCollectionReader WRITE setSeries)
|
||||
Q_PROPERTY(QString datasource READ datasource WRITE setDatasource)
|
||||
Q_PROPERTY(QString chartTitle READ chartTitle WRITE setChartTitle)
|
||||
Q_PROPERTY(bool drawLegendBorder READ drawLegendBorder WRITE setDrawLegendBorder)
|
||||
Q_PROPERTY(LegendAlign legendAlign READ legendAlign WRITE setLegendAlign)
|
||||
Q_PROPERTY(LegendStyle legendStyle READ legendStyle WRITE setLegendStyle)
|
||||
Q_PROPERTY(TitleAlign titleAlign READ titleAlign WRITE setTitleAlign)
|
||||
Q_PROPERTY(ChartType chartType READ chartType WRITE setChartType)
|
||||
Q_PROPERTY(QString labelsField READ labelsField WRITE setLabelsField)
|
||||
Q_PROPERTY(bool showLegend READ showLegend WRITE setShowLegend)
|
||||
Q_PROPERTY(QFont titleFont READ titleFont WRITE setTitleFont)
|
||||
Q_PROPERTY(QFont font READ font WRITE setCharItemFont)
|
||||
|
||||
//linesChart
|
||||
Q_PROPERTY(bool drawPoints READ drawPoints WRITE setDrawPoints)
|
||||
@ -152,7 +172,8 @@ class ChartItem : public LimeReport::ItemDesignIntf
|
||||
friend class AbstractChart;
|
||||
public:
|
||||
|
||||
enum LegendAlign{LegendAlignTop,LegendAlignCenter,LegendAlignBottom};
|
||||
enum LegendAlign{LegendAlignRightTop,LegendAlignRightCenter,LegendAlignRightBottom,
|
||||
LegendAlignBottomLeft,LegendAlignBottomCenter,LegendAlignBottomRight};
|
||||
enum LegendStyle{LegendPoints, LegendLines};
|
||||
enum TitleAlign{TitleAlignLeft, TitleAlignCenter, TitleAlignRight};
|
||||
enum ChartType{Pie, VerticalBar, HorizontalBar, Lines, GridLines};
|
||||
@ -164,11 +185,13 @@ public:
|
||||
};
|
||||
#if QT_VERSION >= 0x050500
|
||||
Q_ENUM(LegendAlign)
|
||||
Q_ENUM(LegendStyle)
|
||||
Q_ENUM(TitleAlign)
|
||||
Q_ENUM(ChartType)
|
||||
Q_ENUM(LineType)
|
||||
#else
|
||||
Q_ENUMS(LegendAlign)
|
||||
Q_ENUMS(LegendStyle)
|
||||
Q_ENUMS(TitleAlign)
|
||||
Q_ENUMS(ChartType)
|
||||
Q_ENUMS(LineType)
|
||||
@ -179,6 +202,16 @@ public:
|
||||
~ChartItem();
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||
|
||||
QObject* xAxisSettings();
|
||||
void setYAxisSettings(QObject *axis);
|
||||
QObject* yAxisSettings();
|
||||
void setXAxisSettings(QObject *axis);
|
||||
|
||||
AxisData *xAxisData();
|
||||
AxisData *yAxisData();
|
||||
|
||||
void showAxisEditorDialog(bool isXAxis);
|
||||
|
||||
QList<SeriesItem *> &series();
|
||||
void setSeries(const QList<SeriesItem *> &series);
|
||||
bool isSeriesExists(const QString& name);
|
||||
@ -195,6 +228,9 @@ public:
|
||||
LegendAlign legendAlign() const;
|
||||
void setLegendAlign(const LegendAlign &legendAlign);
|
||||
|
||||
LegendStyle legendStyle() const;
|
||||
void setLegendStyle(const LegendStyle &legendStyle);
|
||||
|
||||
TitleAlign titleAlign() const;
|
||||
void setTitleAlign(const TitleAlign &titleAlign);
|
||||
|
||||
@ -226,6 +262,12 @@ public:
|
||||
GridChartLines gridChartLines() const;
|
||||
void setGridChartLines(GridChartLines flags);
|
||||
|
||||
QFont titleFont() const;
|
||||
void setTitleFont(QFont value);
|
||||
void setCharItemFont(QFont value);
|
||||
|
||||
QSettings *settings();
|
||||
|
||||
protected:
|
||||
void paintChartTitle(QPainter* painter, QRectF titleRect);
|
||||
virtual BaseDesignIntf* createSameTypeItem(QObject *owner, QGraphicsItem *parent);
|
||||
@ -257,6 +299,8 @@ private:
|
||||
QString m_xAxisField;
|
||||
bool m_horizontalAxisOnTop;
|
||||
GridChartLines m_gridChartLines;
|
||||
LegendStyle m_legendStyle;
|
||||
AxisData *m_xAxisData, *m_yAxisData;
|
||||
};
|
||||
} //namespace LimeReport
|
||||
#endif // LRCHARTITEM_H
|
||||
|
@ -295,4 +295,15 @@ void ChartItemEditor::on_xAxisFieldComboBox_currentTextChanged(const QString &ar
|
||||
{
|
||||
if (!m_initing)
|
||||
m_charItem->setXAxisField(arg1);
|
||||
}
|
||||
}
|
||||
void ChartItemEditor::on_tableWidget_itemChanged(QTableWidgetItem *item)
|
||||
{
|
||||
if (ui->seriesNameLineEdit->hasFocus())
|
||||
return;
|
||||
|
||||
const QString dataStr = item->data(Qt::DisplayRole).toString();
|
||||
if (dataStr == ui->seriesNameLineEdit->text())
|
||||
return;
|
||||
|
||||
ui->seriesNameLineEdit->setText(dataStr);
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ private slots:
|
||||
void on_labelsFieldComboBox_currentTextChanged(const QString &arg1);
|
||||
void slotChangeSeriesColor();
|
||||
void on_seriesTypeComboBox_currentIndexChanged(const QString &arg1);
|
||||
|
||||
void on_xAxisFieldComboBox_currentTextChanged(const QString &arg1);
|
||||
void on_tableWidget_itemChanged(QTableWidgetItem *item);
|
||||
|
||||
private:
|
||||
void readSetting();
|
||||
|
@ -171,9 +171,14 @@ void HorizontalLayout::updateLayoutSize()
|
||||
void HorizontalLayout::relocateChildren()
|
||||
{
|
||||
int spaceBorder = (borderLines() != 0) ? borderLineSize() : 0;
|
||||
QList<BaseDesignIntf*> newChildren;
|
||||
if (layoutsChildren().count() < childItems().size()-1){
|
||||
auto oldChildren = layoutsChildren();
|
||||
layoutsChildren().clear();
|
||||
foreach (BaseDesignIntf* item, childBaseItems()) {
|
||||
if (!oldChildren.contains(item)) {
|
||||
newChildren.append(item);
|
||||
}
|
||||
layoutsChildren().append(item);
|
||||
}
|
||||
}
|
||||
@ -188,6 +193,10 @@ void HorizontalLayout::relocateChildren()
|
||||
}
|
||||
}
|
||||
setIsRelocating(false);
|
||||
|
||||
for (BaseDesignIntf* item : newChildren) {
|
||||
connectToLayout(item);
|
||||
}
|
||||
}
|
||||
|
||||
void HorizontalLayout::divideSpace(){
|
||||
|
@ -61,8 +61,13 @@ BaseDesignIntf *ImageItem::createSameTypeItem(QObject *owner, QGraphicsItem *par
|
||||
}
|
||||
|
||||
void ImageItem::loadPictureFromVariant(QVariant& data){
|
||||
//TODO: Migrate to QMetaType
|
||||
if (data.isValid()){
|
||||
if (data.type()==QVariant::Image){
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
if (data.typeId() == QMetaType::QImage){
|
||||
#else
|
||||
if (data.type() == QVariant::Image){
|
||||
#endif
|
||||
m_picture = data.value<QImage>();
|
||||
} else {
|
||||
switch (m_format) {
|
||||
@ -178,11 +183,22 @@ void ImageItem::updateItemSize(DataSourceManager* dataManager, RenderPass pass,
|
||||
m_resourcePath = expandDataFields(m_resourcePath, NoEscapeSymbols, dataManager);
|
||||
m_picture = QImage(m_resourcePath);
|
||||
} else if (!m_variable.isEmpty()){
|
||||
//TODO: Migrate to QMetaType
|
||||
QVariant data = dataManager->variable(m_variable);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
if (data.typeId() == QMetaType::QString){
|
||||
#else
|
||||
if (data.type() == QVariant::String){
|
||||
#endif
|
||||
m_picture = QImage(data.toString());
|
||||
} else if (data.type() == QVariant::Image){
|
||||
loadPictureFromVariant(data);
|
||||
} else {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
if (data.typeId() == QMetaType::QImage){
|
||||
#else
|
||||
if (data.type() == QVariant::Image){
|
||||
#endif
|
||||
loadPictureFromVariant(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,11 +107,22 @@ void SVGItem::updateItemSize(DataSourceManager *dataManager, RenderPass pass, in
|
||||
m_resourcePath = expandDataFields(m_resourcePath, NoEscapeSymbols, dataManager);
|
||||
m_image = imageFromResource(m_resourcePath);
|
||||
} else if (!m_variable.isEmpty()){
|
||||
//TODO: Migrate to QMetaType
|
||||
QVariant data = dataManager->variable(m_variable);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
if (data.typeId() == QMetaType::QString){
|
||||
#else
|
||||
if (data.type() == QVariant::String){
|
||||
#endif
|
||||
m_image = imageFromResource(data.toString());
|
||||
} else if (data.type() == QVariant::ByteArray) {
|
||||
m_image = data.value<QByteArray>() ;
|
||||
} else {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
if (data.typeId() == QMetaType::QByteArray) {
|
||||
#else
|
||||
if (data.type() == QVariant::ByteArray) {
|
||||
#endif
|
||||
m_image = data.value<QByteArray>() ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,10 +276,6 @@ void TextItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* style, Q
|
||||
BaseDesignIntf::paint(painter, style, widget);
|
||||
}
|
||||
|
||||
QString TextItem::content() const{
|
||||
return m_strText;
|
||||
}
|
||||
|
||||
void TextItem::Init()
|
||||
{
|
||||
m_autoWidth = NoneAutoWidth;
|
||||
@ -299,14 +295,8 @@ void TextItem::setContent(const QString &value)
|
||||
{
|
||||
if (m_strText.compare(value)!=0){
|
||||
QString oldValue = m_strText;
|
||||
if (m_trimValue)
|
||||
m_strText=value.trimmed();
|
||||
else
|
||||
m_strText=value;
|
||||
|
||||
// if (itemMode() == DesignMode && (autoHeight())){
|
||||
// initTextSizes();
|
||||
// }
|
||||
m_strText = value;
|
||||
|
||||
if (!isLoading()){
|
||||
if (autoHeight() || autoWidth() || hasFollower())
|
||||
@ -317,6 +307,10 @@ void TextItem::setContent(const QString &value)
|
||||
}
|
||||
}
|
||||
|
||||
QString TextItem::content() const{
|
||||
return m_strText;
|
||||
}
|
||||
|
||||
void TextItem::updateItemSize(DataSourceManager* dataManager, RenderPass pass, int maxHeight)
|
||||
{
|
||||
|
||||
@ -493,29 +487,43 @@ QString TextItem::formatFieldValue()
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
||||
switch (value.type()) {
|
||||
case QVariant::Date:
|
||||
case QVariant::DateTime:
|
||||
return formatDateTime(value.toDateTime());
|
||||
case QVariant::Double:
|
||||
return formatNumber(value.toDouble());
|
||||
default:
|
||||
return value.toString();
|
||||
case QVariant::Date:
|
||||
case QVariant::DateTime:
|
||||
return formatDateTime(value.toDateTime());
|
||||
case QVariant::Double:
|
||||
return formatNumber(value.toDouble());
|
||||
default:
|
||||
return value.toString();
|
||||
}
|
||||
#else
|
||||
switch (value.typeId()) {
|
||||
case QMetaType::QDate:
|
||||
case QMetaType::QDateTime:
|
||||
return formatDateTime(value.toDateTime());
|
||||
case QMetaType::Double:
|
||||
return formatNumber(value.toDouble());
|
||||
default:
|
||||
return value.toString();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
TextItem::TextPtr TextItem::textDocument() const
|
||||
{
|
||||
TextPtr text(new QTextDocument);
|
||||
QString content = m_trimValue ? m_strText.trimmed() : m_strText;
|
||||
|
||||
if (allowHTML())
|
||||
if (isReplaceCarriageReturns()){
|
||||
text->setHtml(replaceReturns(m_strText));
|
||||
text->setHtml(replaceReturns(content));
|
||||
} else {
|
||||
text->setHtml(m_strText);
|
||||
text->setHtml(content);
|
||||
}
|
||||
else
|
||||
text->setPlainText(m_strText);
|
||||
text->setPlainText(content);
|
||||
|
||||
QTextOption to;
|
||||
to.setAlignment(m_alignment);
|
||||
@ -785,6 +793,7 @@ void TextItem::setTrimValue(bool value)
|
||||
{
|
||||
bool oldValue = m_trimValue;
|
||||
m_trimValue = value;
|
||||
update();
|
||||
notify("trimValue",oldValue,value);
|
||||
}
|
||||
|
||||
@ -827,7 +836,7 @@ void TextItem::expandContent(DataSourceManager* dataManager, RenderPass pass)
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 1))
|
||||
QRegExp rx(QString(Const::NAMED_VARIABLE_RX).arg(variableName));
|
||||
#else
|
||||
QRegularExpression rx(QString(Const::NAMED_VARIABLE_RX).arg(variableName));
|
||||
QRegularExpression rx = getNamedVariableRegEx(variableName);
|
||||
#endif
|
||||
if (context.contains(rx) && pass == FirstPass){
|
||||
backupContent();
|
||||
|
@ -57,9 +57,14 @@ void VerticalLayout::updateLayoutSize()
|
||||
void VerticalLayout::relocateChildren()
|
||||
{
|
||||
int spaceBorder = (borderLines() != 0) ? borderLineSize() : 0;
|
||||
QList<BaseDesignIntf*> newChildren;
|
||||
if (layoutsChildren().count() < childItems().size() - 1){
|
||||
auto oldChildren = layoutsChildren();
|
||||
layoutsChildren().clear();
|
||||
foreach (BaseDesignIntf* item, childBaseItems()) {
|
||||
if (!oldChildren.contains(item)) {
|
||||
newChildren.append(item);
|
||||
}
|
||||
layoutsChildren().append(item);
|
||||
}
|
||||
}
|
||||
@ -74,6 +79,10 @@ void VerticalLayout::relocateChildren()
|
||||
}
|
||||
}
|
||||
setIsRelocating(false);
|
||||
|
||||
for (BaseDesignIntf* item : newChildren) {
|
||||
connectToLayout(item);
|
||||
}
|
||||
}
|
||||
|
||||
bool VerticalLayout::canBeSplitted(int height) const
|
||||
|
@ -55,6 +55,7 @@ SOURCES += \
|
||||
$$REPORT_PATH/items/lrabstractlayout.cpp \
|
||||
$$REPORT_PATH/items/lrchartitem.cpp \
|
||||
$$REPORT_PATH/items/lrchartitemeditor.cpp \
|
||||
$$REPORT_PATH/items/lrchartaxiseditor.cpp \
|
||||
$$REPORT_PATH/items/charts/lrhorizontalbarchart.cpp \
|
||||
$$REPORT_PATH/items/charts/lrlineschart.cpp \
|
||||
$$REPORT_PATH/items/charts/lrgridlineschart.cpp \
|
||||
@ -148,6 +149,7 @@ HEADERS += \
|
||||
$$REPORT_PATH/items/lrabstractlayout.h \
|
||||
$$REPORT_PATH/items/lrchartitem.h \
|
||||
$$REPORT_PATH/items/lrchartitemeditor.h \
|
||||
$$REPORT_PATH/items/lrchartaxiseditor.h \
|
||||
$$REPORT_PATH/items/charts/lrhorizontalbarchart.h \
|
||||
$$REPORT_PATH/items/charts/lrlineschart.h \
|
||||
$$REPORT_PATH/items/charts/lrgridlineschart.h \
|
||||
@ -219,6 +221,7 @@ FORMS += \
|
||||
$$REPORT_PATH/lraboutdialog.ui \
|
||||
$$REPORT_PATH/lrsettingdialog.ui \
|
||||
$$REPORT_PATH/items/lrchartitemeditor.ui \
|
||||
$$REPORT_PATH/items/lrchartaxiseditor.ui \
|
||||
$$REPORT_PATH/items/lrimageitemeditor.ui \
|
||||
$$REPORT_PATH/scripteditor/lrscripteditor.ui
|
||||
|
||||
|
@ -1,21 +1,84 @@
|
||||
#include "lraxisdata.h"
|
||||
|
||||
namespace LimeReport {
|
||||
AxisData::AxisData()
|
||||
: m_rangeMin(0), m_rangeMax(0),
|
||||
m_minValue(0), m_maxValue(0), m_step(0),
|
||||
m_delta(0), m_segmentCount(4)
|
||||
{
|
||||
#include <cmath>
|
||||
#include <QDebug>
|
||||
|
||||
namespace LimeReport {
|
||||
AxisData::AxisData(AxisType type, QObject *parent)
|
||||
: QObject(parent), m_rangeMin(0), m_rangeMax(0),
|
||||
m_minValue(0), m_maxValue(0), m_step(0),
|
||||
m_delta(0), m_segmentCount(4), m_calculateAxisScale(false),
|
||||
m_reverseDirection(false), m_manualMaximum(0),
|
||||
m_manualMinimum(0), m_manualStep(0), m_isMaximumAutomatic(true),
|
||||
m_isMinimumAutomatic(true), m_isStepAutomatic(true),
|
||||
m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
AxisData::AxisData(qreal minValue, qreal maxValue)
|
||||
: AxisData()
|
||||
QString AxisData::toString() const
|
||||
{
|
||||
// Just for debug purposes
|
||||
QString str;
|
||||
QTextStream stream(&str);
|
||||
stream << "{ "
|
||||
<< "min: " << m_minValue << ", max: " << m_maxValue << ", step: " << m_step
|
||||
<< ", range min: " << m_rangeMin << ", range max: " << m_rangeMax << ", segments: " << m_segmentCount
|
||||
<< ", reverseDiection: " << m_reverseDirection << ", calculateAxisScale: " << m_calculateAxisScale
|
||||
<< ", manualMaxEnabled: " << !m_isMaximumAutomatic << ", manualMinEnabled: " << !m_isMinimumAutomatic
|
||||
<< ", manualStepEnabled: " << !m_isStepAutomatic << ", manualMax: " << m_manualMaximum
|
||||
<< ", manualMin: " << m_manualMinimum << ", manualStep: " << m_manualStep
|
||||
<< " }";
|
||||
return str;
|
||||
}
|
||||
|
||||
void AxisData::copy(AxisData *other)
|
||||
{
|
||||
m_calculateAxisScale = other->calculateAxisScale();
|
||||
m_reverseDirection = other->reverseDirection();
|
||||
m_manualMaximum = other->manualMaximum();
|
||||
m_manualMinimum = other->manualMinimum();
|
||||
m_manualStep = other->manualStep();
|
||||
m_isMaximumAutomatic = other->isMaximumAutomatic();
|
||||
m_isMinimumAutomatic = other->isMinimumAutomatic();
|
||||
m_isStepAutomatic = other->isStepAutomatic();
|
||||
}
|
||||
|
||||
void AxisData::update()
|
||||
{
|
||||
if (m_calculateAxisScale) {
|
||||
calculateRoundedAxisScale();
|
||||
} else {
|
||||
calculateSimpleAxisScale();
|
||||
}
|
||||
m_delta = m_step * m_segmentCount;
|
||||
|
||||
// Update manual values if they are automatic
|
||||
if (m_isStepAutomatic) {
|
||||
m_manualStep = m_step;
|
||||
}
|
||||
if (m_isMinimumAutomatic) {
|
||||
m_manualMinimum = m_rangeMin;
|
||||
}
|
||||
if (m_isMaximumAutomatic) {
|
||||
m_manualMaximum = m_rangeMax;
|
||||
}
|
||||
}
|
||||
|
||||
void AxisData::update(qreal minValue, qreal maxValue)
|
||||
{
|
||||
m_minValue = minValue;
|
||||
m_maxValue = maxValue;
|
||||
calculateValuesAboveMax(minValue, maxValue, 4);
|
||||
m_delta = m_step * m_segmentCount;
|
||||
update();
|
||||
}
|
||||
|
||||
void AxisData::updateForDesignMode()
|
||||
{
|
||||
m_minValue = 0;
|
||||
m_maxValue = 40;
|
||||
const bool tmp = m_calculateAxisScale;
|
||||
m_calculateAxisScale = false;
|
||||
update();
|
||||
m_calculateAxisScale = tmp;
|
||||
}
|
||||
|
||||
int AxisData::segmentCount() const
|
||||
@ -23,6 +86,11 @@ int AxisData::segmentCount() const
|
||||
return m_segmentCount;
|
||||
}
|
||||
|
||||
bool AxisData::calculateAxisScale() const
|
||||
{
|
||||
return m_calculateAxisScale;
|
||||
}
|
||||
|
||||
qreal AxisData::rangeMin() const
|
||||
{
|
||||
return m_rangeMin;
|
||||
@ -53,16 +121,229 @@ qreal AxisData::delta() const
|
||||
return m_delta;
|
||||
}
|
||||
|
||||
void AxisData::calculateValuesAboveMax(qreal minValue, qreal maxValue, int segments)
|
||||
void AxisData::calculateRoundedAxisScale()
|
||||
{
|
||||
const int delta = maxValue - minValue;
|
||||
const int maximumSegmentCount = 10;
|
||||
|
||||
bool calculateStep = isStepAutomatic();
|
||||
const bool calculateMinimum = isMinimumAutomatic();
|
||||
const bool calculateMaximum = isMaximumAutomatic();
|
||||
|
||||
qreal temporaryMin = 0;
|
||||
qreal temporaryMax = 0;
|
||||
if (calculateMinimum) {
|
||||
temporaryMin = qMin(0.0, minValue());
|
||||
} else {
|
||||
temporaryMin = qMin(manualMinimum(), minValue());
|
||||
}
|
||||
if (calculateMaximum) {
|
||||
temporaryMax = maxValue();
|
||||
} else {
|
||||
temporaryMax = qMax(manualMaximum(), maxValue());
|
||||
}
|
||||
m_step = calculateStep ? 0 : manualStep();
|
||||
|
||||
if (temporaryMax == temporaryMin) {
|
||||
if (temporaryMax == 0) {
|
||||
temporaryMax = 1;
|
||||
} else {
|
||||
temporaryMax *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
const qreal minAndMaxSpacingOffset = 0.95;
|
||||
|
||||
qreal stepMagnitude = 0.0;
|
||||
qreal normalizedStep = 0.0;
|
||||
bool isStepNormalized = false;
|
||||
bool isLoopFinished = false;
|
||||
|
||||
// Calculate until segment count is below maximum
|
||||
while( !isLoopFinished ) {
|
||||
if (calculateStep) {
|
||||
if(isStepNormalized) {
|
||||
if( normalizedStep == 1.0 ) {
|
||||
normalizedStep = 2.0;
|
||||
} else if( normalizedStep == 2.0 ) {
|
||||
normalizedStep = 5.0;
|
||||
} else {
|
||||
normalizedStep = 1.0;
|
||||
stepMagnitude *= 10;
|
||||
}
|
||||
} else {
|
||||
const double startingStep = (temporaryMax - temporaryMin) / maximumSegmentCount;
|
||||
const int exponent = static_cast< int >( floor( log10( startingStep ) ) );
|
||||
stepMagnitude = pow(10.0, static_cast<double>(exponent));
|
||||
normalizedStep = startingStep / stepMagnitude;
|
||||
if( normalizedStep <= 1.0 ) {
|
||||
normalizedStep = 1.0;
|
||||
} else if( normalizedStep <= 2.0 ) {
|
||||
normalizedStep = 2.0;
|
||||
} else if( normalizedStep <= 5.0 ) {
|
||||
normalizedStep = 5.0;
|
||||
} else {
|
||||
normalizedStep = 1.0;
|
||||
stepMagnitude *= 10;
|
||||
}
|
||||
isStepNormalized = true;
|
||||
}
|
||||
m_step = normalizedStep * stepMagnitude;
|
||||
}
|
||||
|
||||
qreal currentAxisMinimum = temporaryMin;
|
||||
qreal currentAxisMaximum = temporaryMax;
|
||||
|
||||
if (calculateMinimum) {
|
||||
currentAxisMinimum = calculateNewMinimum(currentAxisMinimum, m_step);
|
||||
const qreal currentDelta = currentAxisMaximum - currentAxisMinimum;
|
||||
const qreal actualDelta = currentAxisMaximum - minValue();
|
||||
if ((currentAxisMinimum != 0.0) && ((actualDelta / currentDelta) > minAndMaxSpacingOffset)) {
|
||||
currentAxisMinimum -= m_step;
|
||||
}
|
||||
}
|
||||
|
||||
if (calculateMaximum) {
|
||||
currentAxisMaximum = calculateNewMaximum(currentAxisMaximum, m_step);
|
||||
const qreal currentDelta = currentAxisMaximum - currentAxisMinimum;
|
||||
const qreal actualDelta = maxValue() - currentAxisMinimum;
|
||||
if ((currentAxisMaximum != 0.0) && ((actualDelta / currentDelta) > minAndMaxSpacingOffset)) {
|
||||
currentAxisMaximum += m_step;
|
||||
}
|
||||
}
|
||||
|
||||
m_segmentCount = static_cast<int>(round((currentAxisMaximum - currentAxisMinimum) / m_step));
|
||||
m_rangeMin = currentAxisMinimum;
|
||||
m_rangeMax = currentAxisMaximum;
|
||||
// Check also if step is correctly calucalted. It is possible for float steps that
|
||||
// there might be a difference. Recalculate the step in that case.
|
||||
const qreal tmpStep = (m_rangeMax - m_rangeMin) / m_segmentCount;
|
||||
isLoopFinished = m_segmentCount <= maximumSegmentCount && qFuzzyCompare(tmpStep, m_step);
|
||||
if (!isLoopFinished) {
|
||||
// Configured step may be invalid, calculating it automatically
|
||||
calculateStep = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AxisData::calculateSimpleAxisScale()
|
||||
{
|
||||
qreal min = 0;
|
||||
if (m_minValue < 0) {
|
||||
min = minValue();
|
||||
}
|
||||
m_segmentCount = 4;
|
||||
const int delta = maxValue() - min;
|
||||
int max = delta;
|
||||
while (max % segments != 0){
|
||||
while (max % m_segmentCount != 0){
|
||||
max++;
|
||||
}
|
||||
m_rangeMax = max;
|
||||
m_step = max / segments;
|
||||
m_rangeMin = minValue;
|
||||
m_segmentCount = segments;
|
||||
m_rangeMax = minValue() + max;
|
||||
m_step = max / m_segmentCount;
|
||||
m_rangeMin = minValue();
|
||||
}
|
||||
|
||||
double AxisData::calculateNewMinimum(qreal min, qreal step) const
|
||||
{
|
||||
if (step <= 0.0)
|
||||
return min;
|
||||
|
||||
double ret = floor(min / step) * step;
|
||||
if (ret > min && !qFuzzyCompare(ret, min)) {
|
||||
ret -= step;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
double AxisData::calculateNewMaximum(qreal max, qreal step) const
|
||||
{
|
||||
if (step <= 0.0)
|
||||
return max;
|
||||
|
||||
double ret = floor(max / step) * step;
|
||||
if (ret < max && !qFuzzyCompare(ret, max)) {
|
||||
ret += step;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AxisData::setCalculateAxisScale(bool newCalculateAxisScale)
|
||||
{
|
||||
m_calculateAxisScale = newCalculateAxisScale;
|
||||
}
|
||||
|
||||
bool AxisData::reverseDirection() const
|
||||
{
|
||||
return m_reverseDirection;
|
||||
}
|
||||
|
||||
void AxisData::setReverseDirection(bool reverseDirection)
|
||||
{
|
||||
m_reverseDirection = reverseDirection;
|
||||
}
|
||||
|
||||
qreal AxisData::manualMaximum() const
|
||||
{
|
||||
return m_manualMaximum;
|
||||
}
|
||||
|
||||
void AxisData::setManualMaximum(qreal newManualMaximum)
|
||||
{
|
||||
m_manualMaximum = newManualMaximum;
|
||||
}
|
||||
|
||||
qreal AxisData::manualMinimum() const
|
||||
{
|
||||
return m_manualMinimum;
|
||||
}
|
||||
|
||||
void AxisData::setManualMinimum(qreal newManualMinimum)
|
||||
{
|
||||
m_manualMinimum = newManualMinimum;
|
||||
}
|
||||
|
||||
qreal AxisData::manualStep() const
|
||||
{
|
||||
return m_manualStep;
|
||||
}
|
||||
|
||||
void AxisData::setManualStep(qreal newManualStep)
|
||||
{
|
||||
m_manualStep = newManualStep;
|
||||
}
|
||||
|
||||
bool AxisData::isMaximumAutomatic() const
|
||||
{
|
||||
return m_isMaximumAutomatic;
|
||||
}
|
||||
|
||||
void AxisData::setIsMaximumAutomatic(bool newIsMaximumAutomatic)
|
||||
{
|
||||
m_isMaximumAutomatic = newIsMaximumAutomatic;
|
||||
}
|
||||
|
||||
bool AxisData::isMinimumAutomatic() const
|
||||
{
|
||||
return m_isMinimumAutomatic;
|
||||
}
|
||||
|
||||
void AxisData::setIsMinimumAutomatic(bool newIsMinimumAutomatic)
|
||||
{
|
||||
m_isMinimumAutomatic = newIsMinimumAutomatic;
|
||||
}
|
||||
|
||||
bool AxisData::isStepAutomatic() const
|
||||
{
|
||||
return m_isStepAutomatic;
|
||||
}
|
||||
|
||||
void AxisData::setIsStepAutomatic(bool newIsStepAutomatic)
|
||||
{
|
||||
m_isStepAutomatic = newIsStepAutomatic;
|
||||
}
|
||||
|
||||
AxisData::AxisType AxisData::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,33 @@
|
||||
#ifndef AXISDATA_H
|
||||
#define AXISDATA_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
|
||||
namespace LimeReport {
|
||||
class AxisData
|
||||
class AxisData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool reverseDirection READ reverseDirection WRITE setReverseDirection)
|
||||
Q_PROPERTY(bool calculateAxisScale READ calculateAxisScale WRITE setCalculateAxisScale)
|
||||
Q_PROPERTY(bool isStepAutomatic READ isStepAutomatic WRITE setIsStepAutomatic)
|
||||
Q_PROPERTY(bool isMinimumAutomatic READ isMinimumAutomatic WRITE setIsMinimumAutomatic)
|
||||
Q_PROPERTY(bool isMaximumAutomatic READ isMaximumAutomatic WRITE setIsMaximumAutomatic)
|
||||
Q_PROPERTY(qreal manualStep READ manualStep WRITE setManualStep)
|
||||
Q_PROPERTY(qreal manualMinimum READ manualMinimum WRITE setManualMinimum)
|
||||
Q_PROPERTY(qreal manualMaximum READ manualMaximum WRITE setManualMaximum)
|
||||
public:
|
||||
AxisData();
|
||||
AxisData(qreal minValue, qreal maxValue);
|
||||
enum AxisType {
|
||||
YAxis = 0,
|
||||
XAxis = 1
|
||||
};
|
||||
|
||||
AxisData(AxisType type, QObject *parent = nullptr);
|
||||
|
||||
QString toString() const;
|
||||
void copy(AxisData *other);
|
||||
void update();
|
||||
void update(qreal minValue, qreal maxValue);
|
||||
void updateForDesignMode();
|
||||
|
||||
int segmentCount() const;
|
||||
|
||||
@ -21,8 +40,36 @@ public:
|
||||
|
||||
qreal delta() const;
|
||||
|
||||
bool reverseDirection() const;
|
||||
void setReverseDirection(bool newReverseDirection);
|
||||
bool calculateAxisScale() const;
|
||||
void setCalculateAxisScale(bool newCalculateAxisScale);
|
||||
|
||||
qreal manualMaximum() const;
|
||||
void setManualMaximum(qreal newManualMaximum);
|
||||
|
||||
qreal manualMinimum() const;
|
||||
void setManualMinimum(qreal newManualMinimum);
|
||||
|
||||
qreal manualStep() const;
|
||||
void setManualStep(qreal newManualStep);
|
||||
|
||||
bool isMaximumAutomatic() const;
|
||||
void setIsMaximumAutomatic(bool newIsMaximumAutomatic);
|
||||
|
||||
bool isMinimumAutomatic() const;
|
||||
void setIsMinimumAutomatic(bool newIsMinimumAutomatic);
|
||||
|
||||
bool isStepAutomatic() const;
|
||||
void setIsStepAutomatic(bool newIsStepAutomatic);
|
||||
|
||||
AxisType type() const;
|
||||
|
||||
private:
|
||||
void calculateValuesAboveMax(qreal minValue, qreal maxValue, int segments);
|
||||
void calculateRoundedAxisScale();
|
||||
void calculateSimpleAxisScale();
|
||||
qreal calculateNewMinimum(qreal min, qreal step) const;
|
||||
qreal calculateNewMaximum(qreal max, qreal step) const;
|
||||
|
||||
qreal m_rangeMin;
|
||||
qreal m_rangeMax;
|
||||
@ -31,6 +78,15 @@ private:
|
||||
qreal m_step;
|
||||
qreal m_delta;
|
||||
int m_segmentCount;
|
||||
bool m_calculateAxisScale;
|
||||
bool m_reverseDirection;
|
||||
qreal m_manualMaximum;
|
||||
qreal m_manualMinimum;
|
||||
qreal m_manualStep;
|
||||
bool m_isMaximumAutomatic;
|
||||
bool m_isMinimumAutomatic;
|
||||
bool m_isStepAutomatic;
|
||||
const AxisType m_type;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -261,7 +261,6 @@ public:
|
||||
void setAlternateBackgroundColor(const QColor &alternateBackgroundColor);
|
||||
bool useAlternateBackgroundColor() const;
|
||||
void setUseAlternateBackgroundColor(bool useAlternateBackgroundColor);
|
||||
void replaceGroupsFunction(BandDesignIntf *band);
|
||||
qreal bottomSpace() const;
|
||||
void setBackgroundModeProperty(BGMode value);
|
||||
void setBackgroundOpacity(int value);
|
||||
|
@ -1290,32 +1290,41 @@ void BaseDesignIntf::setItemPos(const QPointF &newPos)
|
||||
}
|
||||
|
||||
|
||||
QWidget* findRootWidget(QWidget* widget){
|
||||
QWidget* BaseDesignIntf::findRootWidget(QWidget* widget)
|
||||
{
|
||||
while (widget->parentWidget()) {
|
||||
widget = widget->parentWidget();
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
void BaseDesignIntf::showEditorDialog(){
|
||||
QWidget *editor = defaultEditor();
|
||||
if (editor) {
|
||||
editor->setStyleSheet(findRootWidget(scene()->views().at(0))->styleSheet());
|
||||
QDialog* dialog = new QDialog(QApplication::activeWindow());
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
#ifdef Q_OS_MAC
|
||||
dialog->setWindowModality(Qt::WindowModal);
|
||||
#else
|
||||
dialog->setWindowModality(Qt::ApplicationModal);
|
||||
#endif
|
||||
dialog->setLayout(new QVBoxLayout());
|
||||
dialog->resize(editor->size());
|
||||
dialog->layout()->setContentsMargins(2,2,2,2);
|
||||
dialog->layout()->addWidget(editor);
|
||||
connect(editor,SIGNAL(destroyed()),dialog,SLOT(close()));
|
||||
dialog->setWindowTitle(editor->windowTitle());
|
||||
dialog->exec();
|
||||
void BaseDesignIntf::showDialog(QWidget *widget)
|
||||
{
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
widget->setStyleSheet(findRootWidget(scene()->views().at(0))->styleSheet());
|
||||
QDialog *dialog = new QDialog(QApplication::activeWindow());
|
||||
widget->setParent(dialog);
|
||||
widget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
#ifdef Q_OS_MAC
|
||||
dialog->setWindowModality(Qt::WindowModal);
|
||||
#else
|
||||
dialog->setWindowModality(Qt::ApplicationModal);
|
||||
#endif
|
||||
dialog->setLayout(new QVBoxLayout());
|
||||
dialog->resize(widget->size());
|
||||
dialog->layout()->setContentsMargins(2,2,2,2);
|
||||
dialog->layout()->addWidget(widget);
|
||||
connect(widget,SIGNAL(destroyed()),dialog,SLOT(close()));
|
||||
dialog->setWindowTitle(widget->windowTitle());
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void BaseDesignIntf::showEditorDialog()
|
||||
{
|
||||
showDialog(defaultEditor());
|
||||
}
|
||||
|
||||
void BaseDesignIntf::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
@ -1340,18 +1349,27 @@ void BaseDesignIntf::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
|
||||
|
||||
QAction* lockGeometryAction = menu.addAction(tr("Lock item geometry"));
|
||||
lockGeometryAction->setCheckable(true);
|
||||
lockGeometryAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
|
||||
|
||||
lockGeometryAction->setChecked(isGeometryLocked());
|
||||
menu.addSeparator();
|
||||
|
||||
QAction* copyAction = menu.addAction(QIcon(":/report/images/copy"), tr("Copy"));
|
||||
copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
|
||||
QAction* cutAction = menu.addAction(QIcon(":/report/images/cut"), tr("Cut"));
|
||||
cutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X));
|
||||
QAction* cutAction = menu.addAction(QIcon(":/report/images/cut"), tr("Cut"));
|
||||
QAction* pasteAction = menu.addAction(QIcon(":/report/images/paste"), tr("Paste"));
|
||||
pasteAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V));
|
||||
pasteAction->setEnabled(false);
|
||||
|
||||
#if QT_VERSION >=QT_VERSION_CHECK(5,0,0)
|
||||
lockGeometryAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_L));
|
||||
copyAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C));
|
||||
cutAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_X));
|
||||
pasteAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_V));
|
||||
#else
|
||||
lockGeometryAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
|
||||
copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
|
||||
cutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X));
|
||||
pasteAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V));
|
||||
#endif
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
ItemsReaderIntf::Ptr reader = StringXMLreader::create(clipboard->text());
|
||||
if (reader->first() && reader->itemType() == "Object"){
|
||||
|
@ -397,6 +397,9 @@ protected:
|
||||
qreal calcAbsolutePosY(qreal currentOffset, BaseDesignIntf* item);
|
||||
qreal calcAbsolutePosX(qreal currentOffset, BaseDesignIntf* item);
|
||||
|
||||
QWidget* findRootWidget(QWidget* widget);
|
||||
void showDialog(QWidget *widget);
|
||||
|
||||
private:
|
||||
int resizeDirectionFlags(QPointF position);
|
||||
void moveSelectedItems(QPointF delta);
|
||||
@ -480,7 +483,7 @@ signals:
|
||||
void propertyChanged(const QString& propertName, const QVariant& oldValue,const QVariant& newValue);
|
||||
void propertyObjectNameChanged(const QString& oldValue, const QString& newValue);
|
||||
void propertyesChanged(QVector<QString> propertyNames);
|
||||
void itemAlignChanged(BaseDesignIntf* item, const BaseDesignIntf::ItemAlign& oldValue, const BaseDesignIntf::ItemAlign& newValue);
|
||||
void itemAlignChanged(BaseDesignIntf* item, const ItemAlign& oldValue, const ItemAlign& newValue);
|
||||
void itemVisibleHasChanged(BaseDesignIntf* item);
|
||||
void beforeRender();
|
||||
void afterData();
|
||||
|
@ -85,7 +85,12 @@ bool QueryHolder::runQuery(IDataSource::DatasourceMode mode)
|
||||
query.exec();
|
||||
|
||||
QSqlQueryModel *model = new QSqlQueryModel;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
|
||||
model->setQuery(std::move(query));
|
||||
#else
|
||||
model->setQuery(query);
|
||||
#endif
|
||||
|
||||
while (model->canFetchMore())
|
||||
model->fetchMore();
|
||||
|
@ -392,7 +392,13 @@ QSharedPointer<QAbstractItemModel>DataSourceManager::previewSQL(const QString &c
|
||||
}
|
||||
|
||||
query.exec();
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
|
||||
model->setQuery(std::move(query));
|
||||
#else
|
||||
model->setQuery(query);
|
||||
#endif
|
||||
|
||||
m_lastError = model->lastError().text();
|
||||
putError(m_lastError);
|
||||
if (model->query().isActive())
|
||||
@ -423,8 +429,8 @@ QString DataSourceManager::extractField(QString source)
|
||||
}
|
||||
|
||||
QString DataSourceManager::replaceVariables(QString value){
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
QRegularExpression rx(Const::VARIABLE_RX);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression rx = getVariableRegEx();
|
||||
QRegularExpressionMatchIterator iter = rx.globalMatch(value);
|
||||
qsizetype pos = 0;
|
||||
QString result;
|
||||
@ -443,7 +449,6 @@ QString DataSourceManager::replaceVariables(QString value){
|
||||
}
|
||||
result += value.mid(pos);
|
||||
return result;
|
||||
// TODO: Qt6 port - done
|
||||
#else
|
||||
QRegExp rx(Const::VARIABLE_RX);
|
||||
|
||||
@ -468,8 +473,8 @@ QString DataSourceManager::replaceVariables(QString value){
|
||||
|
||||
QString DataSourceManager::replaceVariables(QString query, QMap<QString,QString> &aliasesToParam)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
QRegularExpression rx(Const::VARIABLE_RX);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression rx = getVariableRegEx();
|
||||
int curentAliasIndex = 0;
|
||||
if (query.contains(rx)){
|
||||
int pos = -1;
|
||||
@ -508,7 +513,6 @@ QString DataSourceManager::replaceVariables(QString query, QMap<QString,QString>
|
||||
match = rx.match(query);
|
||||
}
|
||||
}
|
||||
// TODO: Qt6 port - done
|
||||
#else
|
||||
QRegExp rx(Const::VARIABLE_RX);
|
||||
int curentAliasIndex = 0;
|
||||
@ -553,9 +557,8 @@ QString DataSourceManager::replaceVariables(QString query, QMap<QString,QString>
|
||||
|
||||
QString DataSourceManager::replaceFields(QString query, QMap<QString,QString> &aliasesToParam, QString masterDatasource)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
|
||||
QRegularExpression rx(Const::FIELD_RX);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression rx = getFieldRegEx();
|
||||
int curentAliasIndex = 0;
|
||||
if (query.contains(rx)){
|
||||
int pos = -1;
|
||||
@ -583,7 +586,6 @@ QString DataSourceManager::replaceFields(QString query, QMap<QString,QString> &a
|
||||
match = rx.match(query);
|
||||
}
|
||||
}
|
||||
// TODO: Qt6 port - done
|
||||
#else
|
||||
QRegExp rx(Const::FIELD_RX);
|
||||
if (query.contains(rx)){
|
||||
@ -1498,7 +1500,7 @@ void DataSourceManager::invalidateQueriesContainsVariable(const QString& variabl
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 1))
|
||||
QRegExp rx(QString(Const::NAMED_VARIABLE_RX).arg(variableName));
|
||||
#else
|
||||
QRegularExpression rx(QString(Const::NAMED_VARIABLE_RX).arg(variableName));
|
||||
QRegularExpression rx = getNamedVariableRegEx(variableName);
|
||||
#endif
|
||||
if (holder->queryText().contains(rx)){
|
||||
holder->invalidate(designTime() ? IDataSource::DESIGN_MODE : IDataSource::RENDER_MODE);
|
||||
|
@ -169,7 +169,7 @@ void initReportItems(){
|
||||
|
||||
#ifdef HAVE_SVG
|
||||
DesignElementsFactory::instance().registerCreator(
|
||||
"BarcodeItem",
|
||||
"SVGItem",
|
||||
LimeReport::ItemAttribs(QObject::tr("SVG Item"),"Item"),
|
||||
createSVGItem
|
||||
);
|
||||
|
@ -67,7 +67,7 @@ QString replaceHTMLSymbols(const QString &value)
|
||||
return result;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QVector<QString> normalizeCaptures(const QRegularExpressionMatch& reg){
|
||||
#else
|
||||
QVector<QString> normalizeCaptures(const QRegExp& reg){
|
||||
@ -93,4 +93,53 @@ ReportError::ReportError(const QString& message):std::runtime_error(message.toSt
|
||||
IExternalPainter::~IExternalPainter(){}
|
||||
IPainterProxy::~IPainterProxy(){}
|
||||
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression getRegEx(QString expression){
|
||||
return QRegularExpression(expression, QRegularExpression::DotMatchesEverythingOption);
|
||||
}
|
||||
QRegularExpression getVariableRegEx(){
|
||||
return QRegularExpression(
|
||||
Const::VARIABLE_RX,
|
||||
QRegularExpression::DotMatchesEverythingOption |
|
||||
QRegularExpression::CaseInsensitiveOption
|
||||
);
|
||||
}
|
||||
QRegularExpression getFieldRegEx(){
|
||||
return QRegularExpression(
|
||||
Const::FIELD_RX,
|
||||
QRegularExpression::DotMatchesEverythingOption |
|
||||
QRegularExpression::CaseInsensitiveOption
|
||||
);
|
||||
}
|
||||
QRegularExpression getScriptRegEx(){
|
||||
return QRegularExpression(
|
||||
Const::SCRIPT_RX,
|
||||
QRegularExpression::DotMatchesEverythingOption |
|
||||
QRegularExpression::CaseInsensitiveOption
|
||||
);
|
||||
}
|
||||
QRegularExpression getGroupFunctionRegEx(QString functionName){
|
||||
return QRegularExpression(
|
||||
QString(Const::GROUP_FUNCTION_RX).arg(functionName),
|
||||
QRegularExpression::DotMatchesEverythingOption |
|
||||
QRegularExpression::InvertedGreedinessOption
|
||||
);
|
||||
}
|
||||
QRegularExpression getGroupFunctionNameRegEx(QString functionName){
|
||||
return QRegularExpression(
|
||||
QString(Const::GROUP_FUNCTION_NAME_RX).arg(functionName),
|
||||
QRegularExpression::DotMatchesEverythingOption |
|
||||
QRegularExpression::InvertedGreedinessOption
|
||||
);
|
||||
}
|
||||
QRegularExpression getNamedVariableRegEx(QString variableName){
|
||||
return QRegularExpression(
|
||||
QString(Const::NAMED_VARIABLE_RX).arg(variableName),
|
||||
QRegularExpression::DotMatchesEverythingOption
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
} //namespace LimeReport
|
||||
|
@ -104,7 +104,7 @@ namespace Const{
|
||||
QString extractClassName(QString className);
|
||||
QString escapeSimbols(const QString& value);
|
||||
QString replaceHTMLSymbols(const QString &value);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QVector<QString> normalizeCaptures(const QRegularExpressionMatch ®);
|
||||
#else
|
||||
QVector<QString> normalizeCaptures(const QRegExp ®);
|
||||
@ -157,6 +157,16 @@ namespace Const{
|
||||
#else
|
||||
typedef QStyleOptionViewItem StyleOptionViewItem;
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression getRegEx(QString expression);
|
||||
QRegularExpression getVariableRegEx();
|
||||
QRegularExpression getFieldRegEx();
|
||||
QRegularExpression getScriptRegEx();
|
||||
QRegularExpression getGroupFunctionRegEx(QString functionName);
|
||||
QRegularExpression getGroupFunctionNameRegEx(QString functionName);
|
||||
QRegularExpression getNamedVariableRegEx(QString variableName);
|
||||
#endif
|
||||
|
||||
|
||||
class Enums
|
||||
{
|
||||
|
@ -48,8 +48,8 @@ void GroupFunction::slotBandRendered(BandDesignIntf *band)
|
||||
QRegExp rxField(Const::FIELD_RX);
|
||||
QRegExp rxVar(Const::VARIABLE_RX);
|
||||
#else
|
||||
QRegularExpression rxField(Const::FIELD_RX);
|
||||
QRegularExpression rxVar(Const::VARIABLE_RX);
|
||||
QRegularExpression rxField = getFieldRegEx();
|
||||
QRegularExpression rxVar = getVariableRegEx();
|
||||
#endif
|
||||
|
||||
switch (m_dataType){
|
||||
@ -154,9 +154,9 @@ GroupFunction::GroupFunction(const QString &expression, const QString &dataBandN
|
||||
QRegExp rxVariable(Const::VARIABLE_RX,Qt::CaseInsensitive);
|
||||
QRegExp rxScript(Const::SCRIPT_RX,Qt::CaseInsensitive);
|
||||
#else
|
||||
QRegularExpression rxField(Const::FIELD_RX, QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression rxVariable(Const::VARIABLE_RX, QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression rxScript(Const::SCRIPT_RX, QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpression rxField = getFieldRegEx();
|
||||
QRegularExpression rxVariable = getVariableRegEx();
|
||||
QRegularExpression rxScript = getScriptRegEx();
|
||||
#endif
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 1))
|
||||
if (rxScript.indexIn(expression) != -1){
|
||||
|
@ -97,6 +97,7 @@ public:
|
||||
LayoutDesignIntf(const QString& xmlTypeName, QObject* owner = 0,QGraphicsItem* parent = 0):
|
||||
ItemDesignIntf(xmlTypeName,owner,parent){}
|
||||
virtual void addChild(BaseDesignIntf *item,bool updateSize=true) = 0;
|
||||
virtual void removeChild(BaseDesignIntf *item) = 0;
|
||||
virtual void restoreChild(BaseDesignIntf *item) = 0;
|
||||
virtual int childrenCount() = 0;
|
||||
friend class BaseDesignIntf;
|
||||
|
@ -554,17 +554,16 @@ CommandIf::Ptr PageDesignIntf::removeReportItemCommand(BaseDesignIntf *item){
|
||||
CommandIf::Ptr command = createBandDeleteCommand(this,band);
|
||||
return command;
|
||||
} else {
|
||||
LayoutDesignIntf* layout = dynamic_cast<LayoutDesignIntf*>(item->parent());
|
||||
if (layout && (layout->childrenCount()==2)){
|
||||
LayoutDesignIntf* parentLayout = dynamic_cast<LayoutDesignIntf*>(item->parent());
|
||||
LayoutDesignIntf* layout = dynamic_cast<LayoutDesignIntf*>(item);
|
||||
// When removing layout child all his children will be assigned to parent
|
||||
if (!layout && parentLayout && (parentLayout->childrenCount() == 2)) {
|
||||
CommandGroup::Ptr commandGroup = CommandGroup::create();
|
||||
commandGroup->addCommand(DeleteLayoutCommand::create(this, layout),false);
|
||||
commandGroup->addCommand(DeleteLayoutCommand::create(this, parentLayout),false);
|
||||
commandGroup->addCommand(DeleteItemCommand::create(this,item),false);
|
||||
return commandGroup;
|
||||
} else {
|
||||
CommandIf::Ptr command = (dynamic_cast<LayoutDesignIntf*>(item))?
|
||||
DeleteLayoutCommand::create(this, dynamic_cast<LayoutDesignIntf*>(item)) :
|
||||
DeleteItemCommand::create(this, item) ;
|
||||
return command;
|
||||
return layout ? DeleteLayoutCommand::create(this, layout) : DeleteItemCommand::create(this, item) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -727,7 +726,6 @@ ReportEnginePrivate *PageDesignIntf::reportEditor()
|
||||
|
||||
void PageDesignIntf::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
|
||||
{
|
||||
|
||||
if (!event->mimeData()->text().isEmpty()){
|
||||
event->setDropAction(Qt::CopyAction);
|
||||
event->accept();
|
||||
@ -756,7 +754,7 @@ void PageDesignIntf::dropEvent(QGraphicsSceneDragDropEvent* event)
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 1))
|
||||
if (isVar) data = data.remove(QRegExp(" \\[.*\\]"));
|
||||
#else
|
||||
if (isVar) data = data.remove(QRegularExpression(" \\[.*\\]"));
|
||||
if (isVar) data = data.remove(QRegularExpression(" \\[.*\\]", QRegularExpression::DotMatchesEverythingOption));
|
||||
#endif
|
||||
ti->setContent(data);
|
||||
if (!isVar){
|
||||
@ -768,7 +766,7 @@ void PageDesignIntf::dropEvent(QGraphicsSceneDragDropEvent* event)
|
||||
parentBand->setProperty("datasource",dataSource.cap(1));
|
||||
}
|
||||
#else
|
||||
QRegularExpression dataSource("(?:\\$D\\{\\s*(.*)\\..*\\})");
|
||||
QRegularExpression dataSource("(?:\\$D\\{\\s*(.*)\\..*\\})", QRegularExpression::DotMatchesEverythingOption);
|
||||
QRegularExpressionMatch match = dataSource.match(data);
|
||||
if(match.hasMatch()){
|
||||
parentBand->setProperty("datasource", match.captured(1));
|
||||
@ -2008,6 +2006,9 @@ CommandIf::Ptr DeleteLayoutCommand::create(PageDesignIntf *page, LayoutDesignInt
|
||||
foreach (BaseDesignIntf* childItem, item->childBaseItems()){
|
||||
command->m_childItems.append(childItem->objectName());
|
||||
}
|
||||
LayoutDesignIntf* layout = dynamic_cast<LayoutDesignIntf*>(item->parent());
|
||||
if (layout)
|
||||
command->m_layoutName = layout->objectName();
|
||||
return CommandIf::Ptr(command);
|
||||
}
|
||||
|
||||
@ -2032,9 +2033,20 @@ void DeleteLayoutCommand::undoIt()
|
||||
BaseDesignIntf *item = page()->addReportItem(m_itemType);
|
||||
ItemsReaderIntf::Ptr reader = StringXMLreader::create(m_itemXML);
|
||||
if (reader->first()) reader->readItem(item);
|
||||
if (!m_layoutName.isEmpty()) {
|
||||
LayoutDesignIntf* layout = dynamic_cast<LayoutDesignIntf*>(page()->reportItemByName(m_layoutName));
|
||||
if (layout){
|
||||
layout->restoreChild(item);
|
||||
}
|
||||
page()->emitRegisterdItem(item);
|
||||
}
|
||||
foreach(QString ci, m_childItems){
|
||||
BaseDesignIntf* ri = page()->reportItemByName(ci);
|
||||
if (ri){
|
||||
LayoutDesignIntf* parentLayout = dynamic_cast<LayoutDesignIntf*>(ri->parent());
|
||||
if (parentLayout) {
|
||||
parentLayout->removeChild(ri);
|
||||
}
|
||||
dynamic_cast<LayoutDesignIntf*>(item)->addChild(ri);
|
||||
}
|
||||
page()->emitRegisterdItem(item);
|
||||
|
@ -415,6 +415,7 @@ namespace LimeReport {
|
||||
void setItem(BaseDesignIntf* item);
|
||||
private:
|
||||
QStringList m_childItems;
|
||||
QString m_layoutName;
|
||||
QString m_itemXML;
|
||||
QString m_itemType;
|
||||
QString m_itemName;
|
||||
|
@ -492,7 +492,7 @@ bool ReportEnginePrivate::showPreviewWindow(ReportPages pages, PreviewHints hint
|
||||
Q_UNUSED(printer)
|
||||
if (pages.count()>0){
|
||||
Q_Q(ReportEngine);
|
||||
PreviewReportWindow* w = new PreviewReportWindow(q, 0, settings());
|
||||
PreviewReportWindow* w = new PreviewReportWindow(q, QApplication::activeWindow(), settings());
|
||||
w->setWindowFlags(Qt::Dialog|Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint| Qt::WindowMinMaxButtonsHint);
|
||||
w->setAttribute(Qt::WA_DeleteOnClose,true);
|
||||
w->setWindowModality(Qt::ApplicationModal);
|
||||
|
@ -196,13 +196,11 @@ void ReportRender::analizeItem(ContentItemDesignIntf* contentItem, BandDesignInt
|
||||
QString content = contentItem->content();
|
||||
QVector<QString> functions;
|
||||
foreach(const QString &functionName, m_datasources->groupFunctionNames()){
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
QRegularExpression rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
|
||||
rx.setPatternOptions(rx.InvertedGreedinessOption);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression rx = getGroupFunctionRegEx(functionName);
|
||||
if(content.indexOf(rx)>=0){
|
||||
functions.append(functionName);
|
||||
}
|
||||
// TODO: Qt6 port - done
|
||||
#else
|
||||
QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
|
||||
rx.setMinimal(true);
|
||||
@ -368,13 +366,11 @@ void ReportRender::clearPageMap()
|
||||
bool checkContentItem(ContentItemDesignIntf* item, DataSourceManager* datasources){
|
||||
QString content = item->content();
|
||||
foreach(QString functionName, datasources->groupFunctionNames()){
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
QRegularExpression rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
|
||||
rx.setPatternOptions(rx.InvertedGreedinessOption);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression rx = getGroupFunctionRegEx(functionName);
|
||||
if(content.indexOf(rx)>=0){
|
||||
return true;
|
||||
}
|
||||
// TODO: Qt6 port - done
|
||||
#else
|
||||
QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
|
||||
if (rx.indexIn(content)>=0){
|
||||
@ -400,16 +396,14 @@ bool ReportRender::containsGroupFunctions(BaseDesignIntf *container){
|
||||
}
|
||||
|
||||
void ReportRender::extractGroupFuntionsFromItem(ContentItemDesignIntf* contentItem, BandDesignIntf* band){
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
|
||||
if ( contentItem && contentItem->content().contains(QRegularExpression("\\$S\\s*\\{.*\\}"))){
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
if ( contentItem && contentItem->content().contains(getScriptRegEx())){
|
||||
foreach(const QString &functionName, m_datasources->groupFunctionNames()){
|
||||
QRegularExpression rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
|
||||
rx.setPatternOptions(rx.InvertedGreedinessOption);
|
||||
QRegularExpression rxName(QString(Const::GROUP_FUNCTION_NAME_RX).arg(functionName));
|
||||
rxName.setPatternOptions(rx.InvertedGreedinessOption);
|
||||
|
||||
QRegularExpression rx = getGroupFunctionRegEx(functionName);
|
||||
QRegularExpression rxName = getGroupFunctionNameRegEx(functionName);
|
||||
QRegularExpressionMatch match = rx.match(contentItem->content());
|
||||
|
||||
if (match.hasMatch()){
|
||||
|
||||
QRegularExpressionMatchIterator iter = rx.globalMatch(contentItem->content());
|
||||
@ -437,31 +431,7 @@ void ReportRender::extractGroupFuntionsFromItem(ContentItemDesignIntf* contentIt
|
||||
}
|
||||
}
|
||||
}
|
||||
// int pos = 0;
|
||||
// while ( (pos = match.capturedStart()) != -1){
|
||||
// QVector<QString> captures = normalizeCaptures(match);
|
||||
// if (captures.size() >= 3){
|
||||
// int dsIndex = captures.size() == 3 ? Const::DATASOURCE_INDEX - 1 : Const::DATASOURCE_INDEX;
|
||||
// BandDesignIntf* dataBand = m_patternPageItem->bandByName(captures.at(dsIndex));
|
||||
// if (dataBand){
|
||||
// GroupFunction* gf = datasources()->addGroupFunction(
|
||||
// functionName, captures.at(Const::VALUE_INDEX), band->objectName(), dataBand->objectName()
|
||||
// );
|
||||
// if (gf){
|
||||
// connect(dataBand, SIGNAL(bandRendered(BandDesignIntf*)),
|
||||
// gf, SLOT(slotBandRendered(BandDesignIntf*)));
|
||||
// connect(dataBand, SIGNAL(bandReRendered(BandDesignIntf*, BandDesignIntf*)),
|
||||
// gf, SLOT(slotBandReRendered(BandDesignIntf*, BandDesignIntf*)));
|
||||
// }
|
||||
// } else {
|
||||
// GroupFunction* gf = datasources()->addGroupFunction(
|
||||
// functionName, captures.at(Const::VALUE_INDEX), band->objectName(), captures.at(dsIndex)
|
||||
// );
|
||||
// gf->setInvalid(tr("Databand \"%1\" not found").arg(captures.at(dsIndex)));
|
||||
// }
|
||||
// }
|
||||
// match = rx.match(contentItem->content(), pos + match.capturedLength());
|
||||
// }
|
||||
|
||||
} else if (contentItem->content().indexOf(rxName)>=0){
|
||||
match = rxName.match(contentItem->content());
|
||||
GroupFunction* gf = datasources()->addGroupFunction(functionName, match.captured(1), band->objectName(), "");
|
||||
@ -470,7 +440,6 @@ void ReportRender::extractGroupFuntionsFromItem(ContentItemDesignIntf* contentIt
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Qt6 port - done
|
||||
#else
|
||||
if ( contentItem && contentItem->content().contains(QRegExp("\\$S\\s*\\{.*\\}"))){
|
||||
foreach(const QString &functionName, m_datasources->groupFunctionNames()){
|
||||
@ -529,10 +498,8 @@ void ReportRender::replaceGroupFunctionsInItem(ContentItemDesignIntf* contentIte
|
||||
if (m_groupfunctionItems.contains(contentItem->patternName())){
|
||||
QString content = contentItem->content();
|
||||
foreach(QString functionName, m_groupfunctionItems.value(contentItem->patternName())){
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 3)
|
||||
|
||||
QRegularExpression rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
|
||||
rx.setPatternOptions(rx.InvertedGreedinessOption);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 1)
|
||||
QRegularExpression rx = getGroupFunctionRegEx(functionName);
|
||||
QRegularExpressionMatch match = rx.match(content);
|
||||
|
||||
if (match.capturedStart() != -1){
|
||||
@ -556,7 +523,6 @@ void ReportRender::replaceGroupFunctionsInItem(ContentItemDesignIntf* contentIte
|
||||
match = rx.match(content, pos + match.capturedLength());
|
||||
}
|
||||
}
|
||||
// TODO: Qt6 port - done
|
||||
#else
|
||||
QRegExp rx(QString(Const::GROUP_FUNCTION_RX).arg(functionName));
|
||||
rx.setMinimal(true);
|
||||
|
@ -398,7 +398,7 @@ QString ScriptEngineManager::expandUserVariables(QString context, RenderPass /*
|
||||
}
|
||||
return context;
|
||||
#else
|
||||
QRegularExpression rx(Const::VARIABLE_RX);
|
||||
QRegularExpression rx = getVariableRegEx();
|
||||
if (context.contains(rx)){
|
||||
int pos = 0;
|
||||
QRegularExpressionMatch match = rx.match(context, pos);
|
||||
@ -504,8 +504,7 @@ QString ScriptEngineManager::expandDataFields(QString context, ExpandType expand
|
||||
|
||||
return context;
|
||||
#else
|
||||
QRegularExpression rx(Const::FIELD_RX);
|
||||
|
||||
QRegularExpression rx = getFieldRegEx();
|
||||
if (context.contains(rx)){
|
||||
QRegularExpressionMatch match = rx.match(context);
|
||||
while (match.hasMatch()){
|
||||
@ -520,17 +519,32 @@ QString ScriptEngineManager::expandDataFields(QString context, ExpandType expand
|
||||
fieldValue="\"\"";
|
||||
} else {
|
||||
fieldValue = escapeSimbols(varValue.toString());
|
||||
switch (dataManager()->fieldData(field).type()) {
|
||||
case QVariant::Char:
|
||||
case QVariant::String:
|
||||
case QVariant::StringList:
|
||||
case QVariant::Date:
|
||||
case QVariant::DateTime:
|
||||
fieldValue = "\""+fieldValue+"\"";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
//TODO: Migrate to QMetaType
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
switch (dataManager()->fieldData(field).typeId()) {
|
||||
case QMetaType::QChar:
|
||||
case QMetaType::QString:
|
||||
case QMetaType::QStringList:
|
||||
case QMetaType::QDate:
|
||||
case QMetaType::QDateTime:
|
||||
fieldValue = "\""+fieldValue+"\"";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (dataManager()->fieldData(field).type()) {
|
||||
case QVariant::Char:
|
||||
case QVariant::String:
|
||||
case QVariant::StringList:
|
||||
case QVariant::Date:
|
||||
case QVariant::DateTime:
|
||||
fieldValue = "\""+fieldValue+"\"";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (expandType == ReplaceHTMLSymbols)
|
||||
@ -567,8 +581,7 @@ QString ScriptEngineManager::expandScripts(QString context, QVariant& varValue,
|
||||
|
||||
if (context.contains(rx)){
|
||||
#else
|
||||
QRegularExpression rx(Const::SCRIPT_RX, QRegularExpression::DotMatchesEverythingOption);
|
||||
|
||||
QRegularExpression rx = getScriptRegEx();
|
||||
if(context.contains(rx)){
|
||||
#endif
|
||||
|
||||
@ -636,8 +649,8 @@ QVariant ScriptEngineManager::evaluateScript(const QString& script){
|
||||
QVariant varValue;
|
||||
|
||||
if (script.contains(rx)){
|
||||
#else
|
||||
QRegularExpression rx(Const::SCRIPT_RX);
|
||||
#else
|
||||
QRegularExpression rx = getScriptRegEx();
|
||||
QVariant varValue;
|
||||
|
||||
if (script.contains(rx)){
|
||||
@ -1110,7 +1123,7 @@ bool ScriptExtractor::parse()
|
||||
|
||||
bool ScriptExtractor::parse(int &curPos, const State& state, ScriptNode::Ptr scriptNode)
|
||||
{
|
||||
while (curPos<m_context.length()){
|
||||
while (curPos < m_context.length()){
|
||||
switch (state) {
|
||||
case OpenBracketFound:
|
||||
if (m_context[curPos]=='}'){
|
||||
@ -1680,11 +1693,10 @@ QVariant ScriptFunctionsManager::calcGroupFunction(const QString &name, const QS
|
||||
if (gf){
|
||||
if (gf->isValid()){
|
||||
return gf->calculate(pageItem);
|
||||
}else{
|
||||
} else{
|
||||
return gf->error();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return QString(QObject::tr("Function %1 not found or have wrong arguments").arg(name));
|
||||
}
|
||||
} else {
|
||||
|
@ -401,7 +401,11 @@ private:
|
||||
class ScriptNode{
|
||||
public:
|
||||
typedef QSharedPointer<ScriptNode> Ptr;
|
||||
QString body(){return m_body;}
|
||||
QString body(){
|
||||
if (m_body.isEmpty() && m_children.count() > 0)
|
||||
return m_children.at(0)->body();
|
||||
return m_body;
|
||||
}
|
||||
void setBody(const QString& body){ m_body = body;}
|
||||
void setStartLex(const QString startLex){ m_startLex = startLex;}
|
||||
QString script(){return m_startLex + m_body + '}';}
|
||||
|
@ -56,7 +56,12 @@ ComboBoxEditor::ComboBoxEditor(QWidget *parent, bool clearable) :
|
||||
connect(m_buttonClear,SIGNAL(clicked()),this,SLOT(slotClearButtonClicked()));
|
||||
}
|
||||
|
||||
connect(m_comboBox,SIGNAL(currentIndexChanged(QString)),this,SLOT(slotCurrentIndexChanged(QString)));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
connect(m_comboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(slotCurrentIndexChanged(QString)));
|
||||
#else
|
||||
connect(m_comboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotCurrentIndexChanged(QString)));
|
||||
#endif
|
||||
|
||||
m_comboBox->installEventFilter(this);
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->addWidget(m_comboBox);
|
||||
|
@ -222,6 +222,10 @@ void QObjectPropertyModel::setMultiObjects(QList<QObject *>* list)
|
||||
m_objects.clear();
|
||||
submit();
|
||||
|
||||
if (list->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!list->contains(m_object)){
|
||||
m_object=list->at(0);
|
||||
list->removeAt(0);
|
||||
|
57
limereport/objectinspector/propertyItems/lraxispropitem.cpp
Normal file
57
limereport/objectinspector/propertyItems/lraxispropitem.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "lraxispropitem.h"
|
||||
|
||||
#include <QToolButton>
|
||||
|
||||
#include <lrchartitemeditor.h>
|
||||
#include <lrpagedesignintf.h>
|
||||
#include <lrreportengine_p.h>
|
||||
|
||||
namespace {
|
||||
LimeReport::ObjectPropItem * createYAxisPropItem(
|
||||
QObject *object, LimeReport::ObjectPropItem::ObjectsList* objects, const QString& name, const QString& displayName, const QVariant& data, LimeReport::ObjectPropItem* parent, bool readonly)
|
||||
{
|
||||
return new LimeReport::AxisPropItem(object, objects, name, displayName, data, parent, readonly, false);
|
||||
}
|
||||
|
||||
LimeReport::ObjectPropItem * createXAxisPropItem(
|
||||
QObject *object, LimeReport::ObjectPropItem::ObjectsList* objects, const QString& name, const QString& displayName, const QVariant& data, LimeReport::ObjectPropItem* parent, bool readonly)
|
||||
{
|
||||
return new LimeReport::AxisPropItem(object, objects, name, displayName, data, parent, readonly, true);
|
||||
}
|
||||
bool VARIABLE_IS_NOT_USED registredXAxisProp = LimeReport::ObjectPropFactory::instance().registerCreator(LimeReport::APropIdent("xAxisSettings", "LimeReport::ChartItem"), QObject::tr("X axis"), createXAxisPropItem);
|
||||
bool VARIABLE_IS_NOT_USED registredYAxisProp = LimeReport::ObjectPropFactory::instance().registerCreator(LimeReport::APropIdent("yAxisSettings", "LimeReport::ChartItem"), QObject::tr("Y axis"), createYAxisPropItem);
|
||||
}
|
||||
|
||||
namespace LimeReport {
|
||||
|
||||
QWidget *AxisPropItem::createProperyEditor(QWidget *parent) const
|
||||
{
|
||||
return new AxisPropEditor(qobject_cast<ChartItem*>(object()), m_isXAxis, parent);
|
||||
}
|
||||
|
||||
QString AxisPropItem::displayValue() const
|
||||
{
|
||||
return QObject::tr("Axis");
|
||||
}
|
||||
|
||||
AxisPropEditor::AxisPropEditor(ChartItem *chart, bool isXAxis, QWidget *parent)
|
||||
: QWidget(parent), m_button(new QPushButton(this)), m_chart(chart), m_isXAxis(isXAxis)
|
||||
{
|
||||
m_button->setText("...");
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->addWidget(m_button);
|
||||
layout->setSpacing(1);
|
||||
layout->setContentsMargins(1,0,1,1);
|
||||
setLayout(layout);
|
||||
setFocusProxy(m_button);
|
||||
setAutoFillBackground(true);
|
||||
connect(m_button,SIGNAL(clicked()),this,SLOT(slotButtonClicked()));
|
||||
}
|
||||
|
||||
void AxisPropEditor::slotButtonClicked()
|
||||
{
|
||||
m_chart->showAxisEditorDialog(m_isXAxis);
|
||||
emit editingFinished();
|
||||
}
|
||||
|
||||
}
|
43
limereport/objectinspector/propertyItems/lraxispropitem.h
Normal file
43
limereport/objectinspector/propertyItems/lraxispropitem.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef AXISPROPITEM_H
|
||||
#define AXISPROPITEM_H
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <lrobjectpropitem.h>
|
||||
#include <lrchartitem.h>
|
||||
|
||||
|
||||
namespace LimeReport {
|
||||
|
||||
class AxisPropEditor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AxisPropEditor(ChartItem* chart, bool isXAxis, QWidget *parent = 0);
|
||||
signals:
|
||||
void editingFinished();
|
||||
private slots:
|
||||
void slotButtonClicked();
|
||||
private:
|
||||
QPushButton* m_button;
|
||||
ChartItem* m_chart;
|
||||
bool m_isXAxis;
|
||||
};
|
||||
|
||||
class AxisPropItem: public LimeReport::ObjectPropItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AxisPropItem():ObjectPropItem(){}
|
||||
AxisPropItem(QObject* object, ObjectsList* objects, const QString& name, const QString& displayName, const QVariant& value, ObjectPropItem* parent, bool readonly, bool isXAxis)
|
||||
:ObjectPropItem(object, objects, name, displayName, value, parent, readonly), m_isXAxis(isXAxis){}
|
||||
QWidget* createProperyEditor(QWidget *parent) const;
|
||||
QString displayValue() const;
|
||||
|
||||
private:
|
||||
bool m_isXAxis = false;
|
||||
};
|
||||
|
||||
} // namespace LimeReport
|
||||
|
||||
#endif // AXISPROPITEM_H
|
@ -85,6 +85,17 @@ LimeReport::RectPropItem::RectPropItem(QObject *object, ObjectsList* objects, co
|
||||
|
||||
QString LimeReport::RectPropItem::displayValue() const
|
||||
{
|
||||
//TODO: Migrate to QMetaType
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
switch(propertyValue().typeId()){
|
||||
case QMetaType::QRect:
|
||||
return rectToString(propertyValue().toRect());
|
||||
case QMetaType::QRectF:
|
||||
return rectToString(propertyValue().toRect());
|
||||
default :
|
||||
return ObjectPropItem::displayValue();
|
||||
}
|
||||
#else
|
||||
switch(propertyValue().type()){
|
||||
case QVariant::Rect:
|
||||
return rectToString(propertyValue().toRect());
|
||||
@ -93,6 +104,7 @@ QString LimeReport::RectPropItem::displayValue() const
|
||||
default :
|
||||
return ObjectPropItem::displayValue();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
LimeReport::RectUnitPropItem::RectUnitPropItem(QObject *object, ObjectsList* objects, const QString &name, const QString &displayName, const QVariant &value, ObjectPropItem *parent, bool /*readonly*/):
|
||||
|
@ -193,13 +193,23 @@ bool XMLWriter::enumOrFlag(QString name, QObject *item)
|
||||
bool XMLWriter::isCollection(QString propertyName, QObject* item)
|
||||
{
|
||||
QMetaProperty prop=item->metaObject()->property(item->metaObject()->indexOfProperty(propertyName.toLatin1()));
|
||||
return QMetaType::type(prop.typeName())==COLLECTION_TYPE_ID;
|
||||
//TODO: Migrate to QMetaType
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
return QMetaType::fromName(prop.typeName()).id() == COLLECTION_TYPE_ID;
|
||||
#else
|
||||
return QMetaType::type(prop.typeName()) == COLLECTION_TYPE_ID;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool XMLWriter::isTranslation(QString propertyName, QObject* item)
|
||||
{
|
||||
QMetaProperty prop=item->metaObject()->property(item->metaObject()->indexOfProperty(propertyName.toLatin1()));
|
||||
return QMetaType::type(prop.typeName())==TRANSLATION_TYPE_ID;
|
||||
//TODO: Migrate to QMetaType
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
return QMetaType::fromName(prop.typeName()).id() == TRANSLATION_TYPE_ID;
|
||||
#else
|
||||
return QMetaType::type(prop.typeName()) == TRANSLATION_TYPE_ID;
|
||||
#endif
|
||||
}
|
||||
|
||||
void XMLWriter::saveCollection(QString propertyName, QObject *item, QDomElement *node)
|
||||
@ -254,7 +264,13 @@ void XMLWriter::saveTranslation(QString propertyName, QObject* item, QDomElement
|
||||
bool XMLWriter::isQObject(QString propertyName, QObject *item)
|
||||
{
|
||||
QMetaProperty prop=item->metaObject()->property(item->metaObject()->indexOfProperty(propertyName.toLatin1()));
|
||||
return QMetaType::type(prop.typeName())==QMetaType::QObjectStar;
|
||||
//TODO: Migrate to QMetaType
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
return QMetaType::fromName(prop.typeName()).id() == QMetaType::QObjectStar;
|
||||
#else
|
||||
return QMetaType::type(prop.typeName()) == QMetaType::QObjectStar;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool XMLWriter::replaceNode(QDomElement node, QObject* item)
|
||||
|
@ -8,18 +8,20 @@ namespace Ui {
|
||||
class LanguageSelectDialog;
|
||||
}
|
||||
|
||||
class LanguageSelectDialog : public QDialog
|
||||
{
|
||||
class LanguageSelectDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit LanguageSelectDialog(QWidget *parent = 0);
|
||||
~LanguageSelectDialog();
|
||||
QLocale::Language getSelectedLanguage();
|
||||
private:
|
||||
|
||||
private:
|
||||
Ui::LanguageSelectDialog *ui;
|
||||
};
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
Q_DECLARE_METATYPE(QLocale::Language)
|
||||
#endif
|
||||
|
||||
#endif // LANGUAGESELECTDIALOG_H
|
||||
|
@ -29,7 +29,11 @@ TranslationEditor::TranslationEditor(QWidget *parent) :
|
||||
ui->tbStrings->setHorizontalHeaderItem(1,new QTableWidgetItem(tr("Report Item")));
|
||||
ui->tbStrings->setHorizontalHeaderItem(2,new QTableWidgetItem(tr("Property")));
|
||||
ui->tbStrings->setHorizontalHeaderItem(3,new QTableWidgetItem(tr("Source text")));
|
||||
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this, SLOT(slotItemChecked()));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
m_clrReturn = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Return), this, SLOT(slotItemChecked()));
|
||||
#else
|
||||
m_clrReturn = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this, SLOT(slotItemChecked()));
|
||||
#endif
|
||||
//ui->tbStrings->setSortingEnabled(true);
|
||||
|
||||
}
|
||||
@ -50,6 +54,7 @@ void TranslationEditor::setReportEngine(ITranslationContainer* translationContai
|
||||
TranslationEditor::~TranslationEditor()
|
||||
{
|
||||
delete ui;
|
||||
delete m_clrReturn;
|
||||
}
|
||||
|
||||
QLocale::Language TranslationEditor::getLanguageByName(const QString& languageName){
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QWidget>
|
||||
#include <QLocale>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QShortcut>
|
||||
#include "lrreporttranslation.h"
|
||||
|
||||
namespace LimeReport {
|
||||
@ -46,6 +47,7 @@ private:
|
||||
PageTranslation* m_currentPageTranslation;
|
||||
PropertyTranslation* m_currentPropertyTranslation;
|
||||
bool m_translationChanging;
|
||||
QShortcut* m_clrReturn;
|
||||
};
|
||||
|
||||
} //namespace LimeReport
|
||||
|
Loading…
Reference in New Issue
Block a user