// $Id: RwModelReport.cpp,v 1.17 2011/03/10 00:54:35 philw Exp $ // Configuration: Should generated Icon Pixmap files have a transparent // background? If not, they will be written with a white background. static const bool WRITE_ICON_PIXMAPS_WITH_TRANSPARENT_BG (true); #ifndef RwModelReportINCLUDED #include "RwModelReport.hpp" #endif #ifndef RepGenSimObjHtmlINCLUDED #include "RepGenSimObjHtml.hpp" #endif #ifndef RepGenSimObjTextINCLUDED #include "RepGenSimObjText.hpp" #endif #ifndef RepGenUtilsINCLUDED #include "RepGenUtils.hpp" #endif #include <QApplication> #include <QClipboard> #include <QDir> #include <QFile> #include <QFileInfo> #include <QFileDialog> #include <QPainter> #include <QProcess> #include <QMessageBox> #ifndef rwFileINCLUDED #include "rwFile.hpp" #endif #ifndef SystemINCLUDED #include "System.hpp" #endif #ifndef SimWorkspaceINCLUDED #include "SimWS.hpp" #endif #ifndef SimObjINCLUDED #include "SimObj.hpp" #endif #ifndef Date_TimeINCLUDED #include "Date_Time.hpp" #endif #ifndef FileTypeAssocFormatINCLUDED #include "FileTypeAssocFormat.hpp" #endif #ifndef FileTypeAssocMgrINCLUDED #include "FileTypeAssocMgr.hpp" #endif #ifndef cwfstreamINCLUDED #include "cwfstream.hpp" #endif #ifndef RwQPixmap16INCLUDED #include "RwQPixmap16.hpp" // Slot and Account Icons #endif #ifndef RwQtIconsINCLUDED #include "RwQtIcons.hpp" // SimObj Icons #endif #ifndef cwVersionINCLUDED #include "cwVersion.hpp" #endif #ifndef rwErrorINCLUDED #include "rwError.hpp" //-- for rwAssert() #endif #include "rwStr.hpp" //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static QString RwModelReport::_recentReportDir (""); //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // constructor 1 of 1 RwModelReport::RwModelReport() : _reportPath (""), _simObj (NULL) { } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // destructor RwModelReport::~RwModelReport() { } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- QDir RwModelReport::reportDir() const { const QFileInfo repFileInfo (_reportPath); if (repFileInfo.isDir()) { return (QDir (_reportPath)); } return (repFileInfo.absoluteDir()); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool RwModelReport::isHtmlReport() const { const bool isHtml (!isTextReport()); return (isHtml); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool RwModelReport::isTextReport() const { const bool isText = _reportPath.toUpper().endsWith ("TXT"); return (isText); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool RwModelReport::chooseReportPath() { static const char (*mname) ("RwModelReport::chooseReportPath"); static const QString caption ("Select Report Output File"); static const QString filter ("HTML (*.htm *.html);;" "TEXT (*.txt);;" "All (*)"); QString startDirStr = _recentReportDir; if (startDirStr.isEmpty()) { const rwFile* modelRwFile = rwWorkspace->getModelFile(); if (modelRwFile && !modelRwFile->Path().isEmpty()) { const QString modelFilePathStr (modelRwFile->Path()); const QFileInfo modelFileInfo (modelFilePathStr); startDirStr = modelFileInfo.absoluteDir().absolutePath(); } else { startDirStr = QDir::currentDirPath(); } } QString startPathStr (startDirStr); // tentative if (_simObj != NULL) { QDir startDir (startDirStr); const QString objName (_simObj->getCompleteName()); const QString fileStr (RepGen::reduceNameString (objName) + ".html"); startPathStr = startDir.absoluteFilePath (fileStr); } static QString selectedFilter (""); // *************************** // *** Show File Chooser *** // *************************** // NOTE [3-29-2009, Phil] -- Re: Confirming file overwrites. // With Qt 4.3.3 (and, I believe, with 4.4 and 4.5.0), there is no way to // make use of the QFileDialog::getSaveFileName static function's DEFAULT // behavior of asking the user whether or not the picked file, if already // existing, should be overwritten. It is a bug to allow that feature to // remain enabled. If the user requests that the picked file NOT be // overwritten, it would be overwritten anyway. I may be missing // something, because I can't get confirmation of this problem on the // QtCentre blog. Apparenty, the check and query needs to be done by // hand AFTER receiving the result from this QFileDialog method. SEE: // http://www.qtcentre.org/forum/showthread.php?t=19833&referrerid=6743 // Note: This can be several options, OR'ed together. const QFileDialog::Options opts = QFileDialog::DontConfirmOverwrite; const QString userPickedPath = QFileDialog::getSaveFileName (NULL, // parent widget caption, startPathStr, filter, &selectedFilter, opts); const bool userPickedEmpty (userPickedPath.isEmpty()); // std::cout << mname << " Picked: '" << qPrintable (userPickedPath) // << "' " << (userPickedEmpty ? "[EMPTY]" : "[Good to go]") // << std::endl; if (userPickedEmpty) { // File selection canceled by user. return (false); //----------->> } setReportPath (userPickedPath); return (true); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RwModelReport::setSimObj (SimObj* obj) { _simObj = obj; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RwModelReport::generateReportFile() { static const char (*mname) ("RwModelReport::generateReportFile"); if (_simObj == NULL) { std::cout << mname << " NULL _simObj" << std::endl; return; //----->> } if (_reportPath.isEmpty()) { const bool pathSelected = chooseReportPath(); if (!pathSelected) return; //---------------------->> } // std::cout << mname << " '" << qPrintable (_reportPath) << "'" // << std::endl; cwofstream os (_reportPath.ascii()); const bool isText = isTextReport(); if (isText) { generateTextReportFile (os); } else { generateHtmlReportFile (os); } os.close(); // ***************************************** // *** Copy document path to clipboard *** // ***************************************** QClipboard *clipboard = QApplication::clipboard(); clipboard->setText (_reportPath, QClipboard::Clipboard); if (clipboard->supportsSelection()) { clipboard->setText (_reportPath, QClipboard::Clipboard); } // ************************* // *** Show in Browser *** // ************************* showInBrowser (true); // queryUserFirst } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RwModelReport::showInBrowser (bool queryUserFirst) { static const char (*mname) ("RwModelReport::showInBrowser"); const FileTypeAssocMgr* mgr = FileTypeAssocMgr::instance(); const FileTypeAssocFormat::Type format (FileTypeAssocFormat::Type_HTML); const QString progStr = mgr->viewModeExecutablePath (format); const QString docFullPathWithScheme = QString ("file://") + _reportPath; QStringList argList; argList << docFullPathWithScheme; if (queryUserFirst) { static const QString msgFmt ( "Show generated report in web browser?\n\n" " Browser: %1\n" " Report File: %2" ); const QString msg = msgFmt .arg (progStr) .arg (_reportPath); const QMessageBox::StandardButton userResp = QMessageBox::question (NULL, "Show in Browser?", msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); // default if (userResp != QMessageBox::Yes) { return; //======>> } } // Spin off the viewer as a separate process. QString workingDir (""); qint64 pid (0); const bool startProgramOk = QProcess::startDetached (progStr, argList, workingDir, &pid); startProgramOk; // (avoid compilation warning) // std::cout << mname // << " prog='" << qPrintable (progStr) << "'" // << " doc='" << qPrintable (docFullPathWithScheme) << "'" // << " pid=" << (int64) pid // << " START " << (startProgramOk ? "SUCCESS" : "FAILURE") // << std::endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // public void RwModelReport::createReportIconFile (const QString& fileStr, IconHandle iconHandle) { static const char (*mname) ("RwModelReport::createReportIconFile"); if (_writtenIconFiles.contains (iconHandle)) { // An Icon Image File (PNG) was ALREADY WRITTEN for this // IconHandle (during this instantiation of RwModelReport). return; //------>> } // Just once during each RwModelReport instantiation, // write out the specified Icon QPixmap to the given file path. QPixmap iconPixmap = RwQPixmap16::findIconHandlePixmap (iconHandle); if (iconPixmap.isNull()) iconPixmap = RwQtIcons::findIconHandlePixmap (iconHandle); const QDir repDir = reportDir(); const QString pathStr = repDir.filePath (fileStr); if (iconPixmap.isNull()) { // ERROR std::cout << mname << " (" << qPrintable (pathStr) << ")" << " (" << qPrintable(iconHandle.iconTagStr()) << ") NOT FOUND" << std::endl; } else // Non-Null QPixmap { // ************************************ // *** Create images subdirectory *** // ************************************ // Note that this needs to be recomputed from the assembled pathStr, // because the fileStr may start with a subdirectory. const QFileInfo pathInfo (pathStr); const QDir pathDir = pathInfo.isDir()? QDir (pathStr) : pathInfo.absoluteDir(); if (!pathDir.exists()) { const QString pathDirStr (pathDir.absolutePath()); // std::cout << mname // << " mkpath: '" << qPrintable (pathDirStr) << "'" // << std::endl; pathDir.mkpath (pathDirStr); } // ******************************** // *** Create Icon Image File *** // ******************************** // Make an "complete" copy of the Icon Pixmap. The background needs // to be filled with white or "transparent". QPixmap completeIconPixmap (iconPixmap.size()); completeIconPixmap.fill ( WRITE_ICON_PIXMAPS_WITH_TRANSPARENT_BG ? Qt::transparent : Qt::white); QPainter pmapPainter (&completeIconPixmap); pmapPainter.drawPixmap (0, 0, iconPixmap); (void) pmapPainter.end(); static const int FullQuality (100); const bool saveSuccess = completeIconPixmap.save (pathStr, "PNG", FullQuality); // std::cout << mname << " (" << qPrintable (pathStr) << ")" // << " (" << iconHandle.iconTagStr() << ") " // << (saveSuccess ? "SAVE OK" : "SAVE FAILED") // << std::endl; if (saveSuccess) { _writtenIconFiles.append (iconHandle); } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // private void RwModelReport::setReportPath (const QString& newPath) { _reportPath = newPath; // ******************************************** // *** Record Recently Accessed Directory *** // ******************************************** if (!newPath.isEmpty()) { QFileInfo finfo (newPath); if (finfo.isDir()) { _recentReportDir = finfo.absolutePath();; } else { QDir fdir (finfo.dir()); _recentReportDir = fdir.absolutePath(); } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RwModelReport::generateHtmlReportFile (cwofstream& os) { const QString titleStr = QString ("RiverWare SimObj Report: %1") .arg (qPrintable(_simObj->getCompleteName())); os << "<html>\n" << "<head>\n" << " <title>" << qPrintable (titleStr) << "</title>\n" << "</head>\n" << "<body bgcolor=\"#FFFFFF\" text=\"#000000\">\n"; Date_Time dt; const QString timeStr (dt.currentTime().ascii()); const rwFile* modelRwFile = rwWorkspace->getModelFile(); QString modelFilePathStr ("(Unsaved RiverWare Workspace)"); if (modelRwFile && !modelRwFile->Path().isEmpty()) { modelFilePathStr = qPrintable(modelRwFile->Path()); } const QString rwVersInfo (cwAppVersion::instance().getVersionInfo()); const QString versionMsg = QString ("%1 (http://cadswes.colorado.edu/)") .arg (qPrintable(rwVersInfo)); os << "<p><font size=\"+1\">RiverWare Model Report Demo</font><br>\n" << "Model File: " << qPrintable (modelFilePathStr) << "<br>\n" << "Report File: " << qPrintable (_reportPath) << "<br>\n" << "Generated by: " << qPrintable (versionMsg) << "<br>\n" << "Generated at: " << timeStr << "</p>\n"; RepGenSimObjHtml objRepGen (this, _simObj); objRepGen.writeObj (os); os << "<p>--- (end) ---</p>\n" << "</body>\n" << "</html>\n" << std::endl; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void RwModelReport::generateTextReportFile (cwofstream& os) { Date_Time dt; const QString timeStr (dt.currentTime().ascii()); const rwFile* modelRwFile = rwWorkspace->getModelFile(); QString modelFilePathStr ("(Unsaved RiverWare Workspace)"); if (modelRwFile && !modelRwFile->Path().isEmpty()) { modelFilePathStr = qPrintable(modelRwFile->Path()); } const QString rwVersInfo (cwAppVersion::instance().getVersionInfo()); const QString versionMsg = QString ("%1 (http://cadswes.colorado.edu/)") .arg (qPrintable(rwVersInfo)); os << "RiverWare Model Report Demo\n" << "Model File: " << qPrintable (modelFilePathStr) << "\n" << "Report File: " << qPrintable (_reportPath) << "\n" << "Generated by: " << qPrintable (versionMsg) << "\n" << "Generated at: " << timeStr << "\n" << endl; RepGenSimObjText objRepGen (this, _simObj); objRepGen.writeObj (os); os << "--- (end) ---" << endl; } //--- (end RwModelReport.hpp) ---