#pragma once#include <QString>#include <QTextDocument>#include <QTextCursor>#include <QAbstractItemModel>class CReportMaker{private: QString m_sOfficePath; QString m_sBrowserPath; QString m_sReportPath; // Instance static CReportMaker * s_pInstance;public: enum exportFileType { eftHTML, eftODT, eftCount }; typedef QHash<QString, QVariant> TableRowDesc; QString eftToString( exportFileType eftVal ); QString appByEFT( exportFileType eftVal ); // Instance inline static CReportMaker * instance() { return s_pInstance; } CReportMaker(); ~CReportMaker(); bool loadReportTemplate( QTextDocument& textDoc, const QString& sFName ); void doSimpleReplacement( QTextDocument& textDoc, QHash<QString, QVariant>& simpleReplacement ); void doTableReplacement(QTextDocument& textDoc, const QString &sTableName, QVector<TableRowDesc> tableReplacement ); void doTableReplacement(QTextDocument& textDoc, const QString &sTableName, const QAbstractItemModel& model ); void saveAndOpen( const QTextDocument& textDoc, exportFileType eftVal, const QString& sFName );};// Shortcutsinline CReportMaker * reportMaker() { return CReportMaker::instance(); }
#include "ReportMaker.h"#include "FileUtils.h"#include "SettingsManager.h"#include <QTextDocumentWriter>#include <QProcess>#include <QTextCodec>#include <QTextTable>#include <QDebug>#include <StringUtils.h>CReportMaker * CReportMaker::s_pInstance = 0;QString CReportMaker::eftToString(CReportMaker::exportFileType eftVal){ static const QString eftStrings[ eftCount ] = { "html", "odt" }; return eftStrings[ eftVal ];}QString CReportMaker::appByEFT(CReportMaker::exportFileType eftVal){ switch ( eftVal ) { case eftHTML: return m_sBrowserPath; case eftODT: return m_sOfficePath; default: return ""; }}CReportMaker::CReportMaker(){ Q_ASSERT( !s_pInstance ); // Save instance pointer s_pInstance = this; // ********************************************** CXmlSettings * pXml = settingsManager()->xml(); pXml->beginGroup("report_settings"); m_sOfficePath = pXml->value( "OfficeProgram", "libreoffice" ).toString(); m_sBrowserPath = pXml->value( "BrowserProgram", "firefox" ).toString(); m_sReportPath = pXml->value( "ReportPath", dataPath() + "Reports/" ).toString(); pXml->endGroup();}CReportMaker::~CReportMaker(){ Q_ASSERT( s_pInstance ); s_pInstance = 0;}bool CReportMaker::loadReportTemplate( QTextDocument &textDoc, const QString &sFName){ if ( !QFile::exists( sFName ) ) { qCritical() << "File not found:" << sFName; return false; } QFile file( sFName ); if ( !file.open(QFile::ReadOnly) ) { qCritical() << "Failed to report open file:" << sFName; return false; } QByteArray data = file.readAll(); QTextCodec *codec = Qt::codecForHtml(data); QString str = codec->toUnicode(data); if ( !Qt::mightBeRichText(str) ) { qCritical() << "Failed to parse HTML report file:" << sFName; return false; } textDoc.setHtml( str ); return true;}void CReportMaker::doSimpleReplacement( QTextDocument &textDoc, QHash<QString, QVariant>& simpleReplacement){ QHashIterator<QString, QVariant> i(simpleReplacement); while ( i.hasNext() ) { i.next(); QString sLetter = i.key(); QVariant val = i.value(); QTextCursor cur = textDoc.find( sLetter ); while ( !cur.isNull() ) { QTextCharFormat cfmt = cur.charFormat(); cur.deleteChar(); cur.setBlockCharFormat( cfmt ); cur.insertText( val.toString() ); cur = textDoc.find( sLetter, cur ); } }}void CReportMaker::doTableReplacement( QTextDocument &textDoc, const QString& sTableName, QVector<CReportMaker::TableRowDesc> tableReplacement){ QTextCursor cur = textDoc.find( sTableName ); if ( !cur.isNull() ) { QTextCharFormat cfmt = cur.charFormat(); cur.deleteChar(); cur.setBlockCharFormat( cfmt ); while ( !cur.currentTable() ) cur.movePosition( QTextCursor::Right ); QTextTable * pTable = cur.currentTable(); // заполняем ассоциацию имен колонок к их номерам, в последней строке таблицы должны в ячейках быть только имена выводимых колонок QHash<int, QString> fieldByColumn; QHash<int, QTextCharFormat> cfmtByColumn; int nLastRow = pTable->rows()-1; for ( int nCol = 0; nCol < pTable->columns(); ++nCol ) { QTextCursor curStartCell = pTable->cellAt( nLastRow, nCol ).firstCursorPosition(); curStartCell.select( QTextCursor::WordUnderCursor ); fieldByColumn.insert( nCol, curStartCell.selectedText() ); cfmtByColumn.insert( nCol, curStartCell.charFormat() ); } pTable->removeRows( nLastRow, 1 ); for ( int i = 0; i < tableReplacement.count(); ++i ) { pTable->appendRows( 1 ); TableRowDesc row = tableReplacement.at( i ); int nLastRow = pTable->rows()-1; for ( int nCol = 0; nCol < pTable->columns(); ++nCol ) { QTextCursor cur = pTable->cellAt( nLastRow, nCol ).firstCursorPosition(); // Для этого поля не был запомнен номер колонки ( не была указана колонка с таким именем в первой строке таблицы шаблона ) if ( !fieldByColumn.contains( nCol ) ) continue; QString sText = row.value( fieldByColumn.value( nCol ) ).toString(); cur.setBlockCharFormat( cfmtByColumn.value( nCol ) ); cur.insertText( sText ); } } }}void CReportMaker::doTableReplacement(QTextDocument &textDoc, const QString &sTableName, const QAbstractItemModel &model){ QTextCharFormat defaultFormat; defaultFormat.setFontPointSize(12); QTextCharFormat headerFormat; headerFormat.setFontPointSize(12); headerFormat.setFontWeight(QFont::Bold); QTextTableFormat tableFormat; tableFormat.setCellPadding(2.0); tableFormat.setHeaderRowCount(1); tableFormat.setBorderStyle( QTextFrameFormat::BorderStyle_Solid ); tableFormat.setBorderBrush( Qt::black ); tableFormat.setWidth( 10 ); QVector<QTextLength> constraints; constraints << QTextLength() << QTextLength() << QTextLength(); tableFormat .setColumnWidthConstraints(constraints); tableFormat .setWidth(QTextLength(QTextLength::PercentageLength, 100)); QTextCursor cur = textDoc.find( sTableName ); if ( !cur.isNull() ) { QTextCharFormat cfmt = cur.charFormat(); cur.deleteChar(); cur.setBlockCharFormat( cfmt ); cur.insertTable(1, model.columnCount(), tableFormat); // заголовок таблицы for ( int i=0; i < model.columnCount(); ++i ) { cur.insertText( model.headerData(i, Qt::Horizontal).toString(), headerFormat ); cur.movePosition(QTextCursor::NextCell); } // таблица for (int row = 0; row < model.rowCount(); ++row) { cur.currentTable()->appendRows(1); cur.movePosition( QTextCursor::PreviousRow ); cur.movePosition( QTextCursor::NextCell ); for ( int col=0; col < model.columnCount(); ++col ) { QVariant vVal = model.data( model.index(row, col) ); QString sVal = VariantToStringIFDT( vVal ); cur.insertText( sVal, defaultFormat ); cur.movePosition( QTextCursor::NextCell ); } } }}void CReportMaker::saveAndOpen(const QTextDocument &textDoc, CReportMaker::exportFileType eftVal, const QString &sFName){ // создаем папку для отчетов если ее не было QDir dir( m_sReportPath ); if ( !dir.exists() ) dir.mkpath( m_sReportPath ); QString fileName = m_sReportPath + sFName + "." + eftToString( eftVal ); QTextDocumentWriter writer(fileName); //writer.setFormat("HTML"); // по непонятной причине вызов не требуется writer.write(&textDoc); QStringList args; args << fileName; QProcess * app = new QProcess; app->start( appByEFT( eftVal ), args);}