//============================================================================= // // File : LogViewWindow.cpp // Creation date : Tue Apr 23 2002 18:08:22 by Juanjo Alvarez // // This file is part of the KVIrc irc client distribution // Copyright (C) 2002 Juanjo Alvarez // Copyright (C) 2002-2010 Szymon Stefanek (pragma at kvirc dot net) // Copyright (C) 2011 Elvio Basello (hellvis69 at gmail dot com) // Copyright (C) 2014 OmegaPhil (OmegaPhil at startmail dot com) // // This program is FREE software. You can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your opinion) any later version. // // This program is distributed in the HOPE that it will be USEFUL, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #include "LogViewWindow.h" #include "LogViewWidget.h" #include "KviHtmlGenerator.h" #include "KviIconManager.h" #include "KviLocale.h" #include "KviModule.h" #include "KviOptions.h" #include "KviMainWindow.h" #include "KviIrcView.h" #include "KviQString.h" #include "KviApplication.h" #include "KviFileUtils.h" #include "KviFileDialog.h" #include "KviControlCodes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //for INT_MAX extern LogViewWindow * g_pLogViewWindow; LogViewListView::LogViewListView(QWidget * pParent) : QTreeWidget(pParent) { header()->setSortIndicatorShown(true); setColumnCount(1); setHeaderLabel(__tr2qs_ctx("Log File","log")); setSelectionMode(QAbstractItemView::SingleSelection); setSortingEnabled(true); setRootIsDecorated(true); setAnimated(true); } void LogViewListView::mousePressEvent(QMouseEvent * pEvent) { if(pEvent->button() == Qt::RightButton) { QTreeWidgetItem * pItem = itemAt(pEvent->pos()); if(pItem) emit rightButtonPressed(pItem,QCursor::pos()); } QTreeWidget::mousePressEvent(pEvent); } LogViewWindow::LogViewWindow() : KviWindow(KviWindow::LogView,"log") { g_pLogViewWindow = this; //m_pLogViewWidget = new KviLogViewWidget(this); m_pSplitter = new KviTalSplitter(Qt::Horizontal,this); m_pSplitter->setObjectName("main_splitter"); m_pSplitter->setChildrenCollapsible(false); m_pLeftLayout = new KviTalVBox(m_pSplitter); m_pTabWidget = new QTabWidget(m_pLeftLayout); m_pBottomLayout = new KviTalHBox(m_pLeftLayout); m_pProgressBar = new QProgressBar(m_pBottomLayout); m_pCancelButton = new QPushButton(m_pBottomLayout); m_pCancelButton->setText(__tr2qs_ctx("Cancel","log")); connect(m_pCancelButton,SIGNAL(clicked()),this,SLOT(abortFilter())); m_pBottomLayout->setVisible(false); m_pIndexTab = new KviTalVBox(m_pTabWidget); m_pTabWidget->addTab(m_pIndexTab,__tr2qs_ctx("Index","log")); m_pListView = new LogViewListView(m_pIndexTab); connect(m_pListView,SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)),this,SLOT(itemSelected(QTreeWidgetItem *,QTreeWidgetItem *))); connect(m_pListView,SIGNAL(rightButtonPressed(QTreeWidgetItem *,QPoint)),this,SLOT(rightButtonClicked(QTreeWidgetItem *,QPoint))); m_pSearchTab = new QWidget(m_pTabWidget); m_pTabWidget->addTab(m_pSearchTab,__tr2qs_ctx("Filter","log")); QGridLayout * pLayout = new QGridLayout(m_pSearchTab); m_pShowChannelsCheck = new QCheckBox(__tr2qs_ctx("Show channel logs","log"),m_pSearchTab); m_pShowChannelsCheck->setChecked(true); pLayout->addWidget(m_pShowChannelsCheck,0,0,1,2); m_pShowQueryesCheck = new QCheckBox(__tr2qs_ctx("Show query logs","log"),m_pSearchTab); m_pShowQueryesCheck->setChecked(true); pLayout->addWidget(m_pShowQueryesCheck,1,0,1,2); m_pShowConsolesCheck = new QCheckBox(__tr2qs_ctx("Show console logs","log"),m_pSearchTab); m_pShowConsolesCheck->setChecked(true); pLayout->addWidget(m_pShowConsolesCheck,2,0,1,2); m_pShowDccChatCheck = new QCheckBox(__tr2qs_ctx("Show DCC chat logs","log"),m_pSearchTab); m_pShowDccChatCheck->setChecked(true); pLayout->addWidget(m_pShowDccChatCheck,3,0,1,2); m_pShowOtherCheck = new QCheckBox(__tr2qs_ctx("Show other logs","log"),m_pSearchTab); m_pShowOtherCheck->setChecked(true); pLayout->addWidget(m_pShowOtherCheck,4,0,1,2); QLabel * pLabel; pLabel = new QLabel(__tr2qs_ctx("Contents filter","log"),m_pSearchTab); pLayout->addWidget(pLabel,5,0,1,2); pLabel = new QLabel(__tr2qs_ctx("Log name mask:","log"),m_pSearchTab); m_pFileNameMask = new QLineEdit(m_pSearchTab); pLayout->addWidget(pLabel,6,0); pLayout->addWidget(m_pFileNameMask,6,1); connect(m_pFileNameMask,SIGNAL(returnPressed()),this,SLOT(applyFilter())); pLabel = new QLabel(__tr2qs_ctx("Log contents mask:","log"),m_pSearchTab); m_pContentsMask = new QLineEdit(m_pSearchTab); pLayout->addWidget(pLabel,7,0); pLayout->addWidget(m_pContentsMask,7,1); connect(m_pContentsMask,SIGNAL(returnPressed()),this,SLOT(applyFilter())); m_pEnableFromFilter = new QCheckBox(__tr2qs_ctx("Only older than","log"),m_pSearchTab); m_pFromDateEdit = new QDateEdit(m_pSearchTab); m_pFromDateEdit->setDate(QDate::currentDate()); m_pFromDateEdit->setEnabled(false); pLayout->addWidget(m_pEnableFromFilter,8,0); pLayout->addWidget(m_pFromDateEdit,8,1); connect(m_pEnableFromFilter,SIGNAL(toggled(bool)),m_pFromDateEdit,SLOT(setEnabled(bool))); m_pEnableToFilter = new QCheckBox(__tr2qs_ctx("Only newer than","log"),m_pSearchTab); m_pToDateEdit = new QDateEdit(m_pSearchTab); m_pToDateEdit->setDate(QDate::currentDate()); m_pToDateEdit->setEnabled(false); pLayout->addWidget(m_pEnableToFilter,9,0); pLayout->addWidget(m_pToDateEdit,9,1); connect(m_pEnableToFilter,SIGNAL(toggled(bool)),m_pToDateEdit,SLOT(setEnabled(bool))); m_pFilterButton = new QPushButton(__tr2qs_ctx("Apply filter","log"),m_pSearchTab); pLayout->addWidget(m_pFilterButton,10,1); connect(m_pFilterButton,SIGNAL(clicked()),this,SLOT(applyFilter())); QWidget * pWidget = new QWidget(m_pSearchTab); pWidget->setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored); pLayout->addWidget(pWidget,11,1); m_pIrcView = new KviIrcView(m_pSplitter,this); m_pIrcView->setMaxBufferSize(INT_MAX); m_pIrcView->setFocusPolicy(Qt::ClickFocus); QList li; li.append(110); li.append(width()-110); m_pSplitter->setSizes(li); // Using setData to track the option ordinal that used to be passed as id m_pExportLogPopup = new QMenu("exportlog", this); QAction* pAction = m_pExportLogPopup->addAction(__tr2qs_ctx("Plain text file","log")); pAction->setData(LogFile::PlainText); pAction = m_pExportLogPopup->addAction(__tr2qs_ctx("HTML archive","log")); pAction->setData(LogFile::HTML); //m_pExportLogPopup->addAction(__tr2qs_ctx("XML file","log")); //m_pExportLogPopup->addAction(__tr2qs_ctx("database file","log")); // 18.11.14: Originally this hooked activated, but Qt4 kept sending bullshit IDs here // https://svn.kvirc.de/kvirc/ticket/934#comment:9 connect(m_pExportLogPopup,SIGNAL(triggered(QAction*)),this,SLOT(exportLog(QAction*))); m_pTimer = new QTimer(this); m_pTimer->setSingleShot(true); m_pTimer->setInterval(0); connect(m_pTimer,SIGNAL(timeout()),this,SLOT(filterNext())); //avoid to execute the long time-consuming procedure of log indexing here: //we could still be inside the context of the "Browse log files" QAction QTimer::singleShot(0,this,SLOT(cacheFileList())); } LogViewWindow::~LogViewWindow() { g_pLogViewWindow = 0; } void LogViewWindow::keyPressEvent(QKeyEvent * pEvent) { if((pEvent->modifiers() & Qt::ControlModifier) || (pEvent->modifiers() & Qt::AltModifier) || (pEvent->modifiers() & Qt::MetaModifier)) { if(pEvent->key() == Qt::Key_F) { m_pIrcView->toggleToolWidget(); return; } } KviWindow::keyPressEvent(pEvent); } QPixmap * LogViewWindow::myIconPtr() { return g_pIconManager->getSmallIcon(KviIconManager::Log); } void LogViewWindow::resizeEvent(QResizeEvent *) { m_pSplitter->setGeometry(0,0,width(),height()); } void LogViewWindow::fillCaptionBuffers() { m_szPlainTextCaption = __tr2qs_ctx("Log Viewer","log"); } void LogViewWindow::die() { close(); } QSize LogViewWindow::sizeHint() const { QSize ret(m_pSplitter->sizeHint().width(),m_pIrcView->sizeHint().height()); return ret; } void LogViewWindow::recurseDirectory(const QString & szDir) { QDir dir(szDir); QFileInfoList list = dir.entryInfoList(); for(int i=0; i < list.count(); i++) { QFileInfo info = list[i]; if(info.isDir()) { // recursive if((info.fileName() != "..") && (info.fileName() != ".")) recurseDirectory(info.filePath()); } else if((info.suffix() == "gz") || (info.suffix() == "log")) { m_logList.append(new LogFile(info.filePath())); } } } void LogViewWindow::setupItemList() { if(m_logList.isEmpty()) return; m_pFilterButton->setEnabled(false); m_pListView->clear(); m_bAborted = false; m_pBottomLayout->setVisible(true); m_pProgressBar->setRange(0,m_logList.count()); m_pProgressBar->setValue(0); m_pLastCategory = 0; m_pLastGroupItem = 0; m_logList.first(); m_pTimer->start(); //singleshot } void LogViewWindow::applyFilter() { setupItemList(); } void LogViewWindow::abortFilter() { m_bAborted = true; } void LogViewWindow::filterNext() { QString szCurGroup; LogFile * pFile = m_logList.current(); if(!pFile) goto filter_last; if(pFile->type() == LogFile::Channel && !m_pShowChannelsCheck->isChecked()) goto filter_next; if(pFile->type() == LogFile::Console && !m_pShowConsolesCheck->isChecked()) goto filter_next; if(pFile->type() == LogFile::DccChat && !m_pShowDccChatCheck->isChecked()) goto filter_next; if(pFile->type() == LogFile::Other && !m_pShowOtherCheck->isChecked()) goto filter_next; if(pFile->type() == LogFile::Query && !m_pShowQueryesCheck->isChecked()) goto filter_next; if(m_pEnableFromFilter->isChecked()) if(pFile->date() > m_pFromDateEdit->date()) goto filter_next; if(m_pEnableToFilter->isChecked()) if(pFile->date() < m_pToDateEdit->date()) goto filter_next; if(!m_pFileNameMask->text().isEmpty()) if(!KviQString::matchString(m_pFileNameMask->text(),pFile->name())) goto filter_next; if(!m_pContentsMask->text().isEmpty()) { QString szBuffer; pFile->getText(szBuffer); if(!KviQString::matchString(m_pContentsMask->text(),szBuffer)) goto filter_next; } if(m_pLastCategory) { if(m_pLastCategory->m_eType != pFile->type()) { m_pLastCategory = 0; for(int i=0; i < m_pListView->topLevelItemCount(); ++i) { LogListViewItemType * pTmp = (LogListViewItemType *)m_pListView->topLevelItem(i); if(pTmp->m_eType == pFile->type()) { m_pLastCategory = pTmp; break; } } if(!m_pLastCategory) m_pLastCategory = new LogListViewItemType(m_pListView,pFile->type()); } } else { m_pLastCategory = new LogListViewItemType(m_pListView,pFile->type()); } szCurGroup = __tr2qs_ctx("%1 on %2","log").arg(pFile->name(),pFile->network()); if(m_szLastGroup != szCurGroup) { m_szLastGroup = szCurGroup; m_pLastGroupItem = 0; for(int i=0; i < m_pLastCategory->childCount(); ++i) { LogListViewItemFolder * pTmp = (LogListViewItemFolder *)m_pLastCategory->child(i); if(pTmp->text(0) == m_szLastGroup) { m_pLastGroupItem = pTmp; break; } } if(!m_pLastGroupItem) m_pLastGroupItem = new LogListViewItemFolder(m_pLastCategory,m_szLastGroup); } new LogListViewLog(m_pLastGroupItem,pFile->type(),pFile); filter_next: pFile = m_logList.next(); filter_last: if(pFile && !m_bAborted) { m_pProgressBar->setValue(m_pProgressBar->value() + 1); m_pTimer->start(); //singleshot } else { m_pBottomLayout->setVisible(false); m_pListView->sortItems(0,Qt::AscendingOrder); m_pProgressBar->setValue(0); m_pFilterButton->setEnabled(true); } } void LogViewWindow::cacheFileList() { QString szLogPath; g_pApp->getLocalKvircDirectory(szLogPath,KviApplication::Log); recurseDirectory(szLogPath); setupItemList(); } void LogViewWindow::itemSelected(QTreeWidgetItem * it, QTreeWidgetItem *) { //A parent node m_pIrcView->clearBuffer(); if(!it || !it->parent() || !(((LogListViewItem *)it)->m_pFileData)) return; QString szText; ((LogListViewItem *)it)->m_pFileData->getText(szText); QStringList lines = szText.split('\n'); bool bOk; int iMsgType; for(QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) { QString szNum = (*it).section(' ',0,0); iMsgType = szNum.toInt(&bOk); if(iMsgType < 0 || iMsgType > (KVI_NUM_MSGTYPE_OPTIONS-1)) iMsgType=0; if(bOk) outputNoFmt(iMsgType,(*it).section(' ',1),KviIrcView::NoRepaint | KviIrcView::NoTimestamp); else outputNoFmt(0,*it,KviIrcView::NoRepaint | KviIrcView::NoTimestamp); } m_pIrcView->repaint(); } void LogViewWindow::rightButtonClicked(QTreeWidgetItem * pItem, const QPoint &) { if(!pItem) return; m_pListView->setCurrentItem(pItem); QMenu * pPopup = new QMenu(this); if(((LogListViewItem *)pItem)->childCount()) { //pPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::UserList)),__tr2qs_ctx("Export all log files to","log"),m_pExportLogPopup); pPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Discard)),__tr2qs_ctx("Remove all log files within this folder","log"),this,SLOT(deleteCurrent())); } else { pPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Floppy)),__tr2qs_ctx("Export log file to","log"))->setMenu(m_pExportLogPopup); pPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Discard)),__tr2qs_ctx("Remove log file","log"),this,SLOT(deleteCurrent())); } pPopup->exec(QCursor::pos()); } void LogViewWindow::deleteCurrent() { LogListViewItem * pItem = (LogListViewItem *)(m_pListView->currentItem()); if(!pItem) return; if(!pItem->childCount()) { if(!pItem->fileName().isNull()) { if(QMessageBox::question( this, __tr2qs_ctx("Confirm current user log deletion","log"), __tr2qs_ctx("Do you really wish to delete this log?","log"), __tr2qs("Yes"),__tr2qs("No"),0,1) != 0) return; KviFileUtils::removeFile(pItem->fileName()); delete pItem; m_pIrcView->clearBuffer(); if(!pItem->parent()->childCount()) delete pItem->parent(); } return; } if(QMessageBox::question( this, __tr2qs_ctx("Confirm current user logs deletion","log"), __tr2qs_ctx("Do you really wish to delete all these logs?","log"), __tr2qs("Yes"),__tr2qs("No"),0,1) != 0) return; KviPointerList itemsList; itemsList.setAutoDelete(false); for(int i=0; i < pItem->childCount(); i++) { if(!pItem->child(i)->childCount()) { itemsList.append((LogListViewItem *)pItem->child(i)); continue; } LogListViewItem * pChild = (LogListViewItem *)pItem->child(i); for(int j=0; j < pChild->childCount(); j++) { if(!(LogListViewItem *)pChild->child(j)) { qDebug("Null pointer in logviewitem"); continue; } itemsList.append((LogListViewItem *)pChild->child(j)); } } for(unsigned int u=0; u < itemsList.count(); u++) { LogListViewItem * pCurItem = itemsList.at(u); if(!pCurItem->fileName().isNull()) KviFileUtils::removeFile(pCurItem->fileName()); } delete pItem; } void LogViewWindow::exportLog(QAction* pAction) { /* This slot is required as Qt4 has started to screw up the menu ordinal * sent with the old activated signal - the ordinal is now stored as * QAction user data */ if (pAction) exportLog(pAction->data().toInt()); else qDebug("LogViewWindow::exportLog called with invalid pAction"); } void LogViewWindow::exportLog(int iId) { LogListViewItem * pItem = (LogListViewItem *)(m_pListView->currentItem()); if(!pItem) return; if(!pItem->childCount()) { // Export the log createLog(pItem->log(), iId); return; } // We selected a node in the log list, scan the children KviPointerList logList; logList.setAutoDelete(false); for(int i = 0; i < pItem->childCount(); i++) { if(!pItem->child(i)->childCount()) { // The child is a log file, append it to the list logList.append((LogListViewItem *)pItem->child(i)); continue; } // The child is a node, scan it LogListViewItem * pChild = (LogListViewItem *)pItem->child(i); for(int j=0; j < pChild->childCount(); j++) { if(!(LogListViewItem *)pChild->child(j)) { qDebug("Null pointer in logviewitem"); continue; } // Add the child to the list logList.append((LogListViewItem *)pChild->child(j)); } } // Scan the list for(unsigned int u = 0; u < logList.count(); u++) { LogListViewItem * pCurItem = logList.at(u); createLog(pCurItem->log(), iId); } } void LogViewWindow::createLog(LogFile * pLog, int iId, QString * pszFile) { if(!pLog) return; QRegExp rx; QString szLog, szLogDir, szInputBuffer, szOutputBuffer, szLine, szTmp; QString szDate = pLog->date().toString("yyyy.MM.dd"); /* Fetching previous export path and concatenating with generated filename * adjustFilePath is for file paths not directory paths */ szLog = KVI_OPTION_STRING(KviOption_stringLogsExportPath).trimmed(); if (!szLog.isEmpty()) szLog += KVI_PATH_SEPARATOR_CHAR; szLog += QString("%1_%2.%3_%4").arg(pLog->typeString(),pLog->name(),pLog->network(),szDate); KviFileUtils::adjustFilePath(szLog); // Getting output file path from the user, with overwrite confirmation if(!KviFileDialog::askForSaveFileName( szLog, __tr2qs_ctx("Export Log - KVIrc","log"), szLog, QString(), false, true, true, this)) return; /* Save export directory - this directory path is also used in the HTML export * and info is used when working with pszFile */ QFileInfo info(szLog); szLogDir = info.absoluteDir().absolutePath(); KVI_OPTION_STRING(KviOption_stringLogsExportPath) = szLogDir; /* Reading in log file - LogFiles are read in as bytes, so '\r' isn't * sanitised by default */ pLog->getText(szInputBuffer); QStringList lines = szInputBuffer.replace('\r', "").split('\n'); switch(iId) { case LogFile::PlainText: { /* Only append extension if it isn't there already (e.g. a specific * file is to be overwritten) */ if(!szLog.endsWith(".txt")) szLog += ".txt"; // Scan the file for(QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) { szTmp = (*it); szLine = KviControlCodes::stripControlBytes(szTmp); // Remove icons' code rx.setPattern("^\\d{1,3}\\s"); szLine.replace(rx,""); // Remove link from a user speaking, deal with (and keep) various ranks // e.g.: --> rx.setPattern("\\s<([+%@&~!]?)!nc"); szLine.replace(rx," <\\1"); // Remove link from a nick in a mask // e.g.: !nFoo [~bar@!hfoo.bar] --> Foo [~bar@!hfoo.bar] rx.setPattern("\\s!n"); szLine.replace(rx," "); // Remove link from a host in a mask // e.g.: Foo [~bar@!hfoo.bar] --> Foo [~bar@foo.bar] rx.setPattern("@!h"); szLine.replace(rx,"@"); // Remove link from a channel // e.g.: !c#KVIrc --> #KVIrc rx.setPattern("!c#"); szLine.replace(rx,"#"); szOutputBuffer += szLine; szOutputBuffer += "\n"; } break; } case LogFile::HTML: { /* Only append extension if it isn't there already (e.g. a specific * file is to be overwritten) */ if(!szLog.endsWith(".html")) szLog += ".html"; szTmp = QString("KVIrc %1 %2").arg(KVI_VERSION).arg(KVI_RELEASE_NAME); QString szNick = ""; bool bFirstLine = true; QString szTitle; switch(pLog->type()) { case LogFile::Channel: szTitle = __tr2qs_ctx("Channel %1 on %2","log").arg(pLog->name(),pLog->network()); break; case LogFile::Console: szTitle = __tr2qs_ctx("Console on %1","log").arg(pLog->network()); break; case LogFile::Query: szTitle = __tr2qs_ctx("Query with %1 on %2","log").arg(pLog->name(),pLog->network()); break; case LogFile::DccChat: szTitle = __tr2qs_ctx("DCC Chat with %1","log").arg(pLog->name()); break; case LogFile::Other: szTitle = __tr2qs_ctx("Something on %1","log").arg(pLog->network()); break; } // Prepare HTML document szOutputBuffer += "\n"; szOutputBuffer += "\n"; szOutputBuffer += "\n"; szOutputBuffer += "\t\n"; szOutputBuffer += "\t\n"; szOutputBuffer += "\t" + szTitle + "\n"; szOutputBuffer += "\n\n"; szOutputBuffer += "

" + szTitle + "

\n

Date: " + szDate + "

\n"; // Scan the file for(QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) { szTmp = (*it); // Find who has talked QString szTmpNick = szTmp.section(" ",2,2); if((szTmpNick.left(1) != "<") && (szTmpNick.right(1) != ">")) szTmpNick = ""; // locate msgtype QString szNum = szTmp.section(' ',0,0); bool bOk; int iMsgType = szNum.toInt(&bOk); // only human text for now... if(iMsgType != 24 && iMsgType != 25 && iMsgType != 26) continue; // remove msgtype tag szTmp = szTmp.remove(0,szNum.length()+1); szTmp = KviHtmlGenerator::convertToHtml(szTmp,true); // insert msgtype icon at start of the current text line KviMessageTypeSettings msg(KVI_OPTION_MSGTYPE(iMsgType)); QString szIcon = g_pIconManager->getSmallIconResourceName((KviIconManager::SmallIcon)msg.pixId()); szTmp.prepend("\"\" "); /* * Check if the nick who has talked is the same of the above line. * If so, we have to put the line as it is, otherwise we have to * open a new paragraph */ if(szTmpNick != szNick) { /* * People is not the same, close the paragraph opened * before and open a new one */ if(!bFirstLine) szOutputBuffer += "

\n"; szTmp.prepend("

"); szNick = szTmpNick; } else { // Break the line szTmp.prepend("
\n"); } szOutputBuffer += szTmp; bFirstLine = false; } // Close the last paragraph szOutputBuffer += "

\n"; // regexp to search all embedded icons rx.setPattern("= 0) { int iLength = rx.matchedLength(); QString szCap = rx.cap(1); // if the icon isn't in the images list then add if(szImagesList.indexOf(szCap) == -1) szImagesList.append(szCap); iIndex = szOutputBuffer.indexOf(rx, iIndex + iLength); } // get current theme path QString szCurrentThemePath; g_pApp->getLocalKvircDirectory(szCurrentThemePath,KviApplication::Themes,KVI_OPTION_STRING(KviOption_stringIconThemeSubdir)); szCurrentThemePath += KVI_PATH_SEPARATOR_CHAR; // current coresmall path szCurrentThemePath += "coresmall"; szCurrentThemePath += KVI_PATH_SEPARATOR_CHAR; // check if coresmall exists in current theme if(!KviFileUtils::directoryExists(szCurrentThemePath)) { // get global coresmall path g_pApp->getGlobalKvircDirectory(szCurrentThemePath,KviApplication::Pics,"coresmall"); KviQString::ensureLastCharIs(szCurrentThemePath,QChar(KVI_PATH_SEPARATOR_CHAR)); } // copy all icons to the log destination folder for(int i=0; i < szImagesList.count(); i++) { QString szSourceFile = szCurrentThemePath + szImagesList.at(i); QString szDestFile = szLogDir + szImagesList.at(i); KviFileUtils::copyFile(szSourceFile,szDestFile); } // remove internal tags rx.setPattern("||smallicons:"); szOutputBuffer.replace(rx,""); szOutputBuffer.replace(">!nc",">"); szOutputBuffer.replace("@!nc","@"); szOutputBuffer.replace("%!nc","%"); // Close the document szOutputBuffer += "\n\n"; break; } } // File overwriting already dealt with when file path was obtained QFile log(szLog); if(!log.open(QIODevice::WriteOnly | QIODevice::Text)) return; if(pszFile) { *pszFile = ""; *pszFile = info.filePath(); } // Ensure we're writing in UTF-8 QTextStream output(&log); output.setCodec("UTF-8"); output << szOutputBuffer; // Close file descriptors log.close(); }