PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/ExtLibs/wxWidgets/src/common/docview.cpp

https://bitbucket.org/lennonchan/cafu
C++ | 1783 lines | 1271 code | 296 blank | 216 comment | 195 complexity | 3958485f6ca4b4f243120a2184b609f9 MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/common/docview.cpp
  3. // Purpose: Document/view classes
  4. // Author: Julian Smart
  5. // Modified by: Vadim Zeitlin
  6. // Created: 01/02/97
  7. // RCS-ID: $Id$
  8. // Copyright: (c) Julian Smart
  9. // Licence: wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11. // ============================================================================
  12. // declarations
  13. // ============================================================================
  14. // ----------------------------------------------------------------------------
  15. // headers
  16. // ----------------------------------------------------------------------------
  17. // For compilers that support precompilation, includes "wx.h".
  18. #include "wx/wxprec.h"
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22. #if wxUSE_DOC_VIEW_ARCHITECTURE
  23. #include "wx/docview.h"
  24. #ifndef WX_PRECOMP
  25. #include "wx/list.h"
  26. #include "wx/string.h"
  27. #include "wx/utils.h"
  28. #include "wx/app.h"
  29. #include "wx/dc.h"
  30. #include "wx/dialog.h"
  31. #include "wx/menu.h"
  32. #include "wx/filedlg.h"
  33. #include "wx/intl.h"
  34. #include "wx/log.h"
  35. #include "wx/msgdlg.h"
  36. #include "wx/mdi.h"
  37. #include "wx/choicdlg.h"
  38. #endif
  39. #if wxUSE_PRINTING_ARCHITECTURE
  40. #include "wx/prntbase.h"
  41. #include "wx/printdlg.h"
  42. #endif
  43. #include "wx/confbase.h"
  44. #include "wx/filename.h"
  45. #include "wx/file.h"
  46. #include "wx/ffile.h"
  47. #include "wx/cmdproc.h"
  48. #include "wx/tokenzr.h"
  49. #include "wx/filename.h"
  50. #include "wx/stdpaths.h"
  51. #include "wx/vector.h"
  52. #include "wx/scopedarray.h"
  53. #include "wx/scopedptr.h"
  54. #include "wx/except.h"
  55. #if wxUSE_STD_IOSTREAM
  56. #include "wx/ioswrap.h"
  57. #include "wx/beforestd.h"
  58. #if wxUSE_IOSTREAMH
  59. #include <fstream.h>
  60. #else
  61. #include <fstream>
  62. #endif
  63. #include "wx/afterstd.h"
  64. #else
  65. #include "wx/wfstream.h"
  66. #endif
  67. typedef wxVector<wxDocTemplate *> wxDocTemplates;
  68. // ----------------------------------------------------------------------------
  69. // wxWidgets macros
  70. // ----------------------------------------------------------------------------
  71. IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler)
  72. IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler)
  73. IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject)
  74. IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler)
  75. IMPLEMENT_CLASS(wxDocChildFrame, wxFrame)
  76. IMPLEMENT_CLASS(wxDocParentFrame, wxFrame)
  77. #if wxUSE_PRINTING_ARCHITECTURE
  78. IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout)
  79. #endif
  80. // ============================================================================
  81. // implementation
  82. // ============================================================================
  83. // ----------------------------------------------------------------------------
  84. // private helpers
  85. // ----------------------------------------------------------------------------
  86. namespace
  87. {
  88. wxString FindExtension(const wxString& path)
  89. {
  90. wxString ext;
  91. wxFileName::SplitPath(path, NULL, NULL, &ext);
  92. // VZ: extensions are considered not case sensitive - is this really a good
  93. // idea?
  94. return ext.MakeLower();
  95. }
  96. } // anonymous namespace
  97. // ----------------------------------------------------------------------------
  98. // Definition of wxDocument
  99. // ----------------------------------------------------------------------------
  100. wxDocument::wxDocument(wxDocument *parent)
  101. {
  102. m_documentModified = false;
  103. m_documentTemplate = NULL;
  104. m_documentParent = parent;
  105. if ( parent )
  106. parent->m_childDocuments.push_back(this);
  107. m_commandProcessor = NULL;
  108. m_savedYet = false;
  109. }
  110. bool wxDocument::DeleteContents()
  111. {
  112. return true;
  113. }
  114. wxDocument::~wxDocument()
  115. {
  116. delete m_commandProcessor;
  117. if (GetDocumentManager())
  118. GetDocumentManager()->RemoveDocument(this);
  119. if ( m_documentParent )
  120. m_documentParent->m_childDocuments.remove(this);
  121. // Not safe to do here, since it'll invoke virtual view functions
  122. // expecting to see valid derived objects: and by the time we get here,
  123. // we've called destructors higher up.
  124. //DeleteAllViews();
  125. }
  126. bool wxDocument::Close()
  127. {
  128. if ( !OnSaveModified() )
  129. return false;
  130. // When the parent document closes, its children must be closed as well as
  131. // they can't exist without the parent.
  132. // As usual, first check if all children can be closed.
  133. DocsList::const_iterator it = m_childDocuments.begin();
  134. for ( DocsList::const_iterator end = m_childDocuments.end(); it != end; ++it )
  135. {
  136. if ( !(*it)->OnSaveModified() )
  137. {
  138. // Leave the parent document opened if a child can't close.
  139. return false;
  140. }
  141. }
  142. // Now that they all did, do close them: as m_childDocuments is modified as
  143. // we iterate over it, don't use the usual for-style iteration here.
  144. while ( !m_childDocuments.empty() )
  145. {
  146. wxDocument * const childDoc = m_childDocuments.front();
  147. // This will call OnSaveModified() once again but it shouldn't do
  148. // anything as the document was just saved or marked as not needing to
  149. // be saved by the call to OnSaveModified() that returned true above.
  150. if ( !childDoc->Close() )
  151. {
  152. wxFAIL_MSG( "Closing the child document unexpectedly failed "
  153. "after its OnSaveModified() returned true" );
  154. }
  155. // Delete the child document by deleting all its views.
  156. childDoc->DeleteAllViews();
  157. }
  158. return OnCloseDocument();
  159. }
  160. bool wxDocument::OnCloseDocument()
  161. {
  162. // Tell all views that we're about to close
  163. NotifyClosing();
  164. DeleteContents();
  165. Modify(false);
  166. return true;
  167. }
  168. // Note that this implicitly deletes the document when the last view is
  169. // deleted.
  170. bool wxDocument::DeleteAllViews()
  171. {
  172. wxDocManager* manager = GetDocumentManager();
  173. // first check if all views agree to be closed
  174. const wxList::iterator end = m_documentViews.end();
  175. for ( wxList::iterator i = m_documentViews.begin(); i != end; ++i )
  176. {
  177. wxView *view = (wxView *)*i;
  178. if ( !view->Close() )
  179. return false;
  180. }
  181. // all views agreed to close, now do close them
  182. if ( m_documentViews.empty() )
  183. {
  184. // normally the document would be implicitly deleted when the last view
  185. // is, but if don't have any views, do it here instead
  186. if ( manager && manager->GetDocuments().Member(this) )
  187. delete this;
  188. }
  189. else // have views
  190. {
  191. // as we delete elements we iterate over, don't use the usual "from
  192. // begin to end" loop
  193. for ( ;; )
  194. {
  195. wxView *view = (wxView *)*m_documentViews.begin();
  196. bool isLastOne = m_documentViews.size() == 1;
  197. // this always deletes the node implicitly and if this is the last
  198. // view also deletes this object itself (also implicitly, great),
  199. // so we can't test for m_documentViews.empty() after calling this!
  200. delete view;
  201. if ( isLastOne )
  202. break;
  203. }
  204. }
  205. return true;
  206. }
  207. wxView *wxDocument::GetFirstView() const
  208. {
  209. if ( m_documentViews.empty() )
  210. return NULL;
  211. return static_cast<wxView *>(m_documentViews.GetFirst()->GetData());
  212. }
  213. void wxDocument::Modify(bool mod)
  214. {
  215. if (mod != m_documentModified)
  216. {
  217. m_documentModified = mod;
  218. // Allow views to append asterix to the title
  219. wxView* view = GetFirstView();
  220. if (view) view->OnChangeFilename();
  221. }
  222. }
  223. wxDocManager *wxDocument::GetDocumentManager() const
  224. {
  225. // For child documents we use the same document manager as the parent, even
  226. // though we don't have our own template (as children are not opened/saved
  227. // directly).
  228. if ( m_documentParent )
  229. return m_documentParent->GetDocumentManager();
  230. return m_documentTemplate ? m_documentTemplate->GetDocumentManager() : NULL;
  231. }
  232. bool wxDocument::OnNewDocument()
  233. {
  234. // notice that there is no need to neither reset nor even check the
  235. // modified flag here as the document itself is a new object (this is only
  236. // called from CreateDocument()) and so it shouldn't be saved anyhow even
  237. // if it is modified -- this could happen if the user code creates
  238. // documents pre-filled with some user-entered (and which hence must not be
  239. // lost) information
  240. SetDocumentSaved(false);
  241. const wxString name = GetDocumentManager()->MakeNewDocumentName();
  242. SetTitle(name);
  243. SetFilename(name, true);
  244. return true;
  245. }
  246. bool wxDocument::Save()
  247. {
  248. if ( AlreadySaved() )
  249. return true;
  250. if ( m_documentFile.empty() || !m_savedYet )
  251. return SaveAs();
  252. return OnSaveDocument(m_documentFile);
  253. }
  254. bool wxDocument::SaveAs()
  255. {
  256. wxDocTemplate *docTemplate = GetDocumentTemplate();
  257. if (!docTemplate)
  258. return false;
  259. #ifdef wxHAS_MULTIPLE_FILEDLG_FILTERS
  260. wxString filter = docTemplate->GetDescription() + wxT(" (") +
  261. docTemplate->GetFileFilter() + wxT(")|") +
  262. docTemplate->GetFileFilter();
  263. // Now see if there are some other template with identical view and document
  264. // classes, whose filters may also be used.
  265. if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo())
  266. {
  267. wxList::compatibility_iterator
  268. node = docTemplate->GetDocumentManager()->GetTemplates().GetFirst();
  269. while (node)
  270. {
  271. wxDocTemplate *t = (wxDocTemplate*) node->GetData();
  272. if (t->IsVisible() && t != docTemplate &&
  273. t->GetViewClassInfo() == docTemplate->GetViewClassInfo() &&
  274. t->GetDocClassInfo() == docTemplate->GetDocClassInfo())
  275. {
  276. // add a '|' to separate this filter from the previous one
  277. if ( !filter.empty() )
  278. filter << wxT('|');
  279. filter << t->GetDescription()
  280. << wxT(" (") << t->GetFileFilter() << wxT(") |")
  281. << t->GetFileFilter();
  282. }
  283. node = node->GetNext();
  284. }
  285. }
  286. #else
  287. wxString filter = docTemplate->GetFileFilter() ;
  288. #endif
  289. wxString defaultDir = docTemplate->GetDirectory();
  290. if ( defaultDir.empty() )
  291. {
  292. defaultDir = wxPathOnly(GetFilename());
  293. if ( defaultDir.empty() )
  294. defaultDir = GetDocumentManager()->GetLastDirectory();
  295. }
  296. wxString fileName = wxFileSelector(_("Save As"),
  297. defaultDir,
  298. wxFileNameFromPath(GetFilename()),
  299. docTemplate->GetDefaultExtension(),
  300. filter,
  301. wxFD_SAVE | wxFD_OVERWRITE_PROMPT,
  302. GetDocumentWindow());
  303. if (fileName.empty())
  304. return false; // cancelled by user
  305. // Files that were not saved correctly are not added to the FileHistory.
  306. if (!OnSaveDocument(fileName))
  307. return false;
  308. SetTitle(wxFileNameFromPath(fileName));
  309. SetFilename(fileName, true); // will call OnChangeFileName automatically
  310. // A file that doesn't use the default extension of its document template
  311. // cannot be opened via the FileHistory, so we do not add it.
  312. if (docTemplate->FileMatchesTemplate(fileName))
  313. {
  314. GetDocumentManager()->AddFileToHistory(fileName);
  315. }
  316. //else: the user will probably not be able to open the file again, so we
  317. // could warn about the wrong file-extension here
  318. return true;
  319. }
  320. bool wxDocument::OnSaveDocument(const wxString& file)
  321. {
  322. if ( !file )
  323. return false;
  324. if ( !DoSaveDocument(file) )
  325. return false;
  326. Modify(false);
  327. SetFilename(file);
  328. SetDocumentSaved(true);
  329. #if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON
  330. wxFileName fn(file) ;
  331. fn.MacSetDefaultTypeAndCreator() ;
  332. #endif
  333. return true;
  334. }
  335. bool wxDocument::OnOpenDocument(const wxString& file)
  336. {
  337. // notice that there is no need to check the modified flag here for the
  338. // reasons explained in OnNewDocument()
  339. if ( !DoOpenDocument(file) )
  340. return false;
  341. SetFilename(file, true);
  342. // stretching the logic a little this does make sense because the document
  343. // had been saved into the file we just loaded it from, it just could have
  344. // happened during a previous program execution, it's just that the name of
  345. // this method is a bit unfortunate, it should probably have been called
  346. // HasAssociatedFileName()
  347. SetDocumentSaved(true);
  348. UpdateAllViews();
  349. return true;
  350. }
  351. #if wxUSE_STD_IOSTREAM
  352. wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream)
  353. #else
  354. wxInputStream& wxDocument::LoadObject(wxInputStream& stream)
  355. #endif
  356. {
  357. return stream;
  358. }
  359. #if wxUSE_STD_IOSTREAM
  360. wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream)
  361. #else
  362. wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream)
  363. #endif
  364. {
  365. return stream;
  366. }
  367. bool wxDocument::Revert()
  368. {
  369. if ( wxMessageBox
  370. (
  371. _("Discard changes and reload the last saved version?"),
  372. wxTheApp->GetAppDisplayName(),
  373. wxYES_NO | wxCANCEL | wxICON_QUESTION,
  374. GetDocumentWindow()
  375. ) != wxYES )
  376. return false;
  377. if ( !DoOpenDocument(GetFilename()) )
  378. return false;
  379. Modify(false);
  380. UpdateAllViews();
  381. return true;
  382. }
  383. // Get title, or filename if no title, else unnamed
  384. #if WXWIN_COMPATIBILITY_2_8
  385. bool wxDocument::GetPrintableName(wxString& buf) const
  386. {
  387. // this function cannot only be overridden by the user code but also
  388. // called by it so we need to ensure that we return the same thing as
  389. // GetUserReadableName() but we can't call it because this would result in
  390. // an infinite recursion, hence we use the helper DoGetUserReadableName()
  391. buf = DoGetUserReadableName();
  392. return true;
  393. }
  394. #endif // WXWIN_COMPATIBILITY_2_8
  395. wxString wxDocument::GetUserReadableName() const
  396. {
  397. #if WXWIN_COMPATIBILITY_2_8
  398. // we need to call the old virtual function to ensure that the overridden
  399. // version of it is still called
  400. wxString name;
  401. if ( GetPrintableName(name) )
  402. return name;
  403. #endif // WXWIN_COMPATIBILITY_2_8
  404. return DoGetUserReadableName();
  405. }
  406. wxString wxDocument::DoGetUserReadableName() const
  407. {
  408. if ( !m_documentTitle.empty() )
  409. return m_documentTitle;
  410. if ( !m_documentFile.empty() )
  411. return wxFileNameFromPath(m_documentFile);
  412. return _("unnamed");
  413. }
  414. wxWindow *wxDocument::GetDocumentWindow() const
  415. {
  416. wxView * const view = GetFirstView();
  417. return view ? view->GetFrame() : wxTheApp->GetTopWindow();
  418. }
  419. wxCommandProcessor *wxDocument::OnCreateCommandProcessor()
  420. {
  421. return new wxCommandProcessor;
  422. }
  423. // true if safe to close
  424. bool wxDocument::OnSaveModified()
  425. {
  426. if ( IsModified() )
  427. {
  428. switch ( wxMessageBox
  429. (
  430. wxString::Format
  431. (
  432. _("Do you want to save changes to %s?"),
  433. GetUserReadableName()
  434. ),
  435. wxTheApp->GetAppDisplayName(),
  436. wxYES_NO | wxCANCEL | wxICON_QUESTION | wxCENTRE
  437. ) )
  438. {
  439. case wxNO:
  440. Modify(false);
  441. break;
  442. case wxYES:
  443. return Save();
  444. case wxCANCEL:
  445. return false;
  446. }
  447. }
  448. return true;
  449. }
  450. bool wxDocument::Draw(wxDC& WXUNUSED(context))
  451. {
  452. return true;
  453. }
  454. bool wxDocument::AddView(wxView *view)
  455. {
  456. if ( !m_documentViews.Member(view) )
  457. {
  458. m_documentViews.Append(view);
  459. OnChangedViewList();
  460. }
  461. return true;
  462. }
  463. bool wxDocument::RemoveView(wxView *view)
  464. {
  465. (void)m_documentViews.DeleteObject(view);
  466. OnChangedViewList();
  467. return true;
  468. }
  469. bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags)
  470. {
  471. return GetDocumentTemplate()->CreateView(this, flags) != NULL;
  472. }
  473. // Called after a view is added or removed.
  474. // The default implementation deletes the document if
  475. // there are no more views.
  476. void wxDocument::OnChangedViewList()
  477. {
  478. if ( m_documentViews.empty() && OnSaveModified() )
  479. delete this;
  480. }
  481. void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint)
  482. {
  483. wxList::compatibility_iterator node = m_documentViews.GetFirst();
  484. while (node)
  485. {
  486. wxView *view = (wxView *)node->GetData();
  487. if (view != sender)
  488. view->OnUpdate(sender, hint);
  489. node = node->GetNext();
  490. }
  491. }
  492. void wxDocument::NotifyClosing()
  493. {
  494. wxList::compatibility_iterator node = m_documentViews.GetFirst();
  495. while (node)
  496. {
  497. wxView *view = (wxView *)node->GetData();
  498. view->OnClosingDocument();
  499. node = node->GetNext();
  500. }
  501. }
  502. void wxDocument::SetFilename(const wxString& filename, bool notifyViews)
  503. {
  504. m_documentFile = filename;
  505. OnChangeFilename(notifyViews);
  506. }
  507. void wxDocument::OnChangeFilename(bool notifyViews)
  508. {
  509. if ( notifyViews )
  510. {
  511. // Notify the views that the filename has changed
  512. wxList::compatibility_iterator node = m_documentViews.GetFirst();
  513. while (node)
  514. {
  515. wxView *view = (wxView *)node->GetData();
  516. view->OnChangeFilename();
  517. node = node->GetNext();
  518. }
  519. }
  520. }
  521. bool wxDocument::DoSaveDocument(const wxString& file)
  522. {
  523. #if wxUSE_STD_IOSTREAM
  524. wxSTD ofstream store(file.mb_str(), wxSTD ios::binary);
  525. if ( !store )
  526. #else
  527. wxFileOutputStream store(file);
  528. if ( store.GetLastError() != wxSTREAM_NO_ERROR )
  529. #endif
  530. {
  531. wxLogError(_("File \"%s\" could not be opened for writing."), file);
  532. return false;
  533. }
  534. if (!SaveObject(store))
  535. {
  536. wxLogError(_("Failed to save document to the file \"%s\"."), file);
  537. return false;
  538. }
  539. return true;
  540. }
  541. bool wxDocument::DoOpenDocument(const wxString& file)
  542. {
  543. #if wxUSE_STD_IOSTREAM
  544. wxSTD ifstream store(file.mb_str(), wxSTD ios::binary);
  545. if ( !store )
  546. #else
  547. wxFileInputStream store(file);
  548. if (store.GetLastError() != wxSTREAM_NO_ERROR || !store.IsOk())
  549. #endif
  550. {
  551. wxLogError(_("File \"%s\" could not be opened for reading."), file);
  552. return false;
  553. }
  554. #if wxUSE_STD_IOSTREAM
  555. LoadObject(store);
  556. if ( !store )
  557. #else
  558. int res = LoadObject(store).GetLastError();
  559. if ( res != wxSTREAM_NO_ERROR && res != wxSTREAM_EOF )
  560. #endif
  561. {
  562. wxLogError(_("Failed to read document from the file \"%s\"."), file);
  563. return false;
  564. }
  565. return true;
  566. }
  567. // ----------------------------------------------------------------------------
  568. // Document view
  569. // ----------------------------------------------------------------------------
  570. wxView::wxView()
  571. {
  572. m_viewDocument = NULL;
  573. m_viewFrame = NULL;
  574. m_docChildFrame = NULL;
  575. }
  576. wxView::~wxView()
  577. {
  578. if (m_viewDocument && GetDocumentManager())
  579. GetDocumentManager()->ActivateView(this, false);
  580. // reset our frame view first, before removing it from the document as
  581. // SetView(NULL) is a simple call while RemoveView() may result in user
  582. // code being executed and this user code can, for example, show a message
  583. // box which would result in an activation event for m_docChildFrame and so
  584. // could reactivate the view being destroyed -- unless we reset it first
  585. if ( m_docChildFrame && m_docChildFrame->GetView() == this )
  586. {
  587. // prevent it from doing anything with us
  588. m_docChildFrame->SetView(NULL);
  589. // it doesn't make sense to leave the frame alive if its associated
  590. // view doesn't exist any more so unconditionally close it as well
  591. //
  592. // notice that we only get here if m_docChildFrame is non-NULL in the
  593. // first place and it will be always NULL if we're deleted because our
  594. // frame was closed, so this only catches the case of directly deleting
  595. // the view, as it happens if its creation fails in wxDocTemplate::
  596. // CreateView() for example
  597. m_docChildFrame->GetWindow()->Destroy();
  598. }
  599. if ( m_viewDocument )
  600. m_viewDocument->RemoveView(this);
  601. }
  602. void wxView::SetDocChildFrame(wxDocChildFrameAnyBase *docChildFrame)
  603. {
  604. SetFrame(docChildFrame ? docChildFrame->GetWindow() : NULL);
  605. m_docChildFrame = docChildFrame;
  606. }
  607. bool wxView::TryBefore(wxEvent& event)
  608. {
  609. wxDocument * const doc = GetDocument();
  610. return doc && doc->ProcessEventLocally(event);
  611. }
  612. void wxView::OnActivateView(bool WXUNUSED(activate),
  613. wxView *WXUNUSED(activeView),
  614. wxView *WXUNUSED(deactiveView))
  615. {
  616. }
  617. void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info))
  618. {
  619. OnDraw(dc);
  620. }
  621. void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
  622. {
  623. }
  624. void wxView::OnChangeFilename()
  625. {
  626. // GetFrame can return wxWindow rather than wxTopLevelWindow due to
  627. // generic MDI implementation so use SetLabel rather than SetTitle.
  628. // It should cause SetTitle() for top level windows.
  629. wxWindow *win = GetFrame();
  630. if (!win) return;
  631. wxDocument *doc = GetDocument();
  632. if (!doc) return;
  633. wxString label = doc->GetUserReadableName();
  634. if (doc->IsModified())
  635. {
  636. label += "*";
  637. }
  638. win->SetLabel(label);
  639. }
  640. void wxView::SetDocument(wxDocument *doc)
  641. {
  642. m_viewDocument = doc;
  643. if (doc)
  644. doc->AddView(this);
  645. }
  646. bool wxView::Close(bool deleteWindow)
  647. {
  648. return OnClose(deleteWindow);
  649. }
  650. void wxView::Activate(bool activate)
  651. {
  652. if (GetDocument() && GetDocumentManager())
  653. {
  654. OnActivateView(activate, this, GetDocumentManager()->GetCurrentView());
  655. GetDocumentManager()->ActivateView(this, activate);
  656. }
  657. }
  658. bool wxView::OnClose(bool WXUNUSED(deleteWindow))
  659. {
  660. return GetDocument() ? GetDocument()->Close() : true;
  661. }
  662. #if wxUSE_PRINTING_ARCHITECTURE
  663. wxPrintout *wxView::OnCreatePrintout()
  664. {
  665. return new wxDocPrintout(this);
  666. }
  667. #endif // wxUSE_PRINTING_ARCHITECTURE
  668. // ----------------------------------------------------------------------------
  669. // wxDocTemplate
  670. // ----------------------------------------------------------------------------
  671. wxDocTemplate::wxDocTemplate(wxDocManager *manager,
  672. const wxString& descr,
  673. const wxString& filter,
  674. const wxString& dir,
  675. const wxString& ext,
  676. const wxString& docTypeName,
  677. const wxString& viewTypeName,
  678. wxClassInfo *docClassInfo,
  679. wxClassInfo *viewClassInfo,
  680. long flags)
  681. {
  682. m_documentManager = manager;
  683. m_description = descr;
  684. m_directory = dir;
  685. m_defaultExt = ext;
  686. m_fileFilter = filter;
  687. m_flags = flags;
  688. m_docTypeName = docTypeName;
  689. m_viewTypeName = viewTypeName;
  690. m_documentManager->AssociateTemplate(this);
  691. m_docClassInfo = docClassInfo;
  692. m_viewClassInfo = viewClassInfo;
  693. }
  694. wxDocTemplate::~wxDocTemplate()
  695. {
  696. m_documentManager->DisassociateTemplate(this);
  697. }
  698. // Tries to dynamically construct an object of the right class.
  699. wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags)
  700. {
  701. // InitDocument() is supposed to delete the document object if its
  702. // initialization fails so don't use wxScopedPtr<> here: this is fragile
  703. // but unavoidable because the default implementation uses CreateView()
  704. // which may -- or not -- create a wxView and if it does create it and its
  705. // initialization fails then the view destructor will delete the document
  706. // (via RemoveView()) and as we can't distinguish between the two cases we
  707. // just have to assume that it always deletes it in case of failure
  708. wxDocument * const doc = DoCreateDocument();
  709. return doc && InitDocument(doc, path, flags) ? doc : NULL;
  710. }
  711. bool
  712. wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags)
  713. {
  714. doc->SetFilename(path);
  715. doc->SetDocumentTemplate(this);
  716. GetDocumentManager()->AddDocument(doc);
  717. doc->SetCommandProcessor(doc->OnCreateCommandProcessor());
  718. if (doc->OnCreate(path, flags))
  719. return true;
  720. if (GetDocumentManager()->GetDocuments().Member(doc))
  721. doc->DeleteAllViews();
  722. return false;
  723. }
  724. wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags)
  725. {
  726. wxScopedPtr<wxView> view(DoCreateView());
  727. if ( !view )
  728. return NULL;
  729. view->SetDocument(doc);
  730. if ( !view->OnCreate(doc, flags) )
  731. return NULL;
  732. return view.release();
  733. }
  734. // The default (very primitive) format detection: check is the extension is
  735. // that of the template
  736. bool wxDocTemplate::FileMatchesTemplate(const wxString& path)
  737. {
  738. wxStringTokenizer parser (GetFileFilter(), wxT(";"));
  739. wxString anything = wxT ("*");
  740. while (parser.HasMoreTokens())
  741. {
  742. wxString filter = parser.GetNextToken();
  743. wxString filterExt = FindExtension (filter);
  744. if ( filter.IsSameAs (anything) ||
  745. filterExt.IsSameAs (anything) ||
  746. filterExt.IsSameAs (FindExtension (path)) )
  747. return true;
  748. }
  749. return GetDefaultExtension().IsSameAs(FindExtension(path));
  750. }
  751. wxDocument *wxDocTemplate::DoCreateDocument()
  752. {
  753. if (!m_docClassInfo)
  754. return NULL;
  755. return static_cast<wxDocument *>(m_docClassInfo->CreateObject());
  756. }
  757. wxView *wxDocTemplate::DoCreateView()
  758. {
  759. if (!m_viewClassInfo)
  760. return NULL;
  761. return static_cast<wxView *>(m_viewClassInfo->CreateObject());
  762. }
  763. // ----------------------------------------------------------------------------
  764. // wxDocManager
  765. // ----------------------------------------------------------------------------
  766. BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler)
  767. EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen)
  768. EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose)
  769. EVT_MENU(wxID_CLOSE_ALL, wxDocManager::OnFileCloseAll)
  770. EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert)
  771. EVT_MENU(wxID_NEW, wxDocManager::OnFileNew)
  772. EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave)
  773. EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs)
  774. EVT_MENU(wxID_UNDO, wxDocManager::OnUndo)
  775. EVT_MENU(wxID_REDO, wxDocManager::OnRedo)
  776. // We don't know in advance how many items can there be in the MRU files
  777. // list so set up OnMRUFile() as a handler for all menu events and do the
  778. // check for the id of the menu item clicked inside it.
  779. EVT_MENU(wxID_ANY, wxDocManager::OnMRUFile)
  780. EVT_UPDATE_UI(wxID_OPEN, wxDocManager::OnUpdateFileOpen)
  781. EVT_UPDATE_UI(wxID_CLOSE, wxDocManager::OnUpdateDisableIfNoDoc)
  782. EVT_UPDATE_UI(wxID_CLOSE_ALL, wxDocManager::OnUpdateDisableIfNoDoc)
  783. EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert)
  784. EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew)
  785. EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave)
  786. EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs)
  787. EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo)
  788. EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo)
  789. #if wxUSE_PRINTING_ARCHITECTURE
  790. EVT_MENU(wxID_PRINT, wxDocManager::OnPrint)
  791. EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview)
  792. EVT_MENU(wxID_PRINT_SETUP, wxDocManager::OnPageSetup)
  793. EVT_UPDATE_UI(wxID_PRINT, wxDocManager::OnUpdateDisableIfNoDoc)
  794. EVT_UPDATE_UI(wxID_PREVIEW, wxDocManager::OnUpdateDisableIfNoDoc)
  795. // NB: we keep "Print setup" menu item always enabled as it can be used
  796. // even without an active document
  797. #endif // wxUSE_PRINTING_ARCHITECTURE
  798. END_EVENT_TABLE()
  799. wxDocManager* wxDocManager::sm_docManager = NULL;
  800. wxDocManager::wxDocManager(long WXUNUSED(flags), bool initialize)
  801. {
  802. sm_docManager = this;
  803. m_defaultDocumentNameCounter = 1;
  804. m_currentView = NULL;
  805. m_maxDocsOpen = INT_MAX;
  806. m_fileHistory = NULL;
  807. if ( initialize )
  808. Initialize();
  809. }
  810. wxDocManager::~wxDocManager()
  811. {
  812. Clear();
  813. delete m_fileHistory;
  814. sm_docManager = NULL;
  815. }
  816. // closes the specified document
  817. bool wxDocManager::CloseDocument(wxDocument* doc, bool force)
  818. {
  819. if ( !doc->Close() && !force )
  820. return false;
  821. // Implicitly deletes the document when
  822. // the last view is deleted
  823. doc->DeleteAllViews();
  824. // Check we're really deleted
  825. if (m_docs.Member(doc))
  826. delete doc;
  827. return true;
  828. }
  829. bool wxDocManager::CloseDocuments(bool force)
  830. {
  831. wxList::compatibility_iterator node = m_docs.GetFirst();
  832. while (node)
  833. {
  834. wxDocument *doc = (wxDocument *)node->GetData();
  835. wxList::compatibility_iterator next = node->GetNext();
  836. if (!CloseDocument(doc, force))
  837. return false;
  838. // This assumes that documents are not connected in
  839. // any way, i.e. deleting one document does NOT
  840. // delete another.
  841. node = next;
  842. }
  843. return true;
  844. }
  845. bool wxDocManager::Clear(bool force)
  846. {
  847. if (!CloseDocuments(force))
  848. return false;
  849. m_currentView = NULL;
  850. wxList::compatibility_iterator node = m_templates.GetFirst();
  851. while (node)
  852. {
  853. wxDocTemplate *templ = (wxDocTemplate*) node->GetData();
  854. wxList::compatibility_iterator next = node->GetNext();
  855. delete templ;
  856. node = next;
  857. }
  858. return true;
  859. }
  860. bool wxDocManager::Initialize()
  861. {
  862. m_fileHistory = OnCreateFileHistory();
  863. return true;
  864. }
  865. wxString wxDocManager::GetLastDirectory() const
  866. {
  867. // if we haven't determined the last used directory yet, do it now
  868. if ( m_lastDirectory.empty() )
  869. {
  870. // we're going to modify m_lastDirectory in this const method, so do it
  871. // via non-const self pointer instead of const this one
  872. wxDocManager * const self = const_cast<wxDocManager *>(this);
  873. // first try to reuse the directory of the most recently opened file:
  874. // this ensures that if the user opens a file, closes the program and
  875. // runs it again the "Open file" dialog will open in the directory of
  876. // the last file he used
  877. if ( m_fileHistory && m_fileHistory->GetCount() )
  878. {
  879. const wxString lastOpened = m_fileHistory->GetHistoryFile(0);
  880. const wxFileName fn(lastOpened);
  881. if ( fn.DirExists() )
  882. {
  883. self->m_lastDirectory = fn.GetPath();
  884. }
  885. //else: should we try the next one?
  886. }
  887. //else: no history yet
  888. // if we don't have any files in the history (yet?), use the
  889. // system-dependent default location for the document files
  890. if ( m_lastDirectory.empty() )
  891. {
  892. self->m_lastDirectory = wxStandardPaths::Get().GetAppDocumentsDir();
  893. }
  894. }
  895. return m_lastDirectory;
  896. }
  897. wxFileHistory *wxDocManager::OnCreateFileHistory()
  898. {
  899. return new wxFileHistory;
  900. }
  901. void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event))
  902. {
  903. wxDocument *doc = GetCurrentDocument();
  904. if (doc)
  905. CloseDocument(doc);
  906. }
  907. void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event))
  908. {
  909. CloseDocuments(false);
  910. }
  911. void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
  912. {
  913. CreateNewDocument();
  914. }
  915. void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
  916. {
  917. if ( !CreateDocument("") )
  918. {
  919. OnOpenFileFailure();
  920. }
  921. }
  922. void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
  923. {
  924. wxDocument *doc = GetCurrentDocument();
  925. if (!doc)
  926. return;
  927. doc->Revert();
  928. }
  929. void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
  930. {
  931. wxDocument *doc = GetCurrentDocument();
  932. if (!doc)
  933. return;
  934. doc->Save();
  935. }
  936. void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
  937. {
  938. wxDocument *doc = GetCurrentDocument();
  939. if (!doc)
  940. return;
  941. doc->SaveAs();
  942. }
  943. void wxDocManager::OnMRUFile(wxCommandEvent& event)
  944. {
  945. // Check if the id is in the range assigned to MRU list entries.
  946. const int id = event.GetId();
  947. if ( id >= wxID_FILE1 &&
  948. id < wxID_FILE1 + static_cast<int>(m_fileHistory->GetCount()) )
  949. {
  950. DoOpenMRUFile(id - wxID_FILE1);
  951. }
  952. else
  953. {
  954. event.Skip();
  955. }
  956. }
  957. void wxDocManager::DoOpenMRUFile(unsigned n)
  958. {
  959. wxString filename(GetHistoryFile(n));
  960. if ( filename.empty() )
  961. return;
  962. wxString errMsg; // must contain exactly one "%s" if non-empty
  963. if ( wxFile::Exists(filename) )
  964. {
  965. // try to open it
  966. if ( CreateDocument(filename, wxDOC_SILENT) )
  967. return;
  968. errMsg = _("The file '%s' couldn't be opened.");
  969. }
  970. else // file doesn't exist
  971. {
  972. errMsg = _("The file '%s' doesn't exist and couldn't be opened.");
  973. }
  974. wxASSERT_MSG( !errMsg.empty(), "should have an error message" );
  975. // remove the file which we can't open from the MRU list
  976. RemoveFileFromHistory(n);
  977. // and tell the user about it
  978. wxLogError(errMsg + '\n' +
  979. _("It has been removed from the most recently used files list."),
  980. filename);
  981. }
  982. #if wxUSE_PRINTING_ARCHITECTURE
  983. void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event))
  984. {
  985. wxView *view = GetActiveView();
  986. if (!view)
  987. return;
  988. wxPrintout *printout = view->OnCreatePrintout();
  989. if (printout)
  990. {
  991. wxPrintDialogData printDialogData(m_pageSetupDialogData.GetPrintData());
  992. wxPrinter printer(&printDialogData);
  993. printer.Print(view->GetFrame(), printout, true);
  994. delete printout;
  995. }
  996. }
  997. void wxDocManager::OnPageSetup(wxCommandEvent& WXUNUSED(event))
  998. {
  999. wxPageSetupDialog dlg(wxTheApp->GetTopWindow(), &m_pageSetupDialogData);
  1000. if ( dlg.ShowModal() == wxID_OK )
  1001. {
  1002. m_pageSetupDialogData = dlg.GetPageSetupData();
  1003. }
  1004. }
  1005. wxPreviewFrame* wxDocManager::CreatePreviewFrame(wxPrintPreviewBase* preview,
  1006. wxWindow *parent,
  1007. const wxString& title)
  1008. {
  1009. return new wxPreviewFrame(preview, parent, title);
  1010. }
  1011. void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event))
  1012. {
  1013. wxBusyCursor busy;
  1014. wxView *view = GetActiveView();
  1015. if (!view)
  1016. return;
  1017. wxPrintout *printout = view->OnCreatePrintout();
  1018. if (printout)
  1019. {
  1020. wxPrintDialogData printDialogData(m_pageSetupDialogData.GetPrintData());
  1021. // Pass two printout objects: for preview, and possible printing.
  1022. wxPrintPreviewBase *
  1023. preview = new wxPrintPreview(printout,
  1024. view->OnCreatePrintout(),
  1025. &printDialogData);
  1026. if ( !preview->IsOk() )
  1027. {
  1028. delete preview;
  1029. wxLogError(_("Print preview creation failed."));
  1030. return;
  1031. }
  1032. wxPreviewFrame* frame = CreatePreviewFrame(preview,
  1033. wxTheApp->GetTopWindow(),
  1034. _("Print Preview"));
  1035. wxCHECK_RET( frame, "should create a print preview frame" );
  1036. frame->Centre(wxBOTH);
  1037. frame->Initialize();
  1038. frame->Show(true);
  1039. }
  1040. }
  1041. #endif // wxUSE_PRINTING_ARCHITECTURE
  1042. void wxDocManager::OnUndo(wxCommandEvent& event)
  1043. {
  1044. wxCommandProcessor * const cmdproc = GetCurrentCommandProcessor();
  1045. if ( !cmdproc )
  1046. {
  1047. event.Skip();
  1048. return;
  1049. }
  1050. cmdproc->Undo();
  1051. }
  1052. void wxDocManager::OnRedo(wxCommandEvent& event)
  1053. {
  1054. wxCommandProcessor * const cmdproc = GetCurrentCommandProcessor();
  1055. if ( !cmdproc )
  1056. {
  1057. event.Skip();
  1058. return;
  1059. }
  1060. cmdproc->Redo();
  1061. }
  1062. // Handlers for UI update commands
  1063. void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event)
  1064. {
  1065. // CreateDocument() (which is called from OnFileOpen) may succeed
  1066. // only when there is at least a template:
  1067. event.Enable( GetTemplates().GetCount()>0 );
  1068. }
  1069. void wxDocManager::OnUpdateDisableIfNoDoc(wxUpdateUIEvent& event)
  1070. {
  1071. event.Enable( GetCurrentDocument() != NULL );
  1072. }
  1073. void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event)
  1074. {
  1075. wxDocument* doc = GetCurrentDocument();
  1076. event.Enable(doc && doc->IsModified() && doc->GetDocumentSaved());
  1077. }
  1078. void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event)
  1079. {
  1080. // CreateDocument() (which is called from OnFileNew) may succeed
  1081. // only when there is at least a template:
  1082. event.Enable( GetTemplates().GetCount()>0 );
  1083. }
  1084. void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event)
  1085. {
  1086. wxDocument * const doc = GetCurrentDocument();
  1087. event.Enable( doc && !doc->IsChildDocument() && !doc->AlreadySaved() );
  1088. }
  1089. void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event)
  1090. {
  1091. wxDocument * const doc = GetCurrentDocument();
  1092. event.Enable( doc && !doc->IsChildDocument() );
  1093. }
  1094. void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event)
  1095. {
  1096. wxCommandProcessor * const cmdproc = GetCurrentCommandProcessor();
  1097. if ( !cmdproc )
  1098. {
  1099. event.Enable(false);
  1100. return;
  1101. }
  1102. event.Enable(cmdproc->CanUndo());
  1103. cmdproc->SetMenuStrings();
  1104. }
  1105. void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event)
  1106. {
  1107. wxCommandProcessor * const cmdproc = GetCurrentCommandProcessor();
  1108. if ( !cmdproc )
  1109. {
  1110. event.Enable(false);
  1111. return;
  1112. }
  1113. event.Enable(cmdproc->CanRedo());
  1114. cmdproc->SetMenuStrings();
  1115. }
  1116. wxView *wxDocManager::GetActiveView() const
  1117. {
  1118. wxView *view = GetCurrentView();
  1119. if ( !view && !m_docs.empty() )
  1120. {
  1121. // if we have exactly one document, consider its view to be the current
  1122. // one
  1123. //
  1124. // VZ: I'm not exactly sure why is this needed but this is how this
  1125. // code used to behave before the bug #9518 was fixed and it seems
  1126. // safer to preserve the old logic
  1127. wxList::compatibility_iterator node = m_docs.GetFirst();
  1128. if ( !node->GetNext() )
  1129. {
  1130. wxDocument *doc = static_cast<wxDocument *>(node->GetData());
  1131. view = doc->GetFirstView();
  1132. }
  1133. //else: we have more than one document
  1134. }
  1135. return view;
  1136. }
  1137. bool wxDocManager::TryBefore(wxEvent& event)
  1138. {
  1139. wxView * const view = GetActiveView();
  1140. return view && view->ProcessEventLocally(event);
  1141. }
  1142. namespace
  1143. {
  1144. // helper function: return only the visible templates
  1145. wxDocTemplates GetVisibleTemplates(const wxList& allTemplates)
  1146. {
  1147. // select only the visible templates
  1148. const size_t totalNumTemplates = allTemplates.GetCount();
  1149. wxDocTemplates templates;
  1150. if ( totalNumTemplates )
  1151. {
  1152. templates.reserve(totalNumTemplates);
  1153. for ( wxList::const_iterator i = allTemplates.begin(),
  1154. end = allTemplates.end();
  1155. i != end;
  1156. ++i )
  1157. {
  1158. wxDocTemplate * const temp = (wxDocTemplate *)*i;
  1159. if ( temp->IsVisible() )
  1160. templates.push_back(temp);
  1161. }
  1162. }
  1163. return templates;
  1164. }
  1165. } // anonymous namespace
  1166. void wxDocManager::ActivateDocument(wxDocument *doc)
  1167. {
  1168. wxView * const view = doc->GetFirstView();
  1169. if ( !view )
  1170. return;
  1171. view->Activate(true);
  1172. if ( wxWindow *win = view->GetFrame() )
  1173. win->SetFocus();
  1174. }
  1175. wxDocument *wxDocManager::CreateDocument(const wxString& pathOrig, long flags)
  1176. {
  1177. // this ought to be const but SelectDocumentType/Path() are not
  1178. // const-correct and can't be changed as, being virtual, this risks
  1179. // breaking user code overriding them
  1180. wxDocTemplates templates(GetVisibleTemplates(m_templates));
  1181. const size_t numTemplates = templates.size();
  1182. if ( !numTemplates )
  1183. {
  1184. // no templates can be used, can't create document
  1185. return NULL;
  1186. }
  1187. // normally user should select the template to use but wxDOC_SILENT flag we
  1188. // choose one ourselves
  1189. wxString path = pathOrig; // may be modified below
  1190. wxDocTemplate *temp;
  1191. if ( flags & wxDOC_SILENT )
  1192. {
  1193. wxASSERT_MSG( !path.empty(),
  1194. "using empty path with wxDOC_SILENT doesn't make sense" );
  1195. temp = FindTemplateForPath(path);
  1196. if ( !temp )
  1197. {
  1198. wxLogWarning(_("The format of file '%s' couldn't be determined."),
  1199. path);
  1200. }
  1201. }
  1202. else // not silent, ask the user
  1203. {
  1204. // for the new file we need just the template, for an existing one we
  1205. // need the template and the path, unless it's already specified
  1206. if ( (flags & wxDOC_NEW) || !path.empty() )
  1207. temp = SelectDocumentType(&templates[0], numTemplates);
  1208. else
  1209. temp = SelectDocumentPath(&templates[0], numTemplates, path, flags);
  1210. }
  1211. if ( !temp )
  1212. return NULL;
  1213. // check whether the document with this path is already opened
  1214. if ( !path.empty() )
  1215. {
  1216. const wxFileName fn(path);
  1217. for ( wxList::const_iterator i = m_docs.begin(); i != m_docs.end(); ++i )
  1218. {
  1219. wxDocument * const doc = (wxDocument*)*i;
  1220. if ( fn == doc->GetFilename() )
  1221. {
  1222. // file already open, just activate it and return
  1223. ActivateDocument(doc);
  1224. return doc;
  1225. }
  1226. }
  1227. }
  1228. // no, we need to create a new document
  1229. // if we've reached the max number of docs, close the first one.
  1230. if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen )
  1231. {
  1232. if ( !CloseDocument((wxDocument *)GetDocuments().GetFirst()->GetData()) )
  1233. {
  1234. // can't open the new document if closing the old one failed
  1235. return NULL;
  1236. }
  1237. }
  1238. // do create and initialize the new document finally
  1239. wxDocument * const docNew = temp->CreateDocument(path, flags);
  1240. if ( !docNew )
  1241. return NULL;
  1242. docNew->SetDocumentName(temp->GetDocumentName());
  1243. docNew->SetDocumentTemplate(temp);
  1244. wxTRY
  1245. {
  1246. // call the appropriate function depending on whether we're creating a
  1247. // new file or opening an existing one
  1248. if ( !(flags & wxDOC_NEW ? docNew->OnNewDocument()
  1249. : docNew->OnOpenDocument(path)) )
  1250. {
  1251. docNew->DeleteAllViews();
  1252. return NULL;
  1253. }
  1254. }
  1255. wxCATCH_ALL( docNew->DeleteAllViews(); throw; )
  1256. // add the successfully opened file to MRU, but only if we're going to be
  1257. // able to reopen it successfully later which requires the template for
  1258. // this document to be retrievable from the file extension
  1259. if ( !(flags & wxDOC_NEW) && temp->FileMatchesTemplate(path) )
  1260. AddFileToHistory(path);
  1261. // at least under Mac (where views are top level windows) it seems to be
  1262. // necessary to manually activate the new document to bring it to the
  1263. // forefront -- and it shouldn't hurt doing this under the other platforms
  1264. ActivateDocument(docNew);
  1265. return docNew;
  1266. }
  1267. wxView *wxDocManager::CreateView(wxDocument *doc, long flags)
  1268. {
  1269. wxDocTemplates templates(GetVisibleTemplates(m_templates));
  1270. const size_t numTemplates = templates.size();
  1271. if ( numTemplates == 0 )
  1272. return NULL;
  1273. wxDocTemplate * const
  1274. temp = numTemplates == 1 ? templates[0]
  1275. : SelectViewType(&templates[0], numTemplates);
  1276. if ( !temp )
  1277. return NULL;
  1278. wxView *view = temp->CreateView(doc, flags);
  1279. if ( view )
  1280. view->SetViewName(temp->GetViewName());
  1281. return view;
  1282. }
  1283. // Not yet implemented
  1284. void
  1285. wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
  1286. {
  1287. }
  1288. // Not yet implemented
  1289. bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
  1290. {
  1291. return false;
  1292. }
  1293. wxDocument *wxDocManager::GetCurrentDocument() const
  1294. {
  1295. wxView * const view = GetActiveView();
  1296. return view ? view->GetDocument() : NULL;
  1297. }
  1298. wxCommandProcessor *wxDocManager::GetCurrentCommandProcessor() const
  1299. {
  1300. wxDocument * const doc = GetCurrentDocument();
  1301. return doc ? doc->GetCommandProcessor() : NULL;
  1302. }
  1303. // Make a default name for a new document
  1304. #if WXWIN_COMPATIBILITY_2_8
  1305. bool wxDocManager::MakeDefaultName(wxString& WXUNUSED(name))
  1306. {
  1307. // we consider that this function can only be overridden by the user code,
  1308. // not called by it as it only makes sense to call it internally, so we
  1309. // don't bother to return anything from here
  1310. return false;
  1311. }
  1312. #endif // WXWIN_COMPATIBILITY_2_8
  1313. wxString wxDocManager::MakeNewDocumentName()
  1314. {
  1315. wxString name;
  1316. #if WXWIN_COMPATIBILITY_2_8
  1317. if ( !MakeDefaultName(name) )
  1318. #endif // WXWIN_COMPATIBILITY_2_8
  1319. {
  1320. name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter);
  1321. m_defaultDocumentNameCounter++;
  1322. }
  1323. return name;
  1324. }
  1325. // Make a frame title (override this to do something different)
  1326. // If docName is empty, a document is not currently active.
  1327. wxString wxDocManager::MakeFrameTitle(wxDocument* doc)
  1328. {
  1329. wxString appName = wxTheApp->GetAppDisplayName();
  1330. wxString title;
  1331. if (!doc)
  1332. title = appName;
  1333. else
  1334. {
  1335. wxString docName = doc->GetUserReadableName();
  1336. title = docName + wxString(_(" - ")) + appName;
  1337. }
  1338. return title;
  1339. }
  1340. // Not yet implemented
  1341. wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
  1342. {
  1343. return NULL;
  1344. }
  1345. // File history management
  1346. void wxDocManager::AddFileToHistory(const wxString& file)
  1347. {
  1348. if (m_fileHistory)
  1349. m_fileHistory->AddFileToHistory(file);
  1350. }
  1351. void wxDocManager::RemoveFileFromHistory(size_t i)
  1352. {
  1353. if (m_fileHistory)
  1354. m_fileHistory->RemoveFileFromHistory(i);
  1355. }
  1356. wxString wxDocManager::GetHistoryFile(size_t i) const
  1357. {
  1358. wxString histFile;
  1359. if (m_fileHistory)
  1360. histFile = m_fileHistory->GetHistoryFile(i);
  1361. return histFile;
  1362. }
  1363. void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
  1364. {
  1365. if (m_fileHistory)
  1366. m_fileHistory->UseMenu(menu);
  1367. }
  1368. void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu)
  1369. {
  1370. if (m_fileHistory)
  1371. m_fileHistory->RemoveMenu(menu);
  1372. }
  1373. #if wxUSE_CONFIG
  1374. void wxDocManager::FileHistoryLoad(const wxConfigBase& config)
  1375. {
  1376. if (m_fileHistory)
  1377. m_fileHistory->Load(config);
  1378. }
  1379. void wxDocManager::FileHistorySave(wxConfigBase& config)
  1380. {
  1381. if (m_fileHistory)
  1382. m_fileHistory->Save(config);
  1383. }
  1384. #endif
  1385. void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu)
  1386. {
  1387. if (m_fileHistory)
  1388. m_fileHistory->AddFilesToMenu(menu);
  1389. }
  1390. void wxDocManager::FileHistoryAddFilesToMenu()
  1391. {
  1392. if (m_fileHistory)
  1393. m_fileHistory->AddFilesToMenu();
  1394. }
  1395. size_t wxDocManager::GetHistoryFilesCount() const
  1396. {
  1397. return m_fileHistory ? m_fileHistory->GetCount() : 0;
  1398. }
  1399. // Find out the document template via matching in the document file format
  1400. // against that of the template
  1401. wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path)
  1402. {
  1403. wxDocTemplate *theTemplate = NULL;
  1404. // Find the template which this extension corresponds to
  1405. for (size_t i = 0; i < m_templates.GetCount(); i++)
  1406. {
  1407. wxDocTemplate *temp = (wxDocTemplate *)m_templates.Item(i)->GetData();
  1408. if ( temp->FileMatchesTemplate(path) )
  1409. {
  1410. theTemplate = temp;
  1411. break;
  1412. }
  1413. }
  1414. return theTemplate;
  1415. }
  1416. // Prompts user to open a file, using file specs in templates.
  1417. // Must extend the file selector dialog or implement own; OR
  1418. // match the extension to the template extension.
  1419. wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates,
  1420. int noTemplates,
  1421. wxString& path,
  1422. long WXUNUSED(flags),
  1423. bool WXUNUSED(save))
  1424. {
  1425. #ifdef wxHAS_MULTIPLE_FILEDLG_FILTERS
  1426. wxString descrBuf;
  1427. for (int i = 0; i < noTemplates; i++)
  1428. {
  1429. if (templates[i]->IsVisible())
  1430. {
  1431. // add a '|' to separate this filter from the previous one
  1432. if ( !descrBuf.empty() )
  1433. descrBuf << wxT('|');
  1434. descrBuf << templates[i]->GetDescription()
  1435. << wxT(" (") << templates[i]->GetFileFilter() << wxT(") |")
  1436. << templates[i]->GetFileFilter();
  1437. }
  1438. }
  1439. #else
  1440. wxString descrBuf = wxT("*.*");
  1441. wxUnusedVar(noTemplates);
  1442. #endif
  1443. int FilterIndex = -1;
  1444. wxString pathTmp = wxFileSelectorEx(_("Open File"),
  1445. GetLastDirectory(),
  1446. wxEmptyString,
  1447. &FilterIndex,
  1448. descrBuf,
  1449. wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  1450. wxDocTemplate *theTemplate = NULL;
  1451. if (!pathTmp.empty())
  1452. {
  1453. if (!wxFileExists(pathTmp))
  1454. {
  1455. wxString msgTitle;
  1456. if (!wxTheApp->GetAppDisplayName().empty())
  1457. msgTitle = wxTheApp->GetAppDisplayName();
  1458. else
  1459. msgTitle = wxString(_("File error"));
  1460. wxMessageBox(_("Sorry, could not open this file."),
  1461. msgTitle,
  1462. wxOK | wxICON_EXCLAMATION | wxCENTRE);
  1463. path = wxEmptyString;
  1464. return NULL;
  1465. }
  1466. SetLastDirectory(wxPathOnly(pathTmp));
  1467. path = pathTmp;
  1468. // first choose the template using the extension, if this fails (i.e.
  1469. // wxFileSelectorEx() didn't fill it), then use the path
  1470. if ( FilterIndex != -1 )
  1471. theTemplate = templates[FilterIndex];
  1472. if ( !theTemplate )
  1473. theTemplate = FindTemplateForPath(path);
  1474. if ( !theTemplate )
  1475. {
  1476. // Since we do not add files with non-default extensions to the
  1477. // file history this can only happen if the application changes the
  1478. // allowed templates in runtime.
  1479. wxMessageBox(_("Sorry, the format for this file is unknown."),
  1480. _("Open File"),
  1481. wxOK | wxICON_EXCLAMATION | wxCENTRE);
  1482. }
  1483. }
  1484. else
  1485. {
  1486. path.clear();
  1487. }