/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// // TracesView.cpp : implementation file // #include "stdafx.h" #include "odamfcapp.h" #include "TracesView.h" #include "DbDictionary.h" #include "DbViewportTableRecord.h" #define STL_USING_SET #include "OdaSTL.h" #ifndef MECHANICAL_MODE bool operator==(const OdTracesUsersEx::OdUserData& lhs, const OdTracesUsersEx::OdUserData& rhs) { if (lhs.m_oxygenId.isEmpty() || rhs.m_oxygenId.isEmpty()) return (lhs.m_firstName == rhs.m_firstName && lhs.m_lastName == rhs.m_lastName && lhs.m_userName == rhs.m_userName); return lhs.m_oxygenId == rhs.m_oxygenId; } IMPLEMENT_DYNAMIC(CTraceTabCollab, CDialog) CTraceTabCollab::CTraceTabCollab(CWnd* pParent /*=nullptr*/) : CDialog(IDD_TRACE_TAB_COLLAB, pParent) { } CTraceTabCollab::~CTraceTabCollab() { } void CTraceTabCollab::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_TRACE_COLLABORATORS, m_listCollaborators); } BEGIN_MESSAGE_MAP(CTraceTabCollab, CDialog) ON_NOTIFY(NM_DBLCLK, IDC_LIST_TRACE_COLLABORATORS, &CTraceTabCollab::OnNMDblclkListTraceCollaborators) END_MESSAGE_MAP() IMPLEMENT_DYNAMIC(CTraceTabUsers, CDialog) CTraceTabUsers::CTraceTabUsers(CWnd* pParent /*=nullptr*/) : CDialog(IDD_TRACE_TAB_USERS, pParent) { } CTraceTabUsers::~CTraceTabUsers() { } void CTraceTabUsers::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_TRACE_USERS, m_listTraceUsers); } void CTraceTabUsers::fillUsers() { m_listTraceUsers.DeleteAllItems(); while (m_listTraceUsers.DeleteColumn(0)); m_tracesUsers.m_users.clear(); CRect rect; m_listTraceUsers.GetClientRect(&rect); m_listTraceUsers.SetExtendedStyle(LVS_EX_FULLROWSELECT); m_listTraceUsers.InsertColumn(0, L"First name", LVCFMT_LEFT, (int)(rect.Width() / 3.2 )); m_listTraceUsers.InsertColumn(1, L"Last name", LVCFMT_LEFT, (int)(rect.Width() / 3.2), 1); m_listTraceUsers.InsertColumn(2, L"Username", LVCFMT_LEFT, (int)(rect.Width() / 3.3), 2); OdTraceRuntime* pTrace = OdTraceRuntime::getInstance(m_pDb); OdArray traces; if ( pTrace) pTrace->getTracesUserInfo(traces); for (auto i : traces) { OdArray collaborators; pTrace->getTraceCollaborators(i, collaborators); m_tracesUsers.add(collaborators); } OdTracesUsersEx::OdUserData odaUserExample; odaUserExample.m_firstName = L"Open"; odaUserExample.m_lastName = L"Design"; odaUserExample.m_userName = L"Alliance"; m_tracesUsers.add(odaUserExample); int i = 0; for(const auto& user : m_tracesUsers.m_users) { m_listTraceUsers.InsertItem(i, user.m_firstName); m_listTraceUsers.SetItemText(i, 1, user.m_lastName); m_listTraceUsers.SetItemText(i, 2, user.m_userName); ++i; } } BEGIN_MESSAGE_MAP(CTraceTabUsers, CDialog) ON_NOTIFY(NM_DBLCLK, IDC_LIST_TRACE_USERS, &CTraceTabUsers::OnNMDblclkListTraceUsers) ON_NOTIFY(NM_CLICK, IDC_LIST_TRACE_USERS, &CTraceTabUsers::OnNMClickListTraceUsers) END_MESSAGE_MAP() /* * * * * * * VIEW * * * * * */ // TracesView dialog IMPLEMENT_DYNAMIC(CTracesViewDlg, CDialog) CTracesViewDlg::CTracesViewDlg(CWnd* pParent /*=nullptr*/) : CDialog(IDD_TRACES_VIEW, pParent) { } CTracesViewDlg::~CTracesViewDlg() { } void CTracesViewDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_TRACE, m_listTraces); DDX_Control(pDX, IDOPEN, m_openButton); DDX_Control(pDX, IDCLOSE, m_closeButton); DDX_Control(pDX, IDC_NEW_TRACE, m_newTraceButton); DDX_Control(pDX, IDC_RADIO_TRACE_FRONT, m_radioTraceFront); DDX_Control(pDX, IDC_RADIO_TRACE_BACK, m_radioTraceBack); DDX_Control(pDX, IDC_TRACE_TAB, m_tabCtrl); } BEGIN_MESSAGE_MAP(CTracesViewDlg, CDialog) ON_BN_CLICKED(IDOPEN, &CTracesViewDlg::OnBnClickedOpen) ON_BN_CLICKED(IDCLOSE, &CTracesViewDlg::OnBnClickedClose) ON_NOTIFY(NM_CLICK, IDC_LIST_TRACE, &CTracesViewDlg::OnNMClickListTrace) ON_WM_ACTIVATE() ON_WM_SHOWWINDOW() ON_BN_CLICKED(IDC_RADIO_TRACE_FRONT, &CTracesViewDlg::OnBnClickedRadioTraceFront) ON_BN_CLICKED(IDC_RADIO_TRACE_BACK, &CTracesViewDlg::OnBnClickedRadioTraceBack) ON_BN_CLICKED(IDC_NEW_TRACE, &CTracesViewDlg::OnBnClickedNewTrace) ON_NOTIFY(TCN_SELCHANGE, IDC_TRACE_TAB, &CTracesViewDlg::OnTcnSelchangeTraceTab) ON_BN_CLICKED(IDC_REMOVE_TARCE, &CTracesViewDlg::OnBnClickedRemoveTarce) END_MESSAGE_MAP() void CTracesViewDlg::resetData() { m_openedTraceRowIndex = -1; m_listTraces.DeleteAllItems(); while (m_listTraces.DeleteColumn(0)); while (m_tabCollab.m_listCollaborators.DeleteColumn(0)); m_tabCollab.m_listCollaborators.DeleteAllItems(); while (m_listTraces.DeleteColumn(0)); while (m_tabCollab.m_listCollaborators.DeleteColumn(0)); m_tabCollab.m_listCollaborators.EnableWindow(0); m_openButton.EnableWindow(1); m_closeButton.EnableWindow(0); m_traceInfoArr.clear(); m_listTraces.EnableWindow(1); m_radioTraceFront.EnableWindow(0); m_radioTraceBack.EnableWindow(0); } // TracesView message handlers void CTracesViewDlg::changeButtonStateOnCloseTrace(const OdResult eRes, const int selectedRow) { if (eRes == eOk) { m_listTraces.EnableWindow(1); m_listTraces.SetSelectionMark(selectedRow); m_openButton.EnableWindow(1); m_closeButton.EnableWindow(0); m_listTraces.EnableWindow(1); m_radioTraceFront.EnableWindow(0); m_radioTraceBack.EnableWindow(0); m_openedTraceRowIndex = -1; m_newTraceButton.EnableWindow(1); m_tabUsers.EnableWindow(1); } fillCollaboratorsList(); forceRegenView(); } void CTracesViewDlg::changeButtonStateOnOpenTrace(const bool updateCollaboratos) { if(updateCollaboratos) fillCollaboratorsList(); forceRegenView(); m_newTraceButton.EnableWindow(0); m_openButton.EnableWindow(0); m_closeButton.EnableWindow(1); m_tabCollab.m_listCollaborators.EnableWindow(1); m_listTraces.EnableWindow(0); m_radioTraceFront.EnableWindow(1); m_radioTraceBack.EnableWindow(1); m_radioTraceFront.SetCheck(1); m_radioTraceBack.SetCheck(0); m_tabUsers.EnableWindow(0); } void CTracesViewDlg::OnBnClickedOpen() { if (m_pDb->getTRACEMODE() != 0) return; const int selectedRow = m_listTraces.GetSelectionMark(); if (selectedRow == -1) return; if (selectedRow < (int)m_traceInfoArr.size()) { OdTraceRuntime* pTraceRuntime = OdTraceRuntime::getInstance(m_pDb); m_pDb->startUndoRecord(); OdResult eRes = pTraceRuntime->openTrace(m_traceInfoArr[selectedRow]); ODA_ASSERT(eRes == eOk); if(eRes != eOk) throw eRes; OdGeExtents3d ext; pTraceRuntime->getOpenTraceExtents(ext); if (ext.isValidExtents()) { OdGeMatrix3d matScale; matScale.setToScaling(3, ext.center()); ext.transformBy(matScale); OdDbViewportTableRecordPtr pViewPort = m_pDb->activeViewportId().safeOpenObject(OdDb::kForWrite); pViewPort->setHeight(abs(ext.maxPoint().y - ext.minPoint().y)); pViewPort->setWidth(abs(ext.maxPoint().x - ext.minPoint().x)); pViewPort->setCenterPoint(ext.center().convert2d()); } } m_openedTraceRowIndex = selectedRow; changeButtonStateOnOpenTrace(); } void CTracesViewDlg::OnBnClickedClose() { int selectedRow = m_listTraces.GetSelectionMark(); OdTraceRuntime* pTraceRuntime = OdTraceRuntime::getInstance(m_pDb); m_pDb->startUndoRecord(); OdResult eRes = pTraceRuntime->closeTrace(); ODA_ASSERT(eRes == eOk); if (eRes != eOk) throw eRes; if (selectedRow == -1) { OdArray traces; pTraceRuntime->getTracesUserInfo(traces); selectedRow = traces.length() - 1;//new trace } changeButtonStateOnCloseTrace(eRes, selectedRow); updateTraceListView(); } BOOL CTracesViewDlg::OnInitDialog() { CDialog::OnInitDialog(); m_tabCollab.Create(IDD_TRACE_TAB_COLLAB, &m_tabCtrl); TCITEM tabCollabItem; tabCollabItem.mask = TCIF_TEXT | TCIF_PARAM; tabCollabItem.lParam = (LPARAM)&m_tabCollab; tabCollabItem.pszText = L"Collaborators"; m_tabCtrl.InsertItem(0, &tabCollabItem); CRect rectTabCtrl; m_tabCtrl.GetItemRect(0, &rectTabCtrl); m_tabCollab.SetWindowPos(0, rectTabCtrl.left-10, rectTabCtrl.bottom-4, 0, 0, SWP_NOSIZE | SWP_NOZORDER); m_tabCollab.ShowWindow(SW_SHOW); m_tabCollab.m_owner = this; m_tabUsers.Create(IDD_TRACE_TAB_USERS, &m_tabCtrl); TCITEM tabUsersItem; tabUsersItem.mask = TCIF_TEXT | TCIF_PARAM; tabUsersItem.lParam = (LPARAM)&m_tabUsers; tabUsersItem.pszText = L"Users"; m_tabCtrl.InsertItem(1, &tabUsersItem); m_tabCtrl.GetItemRect(1, &rectTabCtrl); m_tabUsers.SetWindowPos(0, rectTabCtrl.left - 90, rectTabCtrl.bottom - 4, 0, 0, SWP_NOSIZE | SWP_NOZORDER); m_tabUsers.ShowWindow(SW_HIDE); resetData(); return TRUE; } void CTracesViewDlg::addOdaDefaultUser() { m_tabUsers.m_pDb = m_pDb; m_tabUsers.fillUsers(); OdTraceUserProfile traceUser; traceUser.m_firstName = m_tabUsers.m_tracesUsers.m_users.last().m_firstName; traceUser.m_lastName = m_tabUsers.m_tracesUsers.m_users.last().m_lastName; traceUser.m_userName = m_tabUsers.m_tracesUsers.m_users.last().m_userName; traceUser.m_oxygenID = m_tabUsers.m_tracesUsers.m_users.last().m_oxygenId; m_pDb->startUndoRecord(); OdTraceRuntime::getInstance(m_pDb)->setCurrentUserInfo(traceUser); m_tabUsers.m_tracesUsers.m_currentUser = m_tabUsers.m_tracesUsers.m_users.size() - 1; } void CTracesViewDlg::forceRegenView() { if (m_pDwgViewer && m_pDwgViewer->getDevice()) m_pDwgViewer->OnViewerRegen(); } void CTracesViewDlg::updateTraceListView() { m_listTraces.DeleteAllItems(); m_traceInfoArr.clear(); while (m_listTraces.DeleteColumn(0)); while (m_tabCollab.m_listCollaborators.DeleteColumn(0)); CRect rect; m_listTraces.GetClientRect(&rect); m_listTraces.SetExtendedStyle(LVS_EX_FULLROWSELECT); m_listTraces.InsertColumn(0, L"Name", LVCFMT_LEFT, (int)(rect.Width() / 8.5)); m_listTraces.InsertColumn(1, L"Created", LVCFMT_LEFT, (int)(rect.Width() / 2.2), 1); m_listTraces.InsertColumn(2, L"Last modified", LVCFMT_LEFT, (int)(rect.Width() / 2.2), 2); m_tabCollab.m_listCollaborators.SetExtendedStyle(LVS_EX_FULLROWSELECT); m_tabCollab.m_listCollaborators.InsertColumn(0, L"Collaborators", LVCFMT_LEFT, rect.Width() / 6); m_tabCollab.m_listCollaborators.InsertColumn(1, L"Visible", LVCFMT_LEFT, rect.Width() / 20, 1); OdDbObjectId dicId = m_pDb->getNamedObjectsDictionaryId(); OdDbDictionaryPtr pDir = dicId.openObject(); OdDbObjectId id = pDir->getAt(L"ACAD_TRACESTORE"); if (id.isNull()) return; OdDbTraceStorePtr objTrace = id.openObject(); OdArray traceInfoArr = objTrace->getTraceUserInfo(); m_traceInfoArr = traceInfoArr; for (unsigned int i = 0; i < traceInfoArr.size(); ++i) { m_listTraces.InsertItem(i, traceInfoArr[i].m_traceName); OdString created = "Author: \"" + traceInfoArr[i].m_createdBy.m_firstName + " " + traceInfoArr[i].m_createdBy.m_lastName + "(" + traceInfoArr[i].m_createdBy.m_userName + ")\" " + traceInfoArr[i].m_createdBy.m_date; m_listTraces.SetItemText(i, 1, created); OdString edited = "Author: \"" + traceInfoArr[i].m_lastSavedBy.m_firstName + " " + traceInfoArr[i].m_lastSavedBy.m_lastName + "(" + traceInfoArr[i].m_lastSavedBy.m_userName + ")\" " + traceInfoArr[i].m_lastSavedBy.m_date; m_listTraces.SetItemText(i, 2, edited);//m_lastSavedBy } fillCollaboratorsList(); if (m_openedTraceRowIndex != -1) { m_listTraces.SetItemState(m_openedTraceRowIndex, ~LVIS_SELECTED, LVIS_SELECTED); m_listTraces.SetItemState(m_openedTraceRowIndex, LVIS_SELECTED, LVIS_SELECTED); m_listTraces.SetSelectionMark(m_openedTraceRowIndex); m_listTraces.UpdateWindow(); } } void CTracesViewDlg::OnNMClickListTrace(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); fillCollaboratorsList(); *pResult = 0; } void CTracesViewDlg::fillCollaboratorsList() { m_tabCollab.m_listCollaborators.DeleteAllItems(); const int selectedRow = m_openedTraceRowIndex == -1 ? m_listTraces.GetSelectionMark() : m_openedTraceRowIndex; if (selectedRow >= static_cast(m_traceInfoArr.size()) || selectedRow < 0) return; OdArray collaborators; OdResult eRes = OdTraceRuntime::getInstance(m_pDb)->getTraceCollaborators(m_traceInfoArr[selectedRow], collaborators); ODA_ASSERT(eRes == eOk); for (unsigned int i = 0; i < collaborators.size(); ++i) { OdString sInfo = collaborators[i].getFirstName() + " " + collaborators[i].getLastName() + " (" + collaborators[i].getUserName() + ")"; m_tabCollab.m_listCollaborators.InsertItem(i, sInfo); m_tabCollab.m_listCollaborators.SetItemText(i, 1, collaborators[i].isVisible() == OdDb::kVisible ? L"+" : L"-"); } } void CTracesViewDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CDialog::OnActivate(nState, pWndOther, bMinimized); } void CTracesViewDlg::OnShowWindow(BOOL bShow, UINT nStatus) { CDialog::OnShowWindow(bShow, nStatus); if (bShow == 0) return; updateTraceListView(); if (OdTraceRuntime::getInstance(m_pDb) && OdTraceRuntime::getInstance(m_pDb)->getCurrentUserInfo().isEmpty()) addOdaDefaultUser(); } void CTraceTabCollab::OnNMDblclkListTraceCollaborators(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); if (m_owner->m_pDb->getTRACEMODE() == 0) return; const int selectedRow = m_listCollaborators.GetSelectionMark(); if (selectedRow == -1) return; OdArray collaborators; OdTraceRuntime* pTrace = OdTraceRuntime::getInstance(m_owner->m_pDb); OdResult eRes = pTrace->getTraceCollaborators(m_owner->m_traceInfoArr[m_owner->m_openedTraceRowIndex], collaborators); ODA_ASSERT(eRes == eOk); if (selectedRow >= (int)collaborators.size()) return; if (collaborators[selectedRow].getOxygenId() == pTrace->getCurrentUserInfo().m_oxygenID) return;//opened trace can't be invisiable collaborators[selectedRow].setVisible(collaborators[selectedRow].isVisible() == OdDb::Visibility::kInvisible ? OdDb::Visibility::kVisible : OdDb::Visibility::kInvisible); m_owner->m_pDb->startUndoRecord(); eRes = OdTraceRuntime::getInstance(m_owner->m_pDb)->showOpenTraceCollaborators(collaborators); ODA_ASSERT(eRes == eOk); m_owner->fillCollaboratorsList(); m_owner->forceRegenView(); *pResult = 0; } void CTracesViewDlg::OnBnClickedRadioTraceFront() { if (m_pDb->getTRACEMODE() == 2) return; m_pDb->startUndoRecord(); OdResult eRes = OdTraceRuntime::getInstance(m_pDb)->traceFront(); ODA_ASSERT(eRes == eOk); forceRegenView(); } void CTracesViewDlg::OnBnClickedRadioTraceBack() { if (m_pDb->getTRACEMODE() == 1) return; m_pDb->startUndoRecord(); OdResult eRes = OdTraceRuntime::getInstance(m_pDb)->traceBack(); ODA_ASSERT(eRes == eOk); forceRegenView(); } void CTracesViewDlg::OnBnClickedNewTrace() { if (m_pDb->getTRACEMODE() != 0) return; OdTraceUserProfile user(L"ODA", L"OdaMfcApp", L"OdaDebugApp"); if (OdTraceRuntime::getInstance(m_pDb) == 0) { m_pDb->startUndoRecord(); OdTraceRuntime::getInstance(m_pDb, true); } if (OdTraceRuntime::getInstance(m_pDb)->getCurrentUserInfo().isEmpty()) { addOdaDefaultUser(); } m_pDb->startUndoRecord(); OdResult eRes = OdTraceRuntime::getInstance(m_pDb)->newTrace(); ODA_ASSERT(eRes == eOk); changeButtonStateOnOpenTrace(false); } void CTracesViewDlg::OnTcnSelchangeTraceTab(NMHDR* pNMHDR, LRESULT* pResult) { const int tabSelected = m_tabCtrl.GetCurSel(); if (tabSelected == 0) { m_tabCollab.ShowWindow(SW_SHOW); m_tabUsers.ShowWindow(SW_HIDE); } else if(tabSelected == 1) { m_tabCollab.ShowWindow(SW_HIDE); m_tabUsers.ShowWindow(SW_SHOW); m_tabUsers.m_pDb = m_pDb; m_tabUsers.fillUsers(); if (!m_tabUsers.m_tracesUsers.m_users.isEmpty() && m_tabUsers.m_tracesUsers.m_currentUser != -1) { m_tabUsers.m_listTraceUsers.SetItemState(m_tabUsers.m_tracesUsers.m_currentUser, ~LVIS_SELECTED, LVIS_SELECTED); m_tabUsers.m_listTraceUsers.SetItemState(m_tabUsers.m_tracesUsers.m_currentUser, LVIS_SELECTED, LVIS_SELECTED); m_tabUsers.m_listTraceUsers.SetSelectionMark(m_tabUsers.m_tracesUsers.m_currentUser); m_tabUsers.m_listTraceUsers.UpdateWindow(); } } *pResult = 0; } void CTraceTabUsers::setSelectedUser() { if (m_pDb->getTRACEMODE() != 0) return; const int selectedRow = m_listTraceUsers.GetSelectionMark(); if (selectedRow == -1 || selectedRow >= (int)m_tracesUsers.m_users.length()) return; OdTraceUserProfile traceUser; traceUser.m_firstName = m_tracesUsers.m_users[selectedRow].m_firstName; traceUser.m_lastName = m_tracesUsers.m_users[selectedRow].m_lastName; traceUser.m_userName = m_tracesUsers.m_users[selectedRow].m_userName; traceUser.m_oxygenID = m_tracesUsers.m_users[selectedRow].m_oxygenId; m_pDb->startUndoRecord(); OdTraceRuntime::getInstance(m_pDb)->setCurrentUserInfo(traceUser); m_tracesUsers.m_currentUser = selectedRow; } void CTraceTabUsers::OnNMDblclkListTraceUsers(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); setSelectedUser(); *pResult = 0; } #endif void CTraceTabUsers::OnNMClickListTraceUsers(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); setSelectedUser(); *pResult = 0; } void CTracesViewDlg::OnBnClickedRenameTrace() { // TODO: Add your control notification handler code here } void CTracesViewDlg::OnBnClickedRemoveTarce() { OdTraceRuntime* pTrace = OdTraceRuntime::getInstance(m_pDb); const int selectedRow = m_listTraces.GetSelectionMark(); if (pTrace == nullptr || selectedRow == -1) return; OdResult eRes = pTrace->removeTrace(m_traceInfoArr[selectedRow]); if (eRes != eOk) throw OdError(eRes); updateTraceListView(); }