///////////////////////////////////////////////////////////////////////////// // class CDocument is the main document data abstraction class CDocument : public CCmdTarget { DECLARE_DYNAMIC(CDocument) public: // Constructors CDocument(); // Attributes public: const CString& GetTitle() const; virtual void SetTitle(LPCTSTR lpszTitle); const CString& GetPathName() const; virtual void SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU = TRUE); CDocTemplate* GetDocTemplate() const; virtual BOOL IsModified(); virtual void SetModifiedFlag(BOOL bModified = TRUE); // Operations void AddView(CView* pView); void RemoveView(CView* pView); virtual POSITION GetFirstViewPosition() const; virtual CView* GetNextView(POSITION& rPosition) const; // Update Views (simple update - DAG only) void UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL); // Overridables // Special notifications virtual void OnChangedViewList(); // after Add or Remove view virtual void DeleteContents(); // delete doc items etc // File helpers virtual BOOL OnNewDocument(); virtual BOOL OnOpenDocument(LPCTSTR lpszPathName); virtual BOOL OnSaveDocument(LPCTSTR lpszPathName); virtual void OnCloseDocument(); virtual void ReportSaveLoadException(LPCTSTR lpszPathName, CException* e, BOOL bSaving, UINT nIDPDefault); virtual CFile* GetFile(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError); virtual void ReleaseFile(CFile* pFile, BOOL bAbort); // advanced overridables, closing down frame/doc, etc. virtual BOOL CanCloseFrame(CFrameWnd* pFrame); virtual BOOL SaveModified(); // return TRUE if ok to continue virtual void PreCloseFrame(CFrameWnd* pFrame); // Implementation protected: // default implementation CString m_strTitle; CString m_strPathName; CDocTemplate* m_pDocTemplate; CPtrList m_viewList; // list of views BOOL m_bModified; // changed since last saved public: BOOL m_bAutoDelete; // TRUE => delete document when no more views BOOL m_bEmbedded; // TRUE => document is being created by OLE #ifdef _DEBUG virtual void Dump(CDumpContext&) const; virtual void AssertValid() const; #endif //_DEBUG virtual ~CDocument(); // implementation helpers virtual BOOL DoSave(LPCTSTR lpszPathName, BOOL bReplace = TRUE); virtual BOOL DoFileSave(); virtual void UpdateFrameCounts(); void DisconnectViews(); void SendInitialUpdate(); // overridables for implementation virtual HMENU GetDefaultMenu(); // get menu depending on state virtual HACCEL GetDefaultAccelerator(); virtual void OnIdle(); virtual void OnFinalRelease(); virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo); friend class CDocTemplate; protected: // file menu commands //{{AFX_MSG(CDocument) afx_msg void OnFileClose(); afx_msg void OnFileSave(); afx_msg void OnFileSaveAs(); //}}AFX_MSG // mail enabling afx_msg void OnFileSendMail(); afx_msg void OnUpdateFileSendMail(CCmdUI* pCmdUI); DECLARE_MESSAGE_MAP() }; |
void CDocument::AddView(CView* pView) { ASSERT_VALID(pView); ASSERT(pView->m_pDocument == NULL); // must not be already attached ASSERT(m_viewList.Find(pView, NULL) == NULL); // must not be in list m_viewList.AddTail(pView); ASSERT(pView->m_pDocument == NULL); // must be un-attached pView->m_pDocument = this; OnChangedViewList(); // must be the last thing done to the document } |
void CDocument::RemoveView(CView* pView) { ASSERT_VALID(pView); ASSERT(pView->m_pDocument == this); // must be attached to us m_viewList.RemoveAt(m_viewList.Find(pView)); pView->m_pDocument = NULL; OnChangedViewList(); // must be the last thing done to the document } |
void CDocument::OnChangedViewList() { // if no more views on the document, delete ourself // not called if directly closing the document or terminating the app if (m_viewList.IsEmpty() && m_bAutoDelete) { OnCloseDocument(); return; } // update the frame counts as needed UpdateFrameCounts(); } |
void CDocument::DisconnectViews() { while (!m_viewList.IsEmpty()) { CView* pView = (CView*)m_viewList.RemoveHead(); ASSERT_VALID(pView); ASSERT_KINDOF(CView, pView); pView->m_pDocument = NULL; } } |
POSITION CDocument::GetFirstViewPosition() const { return m_viewList.GetHeadPosition(); } CView* CDocument::GetNextView(POSITION& rPosition) const { ASSERT(rPosition != BEFORE_START_POSITION); // use CDocument::GetFirstViewPosition instead ! if (rPosition == NULL) return NULL; // nothing left CView* pView = (CView*)m_viewList.GetNext(rPosition); ASSERT_KINDOF(CView, pView); return pView; } |
CFile* CDocument::GetFile(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError) { CMirrorFile* pFile = new CMirrorFile; ASSERT(pFile != NULL); if (!pFile->Open(lpszFileName, nOpenFlags, pError)) { delete pFile; pFile = NULL; } return pFile; } void CDocument::ReleaseFile(CFile* pFile, BOOL bAbort) { ASSERT_KINDOF(CFile, pFile); if (bAbort) pFile->Abort(); // will not throw an exception else pFile->Close(); delete pFile; } |
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName) { if (IsModified()) TRACE0("Warning: OnOpenDocument replaces an unsaved document. "); CFileException fe; CFile* pFile = GetFile(lpszPathName, CFile::modeRead|CFile::shareDenyWrite, &fe); if (pFile == NULL) { ReportSaveLoadException(lpszPathName, &fe,FALSE, AFX_IDP_FAILED_TO_OPEN_DOC); return FALSE; } DeleteContents(); SetModifiedFlag(); // dirty during de-serialize CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete); loadArchive.m_pDocument = this; loadArchive.m_bForceFlat = FALSE; TRY { CWaitCursor wait; if (pFile->GetLength() != 0) Serialize(loadArchive); // load me loadArchive.Close(); ReleaseFile(pFile, FALSE); } CATCH_ALL(e) { ReleaseFile(pFile, TRUE); DeleteContents(); // remove failed contents TRY { ReportSaveLoadException(lpszPathName, e,FALSE, AFX_IDP_FAILED_TO_OPEN_DOC); } END_TRY DELETE_EXCEPTION(e); return FALSE; } END_CATCH_ALL SetModifiedFlag(FALSE); // start off with unmodified return TRUE; } |
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName) { CFileException fe; CFile* pFile = NULL; pFile = GetFile(lpszPathName, CFile::modeCreate |CFile::modeReadWrite | CFile::shareExclusive, &fe); if (pFile == NULL) { ReportSaveLoadException(lpszPathName, &fe,TRUE, AFX_IDP_INVALID_FILENAME); return FALSE; } CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete); saveArchive.m_pDocument = this; saveArchive.m_bForceFlat = FALSE; TRY { CWaitCursor wait; Serialize(saveArchive); // save me saveArchive.Close(); ReleaseFile(pFile, FALSE); } CATCH_ALL(e) { ReleaseFile(pFile, TRUE); TRY { ReportSaveLoadException(lpszPathName, e,TRUE, AFX_IDP_FAILED_TO_SAVE_DOC); } END_TRY DELETE_EXCEPTION(e); return FALSE; } END_CATCH_ALL SetModifiedFlag(FALSE); // back to unmodified return TRUE; // success } |
void CDocument::OnCloseDocument() // must close all views now (no prompting) - usually destroys this { // destroy all frames viewing this document // the last destroy may destroy us BOOL bAutoDelete = m_bAutoDelete; m_bAutoDelete = FALSE; // dont destroy document while closing views while (!m_viewList.IsEmpty()) { // get frame attached to the view CView* pView = (CView*)m_viewList.GetHead(); ASSERT_VALID(pView); CFrameWnd* pFrame = pView->GetParentFrame(); ASSERT_VALID(pFrame); // and close it PreCloseFrame(pFrame); pFrame->DestroyWindow(); // will destroy the view as well } m_bAutoDelete = bAutoDelete; // clean up contents of document before destroying the document itself DeleteContents(); // delete the document if necessary if (m_bAutoDelete) delete this; } |
void CExampleDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here ar << var1 << var2; } else { // TODO: add loading code here var2 >> var1 >> ar; } } |
void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint) // walk through all views { ASSERT(pSender == NULL || !m_viewList.IsEmpty()); // must have views if sent by one of them POSITION pos = GetFirstViewPosition(); while (pos != NULL) { CView* pView = GetNextView(pos); ASSERT_VALID(pView); if (pView != pSender) pView->OnUpdate(pSender, lHint, pHint); } } |
afx_msg void OnFileNew(); afx_msg void OnFileOpen(); |
virtual void OnFileNew(); virtual void OnFileOpen(); virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); // open named file |
virtual CDocument* OpenDocumentFile( LPCTSTR lpszPathName, BOOL bMakeVisible = TRUE) = 0; // open named file // if lpszPathName == NULL => create new file with this type virtual CDocument* CreateNewDocument(); |
virtual BOOL OnNewDocument(); virtual BOOL OnOpenDocument(LPCTSTR lpszPathName); |
void CDocManager::OnFileNew(){ if (m_templateList.IsEmpty()) { ... return ; } //取第一个文档模板的指针 CDocTemplate *pTemplate = (CDocTemplate*)m_templateList.GetHead(); if (m_templateList.GetCount() > 1) { // 若是多于一个文档模板,弹出对话框提示用户选择 CNewTypeDlg dlg(&m_templateList); int nID = dlg.DoModal(); if (nID == IDOK) pTemplate = dlg.m_pSelectedTemplate; else return ; // none - cancel operation } … //参数为NULL的时候OpenDocument File会新建一个文件 pTemplate->OpenDocumentFile(NULL);} |