/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "StdAfx.h" #include "ErrorReportDialog.h" #include #include "ErrorReport.h" #include "ErrorReportTableModel.h" #include "Clipboard.h" #include "Util/CryMemFile.h" // CCryMemFile #include "Viewport.h" #include "QtViewPaneManager.h" #include "Util/Mailer.h" #include "GameEngine.h" #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////// CErrorReportDialog* CErrorReportDialog::m_instance = 0; // CErrorReportDialog dialog ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::RegisterViewClass() { AzToolsFramework::ViewPaneOptions options; options.sendViewPaneNameBackToAmazonAnalyticsServers = true; options.showInMenu = false; AzToolsFramework::RegisterViewPane(LyViewPane::ErrorReport, LyViewPane::CategoryOther, options); } CErrorReportDialog::CErrorReportDialog(QWidget* parent) : QWidget(parent) , ui(new Ui::CErrorReportDialog) , m_errorReportModel(new CErrorReportTableModel(this)) , m_sortIndicatorColumn(-1) , m_sortIndicatorOrder(Qt::AscendingOrder) { ui->setupUi(this); ui->treeView->setModel(m_errorReportModel); ui->treeView->header()->setContextMenuPolicy(Qt::CustomContextMenu); ui->treeView->header()->setSectionsMovable(true); ui->treeView->viewport()->setMouseTracking(true); ui->treeView->viewport()->installEventFilter(this); ui->treeView->header()->setSectionResizeMode(CErrorReportTableModel::ColumnSeverity, QHeaderView::ResizeToContents); ui->treeView->header()->resizeSection(CErrorReportTableModel::ColumnCount, 30); ui->treeView->header()->resizeSection(CErrorReportTableModel::ColumnText, 200); ui->treeView->header()->resizeSection(CErrorReportTableModel::ColumnFile, 150); ui->treeView->header()->resizeSection(CErrorReportTableModel::ColumnObject, 150); ui->treeView->header()->resizeSection(CErrorReportTableModel::ColumnModule, 100); ui->treeView->header()->resizeSection(CErrorReportTableModel::ColumnDescription, 100); ui->treeView->header()->resizeSection(CErrorReportTableModel::ColumnAssetScope, 200); connect(ui->treeView, SIGNAL(clicked(QModelIndex)), this, SLOT(OnReportItemClick(QModelIndex))); connect(ui->treeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnReportItemDblClick(QModelIndex))); connect(ui->treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(OnReportItemRClick())); connect(ui->treeView->header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(OnReportColumnRClick())); connect(ui->treeView->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(OnSortIndicatorChanged(int,Qt::SortOrder))); ui->treeView->AddGroup(CErrorReportTableModel::ColumnModule); ui->treeView->header()->setSortIndicator(-1, Qt::AscendingOrder); m_instance = this; //CErrorReport *report, //m_pErrorReport = report; m_pErrorReport = 0; } CErrorReportDialog::~CErrorReportDialog() { m_instance = 0; } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::Open(CErrorReport* pReport) { if (!m_instance) { GetIEditor()->OpenView(LyViewPane::ErrorReport); } if (!m_instance) { return; } m_instance->SetReport(pReport); m_instance->UpdateErrors(); m_instance->setFocus(); } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::Close() { if (m_instance) { /* CCryMemFile memFile( new BYTE[256], 256, 256 ); CArchive ar( &memFile, CArchive::store ); m_instance->m_wndReport.SerializeState( ar ); ar.Close(); UINT nSize = (UINT)memFile.GetLength(); LPBYTE pbtData = memFile.Detach(); CXTRegistryManager regManager; regManager.WriteProfileBinary( "Dialogs\\ErrorReport", "Configuration", pbtData, nSize); if ( pbtData ) delete [] pbtData; */ m_instance->close(); } } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::Clear() { if (m_instance) { m_instance->SetReport(0); m_instance->UpdateErrors(); } } bool CErrorReportDialog::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::MouseMove && watched == ui->treeView->viewport()) { QMouseEvent* ev = static_cast(event); const QModelIndex index = ui->treeView->indexAt(ev->pos()); QRect rect = ui->treeView->visualRect(index); rect.moveTopLeft(ui->treeView->viewport()->mapToGlobal(rect.topLeft())); const QRect target = fontMetrics().boundingRect(rect, index.data(Qt::TextAlignmentRole).toInt(), index.data().toString()); if (index.column() == CErrorReportTableModel::ColumnObject && target.contains(QCursor::pos())) { ui->treeView->viewport()->setCursor(Qt::PointingHandCursor); } else { ui->treeView->viewport()->setCursor(Qt::ArrowCursor); } } return QWidget::eventFilter(watched, event); } // CErrorReportDialog message handlers void CErrorReportDialog::SetReport(CErrorReport* report) { m_pErrorReport = report; m_errorReportModel->setErrorReport(report); } void CErrorReportDialog::UpdateErrors() { m_errorReportModel->setErrorReport(m_pErrorReport); } ////////////////////////////////////////////////////////////////////////// #define ID_REMOVE_ITEM 1 #define ID_SORT_ASC 2 #define ID_SORT_DESC 3 #define ID_GROUP_BYTHIS 4 #define ID_SHOW_GROUPBOX 5 #define ID_SHOW_FIELDCHOOSER 6 #define ID_COLUMN_BESTFIT 7 #define ID_COLUMN_ARRANGEBY 100 #define ID_COLUMN_ALIGMENT 200 #define ID_COLUMN_ALIGMENT_LEFT ID_COLUMN_ALIGMENT + 1 #define ID_COLUMN_ALIGMENT_RIGHT ID_COLUMN_ALIGMENT + 2 #define ID_COLUMN_ALIGMENT_CENTER ID_COLUMN_ALIGMENT + 3 #define ID_COLUMN_SHOW 500 void CErrorReportDialog::OnReportColumnRClick() { QHeaderView* header = ui->treeView->header(); int column = header->logicalIndexAt(ui->treeView->mapFromGlobal(QCursor::pos())); if (column < 0) { return; } QMenu menu; QAction* actionSortAscending = menu.addAction(tr("Sort &Ascending")); QAction* actionSortDescending = menu.addAction(tr("Sort Des&cending")); menu.addSeparator(); QAction* actionGroupByThis = menu.addAction(tr("&Group by this field")); QAction* actionGroupByBox = menu.addAction(tr("Group &by box")); menu.addSeparator(); QAction* actionRemoveItem = menu.addAction(tr("&Remove column")); QAction* actionFieldChooser = menu.addAction(tr("Field &Chooser")); menu.addSeparator(); QAction* actionBestFit = menu.addAction(tr("Best &Fit")); actionGroupByBox->setCheckable(true); actionGroupByBox->setChecked(ui->treeView->IsGroupsShown()); // create arrange by items QMenu menuArrange; const int nColumnCount = m_errorReportModel->columnCount(); for (int nColumn = 0; nColumn < nColumnCount; nColumn++) { if (!header->isSectionHidden(nColumn)) { const QString sCaption = m_errorReportModel->headerData(nColumn, Qt::Horizontal).toString(); if (!sCaption.isEmpty()) { menuArrange.addAction(sCaption)->setData(nColumn); } } } menuArrange.addSeparator(); QAction* actionClearGroups = menuArrange.addAction(tr("Clear groups")); menuArrange.setTitle(tr("Arrange By")); menu.insertMenu(actionSortAscending, &menuArrange); // create columns items QMenu menuColumns; for (int nColumn = 0; nColumn < nColumnCount; nColumn++) { const QString sCaption = m_errorReportModel->headerData(nColumn, Qt::Horizontal).toString(); //if (!sCaption.isEmpty()) QAction* action = menuColumns.addAction(sCaption); action->setCheckable(true); action->setChecked(!ui->treeView->header()->isSectionHidden(nColumn)); } menuColumns.setTitle(tr("Columns")); menu.insertMenu(menuArrange.menuAction(), &menuColumns); //create Text alignment submenu QMenu menuAlign; QAction* actionAlignLeft = menuAlign.addAction(tr("Align Left")); QAction* actionAlignRight = menuAlign.addAction(tr("Align Right")); QAction* actionAlignCenter = menuAlign.addAction(tr("Align Center")); actionAlignLeft->setCheckable(true); actionAlignRight->setCheckable(true); actionAlignCenter->setCheckable(true); int nAlignOption = 0; const int alignment = m_errorReportModel->headerData(column, Qt::Horizontal, Qt::TextAlignmentRole).toInt(); actionAlignLeft->setChecked(alignment & Qt::AlignLeft); actionAlignRight->setChecked(alignment & Qt::AlignRight); actionAlignCenter->setChecked(alignment & Qt::AlignHCenter); menuAlign.setTitle(tr("&Alignment")); menu.insertMenu(actionBestFit, &menuAlign); // track menu QAction* nMenuResult = menu.exec(QCursor::pos()); // arrange by items if (menuArrange.actions().contains(nMenuResult)) { // group by item if (actionClearGroups == nMenuResult) { ui->treeView->ClearGroups(); } else { column = nMenuResult->data().toInt(); ui->treeView->ToggleSortOrder(column); } } // process Alignment options if (nMenuResult == actionAlignLeft) { m_errorReportModel->setHeaderData(column, Qt::Horizontal, Qt::AlignLeft, Qt::TextAlignmentRole); } else if (nMenuResult == actionAlignRight) { m_errorReportModel->setHeaderData(column, Qt::Horizontal, Qt::AlignRight, Qt::TextAlignmentRole); } else if (nMenuResult == actionAlignCenter) { m_errorReportModel->setHeaderData(column, Qt::Horizontal, Qt::AlignCenter, Qt::TextAlignmentRole); } // process column selection item if (menuColumns.actions().contains(nMenuResult)) { ui->treeView->header()->setSectionHidden(menuColumns.actions().indexOf(nMenuResult), !nMenuResult->isChecked()); } // other general items if (nMenuResult == actionSortAscending || nMenuResult == actionSortDescending) { ui->treeView->sortByColumn(column, nMenuResult == actionSortAscending ? Qt::AscendingOrder : Qt::DescendingOrder); } else if (nMenuResult == actionFieldChooser) { //OnShowFieldChooser(); } else if (nMenuResult == actionBestFit) { ui->treeView->resizeColumnToContents(column); } else if (nMenuResult == actionRemoveItem) { ui->treeView->header()->setSectionHidden(column, true); } // other general items else if (nMenuResult == actionGroupByThis) { ui->treeView->AddGroup(column); ui->treeView->ShowGroups(true); } else if (nMenuResult == actionGroupByBox) { ui->treeView->ShowGroups(!ui->treeView->IsGroupsShown()); } } #define ID_POPUP_COLLAPSEALLGROUPS 1 #define ID_POPUP_EXPANDALLGROUPS 2 ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::CopyToClipboard() { QString str; const QModelIndexList selRows = ui->treeView->selectionModel()->selectedRows(); for (const QModelIndex& index : selRows) { const CErrorRecord* pRecord = index.data(Qt::UserRole).value(); if (pRecord) { str += pRecord->GetErrorText(); if (pRecord->pObject) { str += QString::fromLatin1(" [Object: %1]").arg(pRecord->pObject->GetName()); } if (pRecord->pItem) { str += QString::fromLatin1(" [Material: %1]").arg(pRecord->pItem->GetName()); } str += QString::fromLatin1("\r\n"); } } if (!str.isEmpty()) { QApplication::clipboard()->setText(str); } } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::OnReportItemRClick() { const QModelIndex index = ui->treeView->indexAt(ui->treeView->viewport()->mapFromGlobal(QCursor::pos())); if (!index.isValid()) { return; } if (ui->treeView->model()->hasChildren(index)) { QMenu menu; menu.addAction(tr("Collapse &All Groups"), ui->treeView, SLOT(collapseAll())); menu.addAction(tr("E&xpand All Groups"), ui->treeView, SLOT(expandAll())); // track menu menu.exec(QCursor::pos()); } else { QMenu menu; //menu.addAction(tr("Select Object(s)")); // TODO: does nothing? menu.addAction(tr("Copy Warning(s) To Clipboard"), this, SLOT(CopyToClipboard())); menu.addAction(tr("E-mail Error Report"), this, SLOT(SendInMail())); menu.addAction(tr("Open in Excel"), this, SLOT(OpenInExcel())); // track menu menu.exec(QCursor::pos()); } } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::SendInMail() { if (!m_pErrorReport) { return; } // Send E-Mail. QString textMsg; for (int i = 0; i < m_errorReportModel->rowCount(); ++i) { const CErrorRecord* err = m_errorReportModel->index(i, 0).data(Qt::UserRole).value(); textMsg += err->GetErrorText() + QString::fromLatin1("\n"); } std::vector who; const QString subject = QString::fromLatin1("Level %1 Error Report").arg(GetIEditor()->GetGameEngine()->GetLevelPath()); CMailer::SendMail(subject.toUtf8().data(), textMsg.toUtf8().data(), who, who, true); } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::OpenInExcel() { if (!m_pErrorReport) { return; } const QString levelName = Path::GetFileName(GetIEditor()->GetGameEngine()->GetLevelName()); const QString filename = QString::fromLatin1("ErrorList_%1_%2.csv").arg(levelName).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")); // Save to temp file. QFile f(filename); if (f.open(QIODevice::WriteOnly)) { for (int i = 0; i < m_errorReportModel->rowCount(); ++i) { const CErrorRecord* err = m_errorReportModel->index(i, 0).data(Qt::UserRole).value(); QString text = err->GetErrorText(); text.replace(',', '.'); text.replace('\t', ','); f.write((text + QString::fromLatin1("\n")).toUtf8().data()); } f.close(); QDesktopServices::openUrl(QUrl::fromLocalFile(filename)); } else { Warning("Failed to save %s", (const char*)filename.toUtf8().data()); } } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::OnReportItemClick(const QModelIndex& index) { QRect rect = ui->treeView->visualRect(index); rect.moveTopLeft(ui->treeView->viewport()->mapToGlobal(rect.topLeft())); const QRect target = fontMetrics().boundingRect(rect, index.data(Qt::TextAlignmentRole).toInt(), index.data().toString()); if (index.column() == CErrorReportTableModel::ColumnObject && target.contains(QCursor::pos())) { OnReportHyperlink(index); } /* if (pItemNotify->pColumn->GetItemIndex() == COLUMN_CHECK) { m_wndReport.Populate(); } */ } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::keyPressEvent(QKeyEvent* event) { if (event->matches(QKeySequence::Copy)) { CopyToClipboard(); event->accept(); } else { QWidget::keyPressEvent(event); } } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::OnReportItemDblClick(const QModelIndex& index) { bool bDone = false; const CErrorRecord* pError = index.data(Qt::UserRole).value(); if (pError && pError->pObject != NULL) { CUndo undo("Select Object(s)"); // Clear other selection. GetIEditor()->ClearSelection(); // Select this object. GetIEditor()->SelectObject(pError->pObject); CViewport* vp = GetIEditor()->GetActiveView(); if (vp) { vp->CenterOnSelection(); } bDone = true; } if (pError && pError->pItem != NULL) { GetIEditor()->OpenDataBaseLibrary(pError->pItem->GetType(), pError->pItem); bDone = true; } if (!bDone && pError && GetIEditor()->GetActiveView()) { float x, y, z; if (GetPositionFromString(pError->error, &x, &y, &z)) { CViewport* vp = GetIEditor()->GetActiveView(); Matrix34 tm = vp->GetViewTM(); tm.SetTranslation(Vec3(x, y, z)); vp->SetViewTM(tm); } } /* if (index.isValid()) { TRACE(_T("Double Click on row %d\n"), index.row()); CErrorMessageRecord* pRecord = DYNAMIC_DOWNCAST(CErrorMessageRecord, pItemNotify->pRow->GetRecord()); if (pRecord) { { m_wndReport.Populate(); } } } */ } void CErrorReportDialog::OnSortIndicatorChanged(int logicalIndex, Qt::SortOrder order) { if (logicalIndex == 0) { ui->treeView->header()->setSortIndicator(m_sortIndicatorColumn, m_sortIndicatorOrder); } else { m_sortIndicatorColumn = logicalIndex; m_sortIndicatorOrder = order; } } ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::OnReportHyperlink(const QModelIndex& index) { const CErrorRecord* pError = index.data(Qt::UserRole).value(); bool bDone = false; if (pError && pError->pObject != NULL) { CUndo undo("Select Object(s)"); // Clear other selection. GetIEditor()->ClearSelection(); // Select this object. GetIEditor()->SelectObject(pError->pObject); bDone = true; } if (pError && pError->pItem != NULL) { GetIEditor()->OpenDataBaseLibrary(pError->pItem->GetType(), pError->pItem); bDone = true; } if (!bDone && pError && GetIEditor()->GetActiveView()) { float x, y, z; if (GetPositionFromString(pError->error, &x, &y, &z)) { CViewport* vp = GetIEditor()->GetActiveView(); Matrix34 tm = vp->GetViewTM(); tm.SetTranslation(Vec3(x, y, z)); vp->SetViewTM(tm); } } } /* ////////////////////////////////////////////////////////////////////////// void CErrorReportDialog::OnShowFieldChooser() { CMainFrm* pMainFrm = (CMainFrame*)AfxGetMainWnd(); if (pMainFrm) { BOOL bShow = !pMainFrm->m_wndFieldChooser.IsVisible(); pMainFrm->ShowControlBar(&pMainFrm->m_wndFieldChooser, bShow, FALSE); } } */ #include