1///////////////////////////////////////////////////////////////////////////// 2// Name: src/common/docview.cpp 3// Purpose: Document/view classes 4// Author: Julian Smart 5// Modified by: 6// Created: 01/02/97 7// RCS-ID: $Id: docview.cpp 66911 2011-02-16 21:31:33Z JS $ 8// Copyright: (c) Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#if wxUSE_DOC_VIEW_ARCHITECTURE 28 29#include "wx/docview.h" 30 31#ifndef WX_PRECOMP 32 #include "wx/list.h" 33 #include "wx/string.h" 34 #include "wx/utils.h" 35 #include "wx/app.h" 36 #include "wx/dc.h" 37 #include "wx/dialog.h" 38 #include "wx/menu.h" 39 #include "wx/filedlg.h" 40 #include "wx/intl.h" 41 #include "wx/log.h" 42 #include "wx/msgdlg.h" 43 #include "wx/mdi.h" 44 #include "wx/choicdlg.h" 45#endif 46 47#include "wx/ffile.h" 48 49#ifdef __WXMAC__ 50 #include "wx/filename.h" 51#endif 52 53#if wxUSE_PRINTING_ARCHITECTURE 54 #include "wx/prntbase.h" 55 #include "wx/printdlg.h" 56#endif 57 58#include "wx/confbase.h" 59#include "wx/file.h" 60#include "wx/cmdproc.h" 61#include "wx/tokenzr.h" 62 63#include <stdio.h> 64#include <string.h> 65 66#if wxUSE_STD_IOSTREAM 67 #include "wx/ioswrap.h" 68 #if wxUSE_IOSTREAMH 69 #include <fstream.h> 70 #else 71 #include <fstream> 72 #endif 73#else 74 #include "wx/wfstream.h" 75#endif 76 77// ---------------------------------------------------------------------------- 78// wxWidgets macros 79// ---------------------------------------------------------------------------- 80 81IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler) 82IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler) 83IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject) 84IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler) 85IMPLEMENT_CLASS(wxDocChildFrame, wxFrame) 86IMPLEMENT_CLASS(wxDocParentFrame, wxFrame) 87 88#if wxUSE_PRINTING_ARCHITECTURE 89 IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout) 90#endif 91 92IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject) 93 94// ---------------------------------------------------------------------------- 95// function prototypes 96// ---------------------------------------------------------------------------- 97 98static wxWindow* wxFindSuitableParent(void); 99 100// ---------------------------------------------------------------------------- 101// local constants 102// ---------------------------------------------------------------------------- 103 104static const wxChar *s_MRUEntryFormat = wxT("&%d %s"); 105 106// ============================================================================ 107// implementation 108// ============================================================================ 109 110// ---------------------------------------------------------------------------- 111// local functions 112// ---------------------------------------------------------------------------- 113 114static wxString FindExtension(const wxChar *path) 115{ 116 wxString ext; 117 wxSplitPath(path, NULL, NULL, &ext); 118 119 // VZ: extensions are considered not case sensitive - is this really a good 120 // idea? 121 return ext.MakeLower(); 122} 123 124// ---------------------------------------------------------------------------- 125// Definition of wxDocument 126// ---------------------------------------------------------------------------- 127 128wxDocument::wxDocument(wxDocument *parent) 129{ 130 m_documentModified = false; 131 m_documentParent = parent; 132 m_documentTemplate = (wxDocTemplate *) NULL; 133 m_commandProcessor = (wxCommandProcessor*) NULL; 134 m_savedYet = false; 135} 136 137bool wxDocument::DeleteContents() 138{ 139 return true; 140} 141 142wxDocument::~wxDocument() 143{ 144 DeleteContents(); 145 146 if (m_commandProcessor) 147 delete m_commandProcessor; 148 149 if (GetDocumentManager()) 150 GetDocumentManager()->RemoveDocument(this); 151 152 // Not safe to do here, since it'll invoke virtual view functions 153 // expecting to see valid derived objects: and by the time we get here, 154 // we've called destructors higher up. 155 //DeleteAllViews(); 156} 157 158bool wxDocument::Close() 159{ 160 if (OnSaveModified()) 161 return OnCloseDocument(); 162 else 163 return false; 164} 165 166bool wxDocument::OnCloseDocument() 167{ 168 // Tell all views that we're about to close 169 NotifyClosing(); 170 DeleteContents(); 171 Modify(false); 172 return true; 173} 174 175// Note that this implicitly deletes the document when the last view is 176// deleted. 177bool wxDocument::DeleteAllViews() 178{ 179 wxDocManager* manager = GetDocumentManager(); 180 181 // first check if all views agree to be closed 182 const wxList::iterator end = m_documentViews.end(); 183 for ( wxList::iterator i = m_documentViews.begin(); i != end; ++i ) 184 { 185 wxView *view = (wxView *)*i; 186 if ( !view->Close() ) 187 return false; 188 } 189 190 // all views agreed to close, now do close them 191 if ( m_documentViews.empty() ) 192 { 193 // normally the document would be implicitly deleted when the last view 194 // is, but if don't have any views, do it here instead 195 if ( manager && manager->GetDocuments().Member(this) ) 196 delete this; 197 } 198 else // have views 199 { 200 // as we delete elements we iterate over, don't use the usual "from 201 // begin to end" loop 202 for ( ;; ) 203 { 204 wxView *view = (wxView *)*m_documentViews.begin(); 205 206 bool isLastOne = m_documentViews.size() == 1; 207 208 // this always deletes the node implicitly and if this is the last 209 // view also deletes this object itself (also implicitly, great), 210 // so we can't test for m_documentViews.empty() after calling this! 211 delete view; 212 213 if ( isLastOne ) 214 break; 215 } 216 } 217 218 return true; 219} 220 221wxView *wxDocument::GetFirstView() const 222{ 223 if (m_documentViews.GetCount() == 0) 224 return (wxView *) NULL; 225 return (wxView *)m_documentViews.GetFirst()->GetData(); 226} 227 228wxDocManager *wxDocument::GetDocumentManager() const 229{ 230 return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL); 231} 232 233bool wxDocument::OnNewDocument() 234{ 235 if (!OnSaveModified()) 236 return false; 237 238 if (OnCloseDocument()==false) return false; 239 DeleteContents(); 240 Modify(false); 241 SetDocumentSaved(false); 242 243 wxString name; 244 GetDocumentManager()->MakeDefaultName(name); 245 SetTitle(name); 246 SetFilename(name, true); 247 248 return true; 249} 250 251bool wxDocument::Save() 252{ 253 if (!IsModified() && m_savedYet) 254 return true; 255 256 if ( m_documentFile.empty() || !m_savedYet ) 257 return SaveAs(); 258 259 return OnSaveDocument(m_documentFile); 260} 261 262bool wxDocument::SaveAs() 263{ 264 wxDocTemplate *docTemplate = GetDocumentTemplate(); 265 if (!docTemplate) 266 return false; 267 268#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) 269 wxString filter = docTemplate->GetDescription() + wxT(" (") + docTemplate->GetFileFilter() + wxT(")|") + docTemplate->GetFileFilter(); 270 271 // Now see if there are some other template with identical view and document 272 // classes, whose filters may also be used. 273 274 if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo()) 275 { 276 wxList::compatibility_iterator node = docTemplate->GetDocumentManager()->GetTemplates().GetFirst(); 277 while (node) 278 { 279 wxDocTemplate *t = (wxDocTemplate*) node->GetData(); 280 281 if (t->IsVisible() && t != docTemplate && 282 t->GetViewClassInfo() == docTemplate->GetViewClassInfo() && 283 t->GetDocClassInfo() == docTemplate->GetDocClassInfo()) 284 { 285 // add a '|' to separate this filter from the previous one 286 if ( !filter.empty() ) 287 filter << wxT('|'); 288 289 filter << t->GetDescription() << wxT(" (") << t->GetFileFilter() << wxT(") |") 290 << t->GetFileFilter(); 291 } 292 293 node = node->GetNext(); 294 } 295 } 296#else 297 wxString filter = docTemplate->GetFileFilter() ; 298#endif 299 wxString defaultDir = docTemplate->GetDirectory(); 300 if (defaultDir.IsEmpty()) 301 defaultDir = wxPathOnly(GetFilename()); 302 303 wxString tmp = wxFileSelector(_("Save as"), 304 defaultDir, 305 wxFileNameFromPath(GetFilename()), 306 docTemplate->GetDefaultExtension(), 307 filter, 308 wxFD_SAVE | wxFD_OVERWRITE_PROMPT, 309 GetDocumentWindow()); 310 311 if (tmp.empty()) 312 return false; 313 314 wxString fileName(tmp); 315 wxString path, name, ext; 316 wxSplitPath(fileName, & path, & name, & ext); 317 318 if (ext.empty()) 319 { 320 fileName += wxT("."); 321 fileName += docTemplate->GetDefaultExtension(); 322 } 323 324 SetFilename(fileName); 325 SetTitle(wxFileNameFromPath(fileName)); 326 327 // Notify the views that the filename has changed 328 wxList::compatibility_iterator node = m_documentViews.GetFirst(); 329 while (node) 330 { 331 wxView *view = (wxView *)node->GetData(); 332 view->OnChangeFilename(); 333 node = node->GetNext(); 334 } 335 336 // Files that were not saved correctly are not added to the FileHistory. 337 if (!OnSaveDocument(m_documentFile)) 338 return false; 339 340 // A file that doesn't use the default extension of its document template cannot be opened 341 // via the FileHistory, so we do not add it. 342 if (docTemplate->FileMatchesTemplate(fileName)) 343 { 344 GetDocumentManager()->AddFileToHistory(fileName); 345 } 346 else 347 { 348 // The user will probably not be able to open the file again, so 349 // we could warn about the wrong file-extension here. 350 } 351 return true; 352} 353 354bool wxDocument::OnSaveDocument(const wxString& file) 355{ 356 if ( !file ) 357 return false; 358 359 if ( !DoSaveDocument(file) ) 360 return false; 361 362 Modify(false); 363 SetFilename(file); 364 SetDocumentSaved(true); 365#ifdef __WXMAC__ 366 wxFileName fn(file) ; 367 fn.MacSetDefaultTypeAndCreator() ; 368#endif 369 return true; 370} 371 372bool wxDocument::OnOpenDocument(const wxString& file) 373{ 374 if (!OnSaveModified()) 375 return false; 376 377 if ( !DoOpenDocument(file) ) 378 return false; 379 380 SetFilename(file, true); 381 Modify(false); 382 m_savedYet = true; 383 384 UpdateAllViews(); 385 386 return true; 387} 388 389#if wxUSE_STD_IOSTREAM 390wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream) 391#else 392wxInputStream& wxDocument::LoadObject(wxInputStream& stream) 393#endif 394{ 395 return stream; 396} 397 398#if wxUSE_STD_IOSTREAM 399wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream) 400#else 401wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream) 402#endif 403{ 404 return stream; 405} 406 407bool wxDocument::Revert() 408{ 409 return false; 410} 411 412 413// Get title, or filename if no title, else unnamed 414bool wxDocument::GetPrintableName(wxString& buf) const 415{ 416 if (!m_documentTitle.empty()) 417 { 418 buf = m_documentTitle; 419 return true; 420 } 421 else if (!m_documentFile.empty()) 422 { 423 buf = wxFileNameFromPath(m_documentFile); 424 return true; 425 } 426 else 427 { 428 buf = _("unnamed"); 429 return true; 430 } 431} 432 433wxWindow *wxDocument::GetDocumentWindow() const 434{ 435 wxView *view = GetFirstView(); 436 if (view) 437 return view->GetFrame(); 438 else 439 return wxTheApp->GetTopWindow(); 440} 441 442wxCommandProcessor *wxDocument::OnCreateCommandProcessor() 443{ 444 return new wxCommandProcessor; 445} 446 447// true if safe to close 448bool wxDocument::OnSaveModified() 449{ 450 if (IsModified()) 451 { 452 wxString title; 453 GetPrintableName(title); 454 455 wxString msgTitle; 456 if (!wxTheApp->GetAppName().empty()) 457 msgTitle = wxTheApp->GetAppName(); 458 else 459 msgTitle = wxString(_("Warning")); 460 461 wxString prompt; 462 prompt.Printf(_("Do you want to save changes to document %s?"), 463 (const wxChar *)title); 464 int res = wxMessageBox(prompt, msgTitle, 465 wxYES_NO|wxCANCEL|wxICON_QUESTION, 466 GetDocumentWindow()); 467 if (res == wxNO) 468 { 469 Modify(false); 470 return true; 471 } 472 else if (res == wxYES) 473 return Save(); 474 else if (res == wxCANCEL) 475 return false; 476 } 477 return true; 478} 479 480bool wxDocument::Draw(wxDC& WXUNUSED(context)) 481{ 482 return true; 483} 484 485bool wxDocument::AddView(wxView *view) 486{ 487 if (!m_documentViews.Member(view)) 488 { 489 m_documentViews.Append(view); 490 OnChangedViewList(); 491 } 492 return true; 493} 494 495bool wxDocument::RemoveView(wxView *view) 496{ 497 (void)m_documentViews.DeleteObject(view); 498 OnChangedViewList(); 499 return true; 500} 501 502bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags) 503{ 504 if (GetDocumentTemplate()->CreateView(this, flags)) 505 return true; 506 else 507 return false; 508} 509 510// Called after a view is added or removed. 511// The default implementation deletes the document if 512// there are no more views. 513void wxDocument::OnChangedViewList() 514{ 515 if (m_documentViews.GetCount() == 0) 516 { 517 if (OnSaveModified()) 518 { 519 delete this; 520 } 521 } 522} 523 524void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint) 525{ 526 wxList::compatibility_iterator node = m_documentViews.GetFirst(); 527 while (node) 528 { 529 wxView *view = (wxView *)node->GetData(); 530 if (view != sender) 531 view->OnUpdate(sender, hint); 532 node = node->GetNext(); 533 } 534} 535 536void wxDocument::NotifyClosing() 537{ 538 wxList::compatibility_iterator node = m_documentViews.GetFirst(); 539 while (node) 540 { 541 wxView *view = (wxView *)node->GetData(); 542 view->OnClosingDocument(); 543 node = node->GetNext(); 544 } 545} 546 547void wxDocument::SetFilename(const wxString& filename, bool notifyViews) 548{ 549 m_documentFile = filename; 550 if ( notifyViews ) 551 { 552 // Notify the views that the filename has changed 553 wxList::compatibility_iterator node = m_documentViews.GetFirst(); 554 while (node) 555 { 556 wxView *view = (wxView *)node->GetData(); 557 view->OnChangeFilename(); 558 node = node->GetNext(); 559 } 560 } 561} 562 563bool wxDocument::DoSaveDocument(const wxString& file) 564{ 565 wxString msgTitle; 566 if (!wxTheApp->GetAppName().empty()) 567 msgTitle = wxTheApp->GetAppName(); 568 else 569 msgTitle = wxString(_("File error")); 570 571#if wxUSE_STD_IOSTREAM 572 wxSTD ofstream store(file.mb_str(), wxSTD ios::binary); 573 if (store.fail() || store.bad()) 574#else 575 wxFileOutputStream store(file); 576 if (store.GetLastError() != wxSTREAM_NO_ERROR) 577#endif 578 { 579 (void)wxMessageBox(_("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION, 580 GetDocumentWindow()); 581 // Saving error 582 return false; 583 } 584 if (!SaveObject(store)) 585 { 586 (void)wxMessageBox(_("Sorry, could not save this file."), msgTitle, wxOK | wxICON_EXCLAMATION, 587 GetDocumentWindow()); 588 // Saving error 589 return false; 590 } 591 592 return true; 593} 594 595bool wxDocument::DoOpenDocument(const wxString& file) 596{ 597#if wxUSE_STD_IOSTREAM 598 wxSTD ifstream store(file.mb_str(), wxSTD ios::binary); 599 if (!store.fail() && !store.bad()) 600#else 601 wxFileInputStream store(file); 602 if (store.GetLastError() == wxSTREAM_NO_ERROR) 603#endif 604 { 605#if wxUSE_STD_IOSTREAM 606 LoadObject(store); 607 if ( !!store || store.eof() ) 608#else 609 int res = LoadObject(store).GetLastError(); 610 if ( res == wxSTREAM_NO_ERROR || res == wxSTREAM_EOF ) 611#endif 612 return true; 613 } 614 615 wxLogError(_("Sorry, could not open this file.")); 616 return false; 617} 618 619 620// ---------------------------------------------------------------------------- 621// Document view 622// ---------------------------------------------------------------------------- 623 624wxView::wxView() 625{ 626 m_viewDocument = (wxDocument*) NULL; 627 628 m_viewFrame = (wxFrame *) NULL; 629} 630 631wxView::~wxView() 632{ 633 if (m_viewDocument && GetDocumentManager()) 634 GetDocumentManager()->ActivateView(this, false); 635 if (m_viewDocument) 636 m_viewDocument->RemoveView(this); 637} 638 639// Extend event processing to search the document's event table 640bool wxView::ProcessEvent(wxEvent& event) 641{ 642 if ( !GetDocument() || !GetDocument()->ProcessEvent(event) ) 643 return wxEvtHandler::ProcessEvent(event); 644 645 return true; 646} 647 648void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView)) 649{ 650} 651 652void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info)) 653{ 654 OnDraw(dc); 655} 656 657void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)) 658{ 659} 660 661void wxView::OnChangeFilename() 662{ 663 // GetFrame can return wxWindow rather than wxTopLevelWindow due to 664 // generic MDI implementation so use SetLabel rather than SetTitle. 665 // It should cause SetTitle() for top level windows. 666 wxWindow *win = GetFrame(); 667 if (!win) return; 668 669 wxDocument *doc = GetDocument(); 670 if (!doc) return; 671 672 wxString name; 673 doc->GetPrintableName(name); 674 win->SetLabel(name); 675} 676 677void wxView::SetDocument(wxDocument *doc) 678{ 679 m_viewDocument = doc; 680 if (doc) 681 doc->AddView(this); 682} 683 684bool wxView::Close(bool deleteWindow) 685{ 686 if (OnClose(deleteWindow)) 687 return true; 688 else 689 return false; 690} 691 692void wxView::Activate(bool activate) 693{ 694 if (GetDocument() && GetDocumentManager()) 695 { 696 OnActivateView(activate, this, GetDocumentManager()->GetCurrentView()); 697 GetDocumentManager()->ActivateView(this, activate); 698 } 699} 700 701bool wxView::OnClose(bool WXUNUSED(deleteWindow)) 702{ 703 return GetDocument() ? GetDocument()->Close() : true; 704} 705 706#if wxUSE_PRINTING_ARCHITECTURE 707wxPrintout *wxView::OnCreatePrintout() 708{ 709 return new wxDocPrintout(this); 710} 711#endif // wxUSE_PRINTING_ARCHITECTURE 712 713// ---------------------------------------------------------------------------- 714// wxDocTemplate 715// ---------------------------------------------------------------------------- 716 717wxDocTemplate::wxDocTemplate(wxDocManager *manager, 718 const wxString& descr, 719 const wxString& filter, 720 const wxString& dir, 721 const wxString& ext, 722 const wxString& docTypeName, 723 const wxString& viewTypeName, 724 wxClassInfo *docClassInfo, 725 wxClassInfo *viewClassInfo, 726 long flags) 727{ 728 m_documentManager = manager; 729 m_description = descr; 730 m_directory = dir; 731 m_defaultExt = ext; 732 m_fileFilter = filter; 733 m_flags = flags; 734 m_docTypeName = docTypeName; 735 m_viewTypeName = viewTypeName; 736 m_documentManager->AssociateTemplate(this); 737 738 m_docClassInfo = docClassInfo; 739 m_viewClassInfo = viewClassInfo; 740} 741 742wxDocTemplate::~wxDocTemplate() 743{ 744 m_documentManager->DisassociateTemplate(this); 745} 746 747// Tries to dynamically construct an object of the right class. 748wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags) 749{ 750 wxDocument *doc = DoCreateDocument(); 751 if ( doc == NULL ) 752 return (wxDocument *) NULL; 753 754 if (InitDocument(doc, path, flags)) 755 { 756 return doc; 757 } 758 else 759 { 760 return (wxDocument *) NULL; 761 } 762} 763 764bool wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags) 765{ 766 doc->SetFilename(path); 767 doc->SetDocumentTemplate(this); 768 GetDocumentManager()->AddDocument(doc); 769 doc->SetCommandProcessor(doc->OnCreateCommandProcessor()); 770 771 if (doc->OnCreate(path, flags)) 772 return true; 773 else 774 { 775 if (GetDocumentManager()->GetDocuments().Member(doc)) 776 doc->DeleteAllViews(); 777 return false; 778 } 779} 780 781wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags) 782{ 783 wxView *view = DoCreateView(); 784 if ( view == NULL ) 785 return (wxView *) NULL; 786 787 view->SetDocument(doc); 788 if (view->OnCreate(doc, flags)) 789 { 790 return view; 791 } 792 else 793 { 794 delete view; 795 return (wxView *) NULL; 796 } 797} 798 799// The default (very primitive) format detection: check is the extension is 800// that of the template 801bool wxDocTemplate::FileMatchesTemplate(const wxString& path) 802{ 803 wxStringTokenizer parser (GetFileFilter(), wxT(";")); 804 wxString anything = wxT ("*"); 805 while (parser.HasMoreTokens()) 806 { 807 wxString filter = parser.GetNextToken(); 808 wxString filterExt = FindExtension (filter); 809 if ( filter.IsSameAs (anything) || 810 filterExt.IsSameAs (anything) || 811 filterExt.IsSameAs (FindExtension (path)) ) 812 return true; 813 } 814 return GetDefaultExtension().IsSameAs(FindExtension(path)); 815} 816 817wxDocument *wxDocTemplate::DoCreateDocument() 818{ 819 if (!m_docClassInfo) 820 return (wxDocument *) NULL; 821 822 return (wxDocument *)m_docClassInfo->CreateObject(); 823} 824 825wxView *wxDocTemplate::DoCreateView() 826{ 827 if (!m_viewClassInfo) 828 return (wxView *) NULL; 829 830 return (wxView *)m_viewClassInfo->CreateObject(); 831} 832 833// ---------------------------------------------------------------------------- 834// wxDocManager 835// ---------------------------------------------------------------------------- 836 837BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler) 838 EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen) 839 EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose) 840 EVT_MENU(wxID_CLOSE_ALL, wxDocManager::OnFileCloseAll) 841 EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert) 842 EVT_MENU(wxID_NEW, wxDocManager::OnFileNew) 843 EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave) 844 EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs) 845 EVT_MENU(wxID_UNDO, wxDocManager::OnUndo) 846 EVT_MENU(wxID_REDO, wxDocManager::OnRedo) 847 848 EVT_UPDATE_UI(wxID_OPEN, wxDocManager::OnUpdateFileOpen) 849 EVT_UPDATE_UI(wxID_CLOSE, wxDocManager::OnUpdateFileClose) 850 EVT_UPDATE_UI(wxID_CLOSE_ALL, wxDocManager::OnUpdateFileClose) 851 EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert) 852 EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew) 853 EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave) 854 EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs) 855 EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo) 856 EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo) 857 858#if wxUSE_PRINTING_ARCHITECTURE 859 EVT_MENU(wxID_PRINT, wxDocManager::OnPrint) 860 EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview) 861 862 EVT_UPDATE_UI(wxID_PRINT, wxDocManager::OnUpdatePrint) 863 EVT_UPDATE_UI(wxID_PREVIEW, wxDocManager::OnUpdatePreview) 864#endif 865END_EVENT_TABLE() 866 867wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL; 868 869wxDocManager::wxDocManager(long flags, bool initialize) 870{ 871 m_defaultDocumentNameCounter = 1; 872 m_flags = flags; 873 m_currentView = (wxView *) NULL; 874 m_maxDocsOpen = 10000; 875 m_fileHistory = (wxFileHistory *) NULL; 876 if (initialize) 877 Initialize(); 878 sm_docManager = this; 879} 880 881wxDocManager::~wxDocManager() 882{ 883 Clear(); 884 if (m_fileHistory) 885 delete m_fileHistory; 886 sm_docManager = (wxDocManager*) NULL; 887} 888 889// closes the specified document 890bool wxDocManager::CloseDocument(wxDocument* doc, bool force) 891{ 892 if (doc->Close() || force) 893 { 894 // Implicitly deletes the document when 895 // the last view is deleted 896 doc->DeleteAllViews(); 897 898 // Check we're really deleted 899 if (m_docs.Member(doc)) 900 delete doc; 901 902 return true; 903 } 904 return false; 905} 906 907bool wxDocManager::CloseDocuments(bool force) 908{ 909 wxList::compatibility_iterator node = m_docs.GetFirst(); 910 while (node) 911 { 912 wxDocument *doc = (wxDocument *)node->GetData(); 913 wxList::compatibility_iterator next = node->GetNext(); 914 915 if (!CloseDocument(doc, force)) 916 return false; 917 918 // This assumes that documents are not connected in 919 // any way, i.e. deleting one document does NOT 920 // delete another. 921 node = next; 922 } 923 return true; 924} 925 926bool wxDocManager::Clear(bool force) 927{ 928 if (!CloseDocuments(force)) 929 return false; 930 931 m_currentView = NULL; 932 933 wxList::compatibility_iterator node = m_templates.GetFirst(); 934 while (node) 935 { 936 wxDocTemplate *templ = (wxDocTemplate*) node->GetData(); 937 wxList::compatibility_iterator next = node->GetNext(); 938 delete templ; 939 node = next; 940 } 941 return true; 942} 943 944bool wxDocManager::Initialize() 945{ 946 m_fileHistory = OnCreateFileHistory(); 947 return true; 948} 949 950wxFileHistory *wxDocManager::OnCreateFileHistory() 951{ 952 return new wxFileHistory; 953} 954 955void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event)) 956{ 957 wxDocument *doc = GetCurrentDocument(); 958 if (!doc) 959 return; 960 if (doc->Close()) 961 { 962 doc->DeleteAllViews(); 963 if (m_docs.Member(doc)) 964 delete doc; 965 } 966} 967 968void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event)) 969{ 970 CloseDocuments(false); 971} 972 973void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event)) 974{ 975 CreateDocument( wxEmptyString, wxDOC_NEW ); 976} 977 978void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event)) 979{ 980 if ( !CreateDocument( wxEmptyString, 0) ) 981 { 982 OnOpenFileFailure(); 983 } 984} 985 986void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event)) 987{ 988 wxDocument *doc = GetCurrentDocument(); 989 if (!doc) 990 return; 991 doc->Revert(); 992} 993 994void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event)) 995{ 996 wxDocument *doc = GetCurrentDocument(); 997 if (!doc) 998 return; 999 doc->Save(); 1000} 1001 1002void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) 1003{ 1004 wxDocument *doc = GetCurrentDocument(); 1005 if (!doc) 1006 return; 1007 doc->SaveAs(); 1008} 1009 1010void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event)) 1011{ 1012#if wxUSE_PRINTING_ARCHITECTURE 1013 wxView *view = GetCurrentView(); 1014 if (!view) 1015 return; 1016 1017 wxPrintout *printout = view->OnCreatePrintout(); 1018 if (printout) 1019 { 1020 wxPrinter printer; 1021 printer.Print(view->GetFrame(), printout, true); 1022 1023 delete printout; 1024 } 1025#endif // wxUSE_PRINTING_ARCHITECTURE 1026} 1027 1028void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event)) 1029{ 1030#if wxUSE_PRINTING_ARCHITECTURE 1031 wxBusyCursor busy; 1032 wxView *view = GetCurrentView(); 1033 if (!view) 1034 return; 1035 1036 wxPrintout *printout = view->OnCreatePrintout(); 1037 if (printout) 1038 { 1039 // Pass two printout objects: for preview, and possible printing. 1040 wxPrintPreviewBase *preview = new wxPrintPreview(printout, view->OnCreatePrintout()); 1041 if ( !preview->Ok() ) 1042 { 1043 delete preview; 1044 wxMessageBox( _("Sorry, print preview needs a printer to be installed.") ); 1045 return; 1046 } 1047 1048 wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"), 1049 wxPoint(100, 100), wxSize(600, 650)); 1050 frame->Centre(wxBOTH); 1051 frame->Initialize(); 1052 frame->Show(true); 1053 } 1054#endif // wxUSE_PRINTING_ARCHITECTURE 1055} 1056 1057void wxDocManager::OnUndo(wxCommandEvent& event) 1058{ 1059 wxDocument *doc = GetCurrentDocument(); 1060 if (!doc) 1061 return; 1062 if (doc->GetCommandProcessor()) 1063 doc->GetCommandProcessor()->Undo(); 1064 else 1065 event.Skip(); 1066} 1067 1068void wxDocManager::OnRedo(wxCommandEvent& event) 1069{ 1070 wxDocument *doc = GetCurrentDocument(); 1071 if (!doc) 1072 return; 1073 if (doc->GetCommandProcessor()) 1074 doc->GetCommandProcessor()->Redo(); 1075 else 1076 event.Skip(); 1077} 1078 1079// Handlers for UI update commands 1080 1081void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event) 1082{ 1083 event.Enable( true ); 1084} 1085 1086void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event) 1087{ 1088 wxDocument *doc = GetCurrentDocument(); 1089 event.Enable( (doc != (wxDocument*) NULL) ); 1090} 1091 1092void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event) 1093{ 1094 wxDocument *doc = GetCurrentDocument(); 1095 event.Enable( (doc != (wxDocument*) NULL) ); 1096} 1097 1098void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event) 1099{ 1100 event.Enable( true ); 1101} 1102 1103void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event) 1104{ 1105 wxDocument *doc = GetCurrentDocument(); 1106 event.Enable( doc && doc->IsModified() ); 1107} 1108 1109void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event) 1110{ 1111 wxDocument *doc = GetCurrentDocument(); 1112 event.Enable( (doc != (wxDocument*) NULL) ); 1113} 1114 1115void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event) 1116{ 1117 wxDocument *doc = GetCurrentDocument(); 1118 if (!doc) 1119 event.Enable(false); 1120 else if (!doc->GetCommandProcessor()) 1121 event.Skip(); 1122 else 1123 { 1124 event.Enable( doc->GetCommandProcessor()->CanUndo() ); 1125 doc->GetCommandProcessor()->SetMenuStrings(); 1126 } 1127} 1128 1129void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event) 1130{ 1131 wxDocument *doc = GetCurrentDocument(); 1132 if (!doc) 1133 event.Enable(false); 1134 else if (!doc->GetCommandProcessor()) 1135 event.Skip(); 1136 else 1137 { 1138 event.Enable( doc->GetCommandProcessor()->CanRedo() ); 1139 doc->GetCommandProcessor()->SetMenuStrings(); 1140 } 1141} 1142 1143void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event) 1144{ 1145 wxDocument *doc = GetCurrentDocument(); 1146 event.Enable( (doc != (wxDocument*) NULL) ); 1147} 1148 1149void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event) 1150{ 1151 wxDocument *doc = GetCurrentDocument(); 1152 event.Enable( (doc != (wxDocument*) NULL) ); 1153} 1154 1155wxView *wxDocManager::GetCurrentView() const 1156{ 1157 if (m_currentView) 1158 return m_currentView; 1159 if (m_docs.GetCount() == 1) 1160 { 1161 wxDocument* doc = (wxDocument*) m_docs.GetFirst()->GetData(); 1162 return doc->GetFirstView(); 1163 } 1164 return (wxView *) NULL; 1165} 1166 1167// Extend event processing to search the view's event table 1168bool wxDocManager::ProcessEvent(wxEvent& event) 1169{ 1170 wxView* view = GetCurrentView(); 1171 if (view) 1172 { 1173 if (view->ProcessEvent(event)) 1174 return true; 1175 } 1176 return wxEvtHandler::ProcessEvent(event); 1177} 1178 1179wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) 1180{ 1181 wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; 1182 int n = 0; 1183 1184 for (size_t i = 0; i < m_templates.GetCount(); i++) 1185 { 1186 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); 1187 if (temp->IsVisible()) 1188 { 1189 templates[n] = temp; 1190 n ++; 1191 } 1192 } 1193 if (n == 0) 1194 { 1195 delete[] templates; 1196 return (wxDocument *) NULL; 1197 } 1198 1199 wxDocument* docToClose = NULL; 1200 1201 // If we've reached the max number of docs, close the 1202 // first one. 1203 if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen ) 1204 { 1205 wxDocument *doc = (wxDocument *)GetDocuments().GetFirst()->GetData(); 1206 docToClose = doc; 1207 } 1208 1209 // New document: user chooses a template, unless there's only one. 1210 if (flags & wxDOC_NEW) 1211 { 1212 if (n == 1) 1213 { 1214 if (docToClose) 1215 { 1216 if (!CloseDocument(docToClose, false)) 1217 { 1218 delete[] templates; 1219 return NULL; 1220 } 1221 } 1222 1223 wxDocTemplate *temp = templates[0]; 1224 delete[] templates; 1225 wxDocument *newDoc = temp->CreateDocument(path, flags); 1226 1227 if (newDoc) 1228 { 1229 newDoc->SetDocumentName(temp->GetDocumentName()); 1230 newDoc->SetDocumentTemplate(temp); 1231 if (!newDoc->OnNewDocument() ) 1232 { 1233 // Document is implicitly deleted by DeleteAllViews 1234 newDoc->DeleteAllViews(); 1235 return NULL; 1236 } 1237 } 1238 return newDoc; 1239 } 1240 1241 wxDocTemplate *temp = SelectDocumentType(templates, n); 1242 delete[] templates; 1243 if (temp) 1244 { 1245 if (docToClose) 1246 { 1247 if (!CloseDocument(docToClose, false)) 1248 { 1249 return NULL; 1250 } 1251 } 1252 1253 wxDocument *newDoc = temp->CreateDocument(path, flags); 1254 1255 if (newDoc) 1256 { 1257 newDoc->SetDocumentName(temp->GetDocumentName()); 1258 newDoc->SetDocumentTemplate(temp); 1259 if (!newDoc->OnNewDocument() ) 1260 { 1261 // Document is implicitly deleted by DeleteAllViews 1262 newDoc->DeleteAllViews(); 1263 return NULL; 1264 } 1265 } 1266 return newDoc; 1267 } 1268 else 1269 return (wxDocument *) NULL; 1270 } 1271 1272 // Existing document 1273 wxDocTemplate *temp; 1274 1275 wxString path2 = path; 1276 1277 if (flags & wxDOC_SILENT) 1278 { 1279 temp = FindTemplateForPath(path2); 1280 if (!temp) 1281 { 1282 // Since we do not add files with non-default extensions to the FileHistory this 1283 // can only happen if the application changes the allowed templates in runtime. 1284 (void)wxMessageBox(_("Sorry, the format for this file is unknown."), 1285 _("Open File"), 1286 wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); 1287 } 1288 } 1289 else 1290 temp = SelectDocumentPath(templates, n, path2, flags); 1291 1292 delete[] templates; 1293 1294 if (temp) 1295 { 1296 if (docToClose) 1297 { 1298 if (!CloseDocument(docToClose, false)) 1299 { 1300 return NULL; 1301 } 1302 } 1303 1304 //see if this file is already open 1305 for (size_t i = 0; i < GetDocuments().GetCount(); ++i) 1306 { 1307 wxDocument* currentDoc = (wxDocument*)(GetDocuments().Item(i)->GetData()); 1308#ifdef __WXMSW__ 1309 //file paths are case-insensitive on Windows 1310 if (path2.CmpNoCase(currentDoc->GetFilename()) == 0) 1311#else 1312 if (path2.Cmp(currentDoc->GetFilename()) == 0) 1313#endif 1314 { 1315 //file already open. Just activate it and return 1316 if (currentDoc->GetFirstView()) 1317 { 1318 ActivateView(currentDoc->GetFirstView(), true); 1319 if (currentDoc->GetDocumentWindow()) 1320 currentDoc->GetDocumentWindow()->SetFocus(); 1321 return currentDoc; 1322 } 1323 } 1324 } 1325 1326 wxDocument *newDoc = temp->CreateDocument(path2, flags); 1327 if (newDoc) 1328 { 1329 newDoc->SetDocumentName(temp->GetDocumentName()); 1330 newDoc->SetDocumentTemplate(temp); 1331 if (!newDoc->OnOpenDocument(path2)) 1332 { 1333 newDoc->DeleteAllViews(); 1334 // delete newDoc; // Implicitly deleted by DeleteAllViews 1335 return (wxDocument *) NULL; 1336 } 1337 // A file that doesn't use the default extension of its document 1338 // template cannot be opened via the FileHistory, so we do not 1339 // add it. 1340 if (temp->FileMatchesTemplate(path2)) 1341 AddFileToHistory(path2); 1342 } 1343 return newDoc; 1344 } 1345 1346 return (wxDocument *) NULL; 1347} 1348 1349wxView *wxDocManager::CreateView(wxDocument *doc, long flags) 1350{ 1351 wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; 1352 int n =0; 1353 1354 for (size_t i = 0; i < m_templates.GetCount(); i++) 1355 { 1356 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); 1357 if (temp->IsVisible()) 1358 { 1359 if (temp->GetDocumentName() == doc->GetDocumentName()) 1360 { 1361 templates[n] = temp; 1362 n ++; 1363 } 1364 } 1365 } 1366 if (n == 0) 1367 { 1368 delete[] templates; 1369 return (wxView *) NULL; 1370 } 1371 if (n == 1) 1372 { 1373 wxDocTemplate *temp = templates[0]; 1374 delete[] templates; 1375 wxView *view = temp->CreateView(doc, flags); 1376 if (view) 1377 view->SetViewName(temp->GetViewName()); 1378 return view; 1379 } 1380 1381 wxDocTemplate *temp = SelectViewType(templates, n); 1382 delete[] templates; 1383 if (temp) 1384 { 1385 wxView *view = temp->CreateView(doc, flags); 1386 if (view) 1387 view->SetViewName(temp->GetViewName()); 1388 return view; 1389 } 1390 else 1391 return (wxView *) NULL; 1392} 1393 1394// Not yet implemented 1395void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags)) 1396{ 1397} 1398 1399// Not yet implemented 1400bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc)) 1401{ 1402 return false; 1403} 1404 1405wxDocument *wxDocManager::GetCurrentDocument() const 1406{ 1407 wxView *view = GetCurrentView(); 1408 if (view) 1409 return view->GetDocument(); 1410 else 1411 return (wxDocument *) NULL; 1412} 1413 1414// Make a default document name 1415bool wxDocManager::MakeDefaultName(wxString& name) 1416{ 1417 name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter); 1418 m_defaultDocumentNameCounter++; 1419 1420 return true; 1421} 1422 1423// Make a frame title (override this to do something different) 1424// If docName is empty, a document is not currently active. 1425wxString wxDocManager::MakeFrameTitle(wxDocument* doc) 1426{ 1427 wxString appName = wxTheApp->GetAppName(); 1428 wxString title; 1429 if (!doc) 1430 title = appName; 1431 else 1432 { 1433 wxString docName; 1434 doc->GetPrintableName(docName); 1435 title = docName + wxString(_(" - ")) + appName; 1436 } 1437 return title; 1438} 1439 1440 1441// Not yet implemented 1442wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path)) 1443{ 1444 return (wxDocTemplate *) NULL; 1445} 1446 1447// File history management 1448void wxDocManager::AddFileToHistory(const wxString& file) 1449{ 1450 if (m_fileHistory) 1451 m_fileHistory->AddFileToHistory(file); 1452} 1453 1454void wxDocManager::RemoveFileFromHistory(size_t i) 1455{ 1456 if (m_fileHistory) 1457 m_fileHistory->RemoveFileFromHistory(i); 1458} 1459 1460wxString wxDocManager::GetHistoryFile(size_t i) const 1461{ 1462 wxString histFile; 1463 1464 if (m_fileHistory) 1465 histFile = m_fileHistory->GetHistoryFile(i); 1466 1467 return histFile; 1468} 1469 1470void wxDocManager::FileHistoryUseMenu(wxMenu *menu) 1471{ 1472 if (m_fileHistory) 1473 m_fileHistory->UseMenu(menu); 1474} 1475 1476void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu) 1477{ 1478 if (m_fileHistory) 1479 m_fileHistory->RemoveMenu(menu); 1480} 1481 1482#if wxUSE_CONFIG 1483void wxDocManager::FileHistoryLoad(wxConfigBase& config) 1484{ 1485 if (m_fileHistory) 1486 m_fileHistory->Load(config); 1487} 1488 1489void wxDocManager::FileHistorySave(wxConfigBase& config) 1490{ 1491 if (m_fileHistory) 1492 m_fileHistory->Save(config); 1493} 1494#endif 1495 1496void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu) 1497{ 1498 if (m_fileHistory) 1499 m_fileHistory->AddFilesToMenu(menu); 1500} 1501 1502void wxDocManager::FileHistoryAddFilesToMenu() 1503{ 1504 if (m_fileHistory) 1505 m_fileHistory->AddFilesToMenu(); 1506} 1507 1508size_t wxDocManager::GetHistoryFilesCount() const 1509{ 1510 return m_fileHistory ? m_fileHistory->GetCount() : 0; 1511} 1512 1513 1514// Find out the document template via matching in the document file format 1515// against that of the template 1516wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path) 1517{ 1518 wxDocTemplate *theTemplate = (wxDocTemplate *) NULL; 1519 1520 // Find the template which this extension corresponds to 1521 for (size_t i = 0; i < m_templates.GetCount(); i++) 1522 { 1523 wxDocTemplate *temp = (wxDocTemplate *)m_templates.Item(i)->GetData(); 1524 if ( temp->FileMatchesTemplate(path) ) 1525 { 1526 theTemplate = temp; 1527 break; 1528 } 1529 } 1530 return theTemplate; 1531} 1532 1533// Try to get a more suitable parent frame than the top window, 1534// for selection dialogs. Otherwise you may get an unexpected 1535// window being activated when a dialog is shown. 1536static wxWindow* wxFindSuitableParent() 1537{ 1538 wxWindow* parent = wxTheApp->GetTopWindow(); 1539 1540 wxWindow* focusWindow = wxWindow::FindFocus(); 1541 if (focusWindow) 1542 { 1543 while (focusWindow && 1544 !focusWindow->IsKindOf(CLASSINFO(wxDialog)) && 1545 !focusWindow->IsKindOf(CLASSINFO(wxFrame))) 1546 1547 focusWindow = focusWindow->GetParent(); 1548 1549 if (focusWindow) 1550 parent = focusWindow; 1551 } 1552 return parent; 1553} 1554 1555// Prompts user to open a file, using file specs in templates. 1556// Must extend the file selector dialog or implement own; OR 1557// match the extension to the template extension. 1558 1559wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, 1560#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) 1561 int noTemplates, 1562#else 1563 int WXUNUSED(noTemplates), 1564#endif 1565 wxString& path, 1566 long WXUNUSED(flags), 1567 bool WXUNUSED(save)) 1568{ 1569 // We can only have multiple filters in Windows and GTK 1570#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) 1571 wxString descrBuf; 1572 1573 int i; 1574 for (i = 0; i < noTemplates; i++) 1575 { 1576 if (templates[i]->IsVisible()) 1577 { 1578 // add a '|' to separate this filter from the previous one 1579 if ( !descrBuf.empty() ) 1580 descrBuf << wxT('|'); 1581 1582 descrBuf << templates[i]->GetDescription() 1583 << wxT(" (") << templates[i]->GetFileFilter() << wxT(") |") 1584 << templates[i]->GetFileFilter(); 1585 } 1586 } 1587#else 1588 wxString descrBuf = wxT("*.*"); 1589#endif 1590 1591 int FilterIndex = -1; 1592 1593 wxWindow* parent = wxFindSuitableParent(); 1594 1595 wxString pathTmp = wxFileSelectorEx(_("Select a file"), 1596 m_lastDirectory, 1597 wxEmptyString, 1598 &FilterIndex, 1599 descrBuf, 1600 0, 1601 parent); 1602 1603 wxDocTemplate *theTemplate = (wxDocTemplate *)NULL; 1604 if (!pathTmp.empty()) 1605 { 1606 if (!wxFileExists(pathTmp)) 1607 { 1608 wxString msgTitle; 1609 if (!wxTheApp->GetAppName().empty()) 1610 msgTitle = wxTheApp->GetAppName(); 1611 else 1612 msgTitle = wxString(_("File error")); 1613 1614 (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK | wxICON_EXCLAMATION, 1615 parent); 1616 1617 path = wxEmptyString; 1618 return (wxDocTemplate *) NULL; 1619 } 1620 m_lastDirectory = wxPathOnly(pathTmp); 1621 1622 path = pathTmp; 1623 1624 // first choose the template using the extension, if this fails (i.e. 1625 // wxFileSelectorEx() didn't fill it), then use the path 1626 if ( FilterIndex != -1 ) 1627 theTemplate = templates[FilterIndex]; 1628 if ( !theTemplate ) 1629 theTemplate = FindTemplateForPath(path); 1630 if ( !theTemplate ) 1631 { 1632 // Since we do not add files with non-default extensions to the FileHistory this 1633 // can only happen if the application changes the allowed templates in runtime. 1634 (void)wxMessageBox(_("Sorry, the format for this file is unknown."), 1635 _("Open File"), 1636 wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); 1637 } 1638 } 1639 else 1640 { 1641 path = wxEmptyString; 1642 } 1643 1644 return theTemplate; 1645} 1646 1647wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates, 1648 int noTemplates, bool sort) 1649{ 1650 wxArrayString strings; 1651 wxDocTemplate **data = new wxDocTemplate *[noTemplates]; 1652 int i; 1653 int n = 0; 1654 1655 for (i = 0; i < noTemplates; i++) 1656 { 1657 if (templates[i]->IsVisible()) 1658 { 1659 int j; 1660 bool want = true; 1661 for (j = 0; j < n; j++) 1662 { 1663 //filter out NOT unique documents + view combinations 1664 if ( templates[i]->m_docTypeName == data[j]->m_docTypeName && 1665 templates[i]->m_viewTypeName == data[j]->m_viewTypeName 1666 ) 1667 want = false; 1668 } 1669 1670 if ( want ) 1671 { 1672 strings.Add(templates[i]->m_description); 1673 1674 data[n] = templates[i]; 1675 n ++; 1676 } 1677 } 1678 } // for 1679 1680 if (sort) 1681 { 1682 strings.Sort(); // ascending sort 1683 // Yes, this will be slow, but template lists 1684 // are typically short. 1685 int j; 1686 n = strings.Count(); 1687 for (i = 0; i < n; i++) 1688 { 1689 for (j = 0; j < noTemplates; j++) 1690 { 1691 if (strings[i] == templates[j]->m_description) 1692 data[i] = templates[j]; 1693 } 1694 } 1695 } 1696 1697 wxDocTemplate *theTemplate; 1698 1699 switch ( n ) 1700 { 1701 case 0: 1702 // no visible templates, hence nothing to choose from 1703 theTemplate = NULL; 1704 break; 1705 1706 case 1: 1707 // don't propose the user to choose if he heas no choice 1708 theTemplate = data[0]; 1709 break; 1710 1711 default: 1712 // propose the user to choose one of several 1713 theTemplate = (wxDocTemplate *)wxGetSingleChoiceData 1714 ( 1715 _("Select a document template"), 1716 _("Templates"), 1717 strings, 1718 (void **)data, 1719 wxFindSuitableParent() 1720 ); 1721 } 1722 1723 delete[] data; 1724 1725 return theTemplate; 1726} 1727 1728wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates, 1729 int noTemplates, bool sort) 1730{ 1731 wxArrayString strings; 1732 wxDocTemplate **data = new wxDocTemplate *[noTemplates]; 1733 int i; 1734 int n = 0; 1735 1736 for (i = 0; i < noTemplates; i++) 1737 { 1738 wxDocTemplate *templ = templates[i]; 1739 if ( templ->IsVisible() && !templ->GetViewName().empty() ) 1740 { 1741 int j; 1742 bool want = true; 1743 for (j = 0; j < n; j++) 1744 { 1745 //filter out NOT unique views 1746 if ( templates[i]->m_viewTypeName == data[j]->m_viewTypeName ) 1747 want = false; 1748 } 1749 1750 if ( want ) 1751 { 1752 strings.Add(templ->m_viewTypeName); 1753 data[n] = templ; 1754 n ++; 1755 } 1756 } 1757 } 1758 1759 if (sort) 1760 { 1761 strings.Sort(); // ascending sort 1762 // Yes, this will be slow, but template lists 1763 // are typically short. 1764 int j; 1765 n = strings.Count(); 1766 for (i = 0; i < n; i++) 1767 { 1768 for (j = 0; j < noTemplates; j++) 1769 { 1770 if (strings[i] == templates[j]->m_viewTypeName) 1771 data[i] = templates[j]; 1772 } 1773 } 1774 } 1775 1776 wxDocTemplate *theTemplate; 1777 1778 // the same logic as above 1779 switch ( n ) 1780 { 1781 case 0: 1782 theTemplate = (wxDocTemplate *)NULL; 1783 break; 1784 1785 case 1: 1786 theTemplate = data[0]; 1787 break; 1788 1789 default: 1790 theTemplate = (wxDocTemplate *)wxGetSingleChoiceData 1791 ( 1792 _("Select a document view"), 1793 _("Views"), 1794 strings, 1795 (void **)data, 1796 wxFindSuitableParent() 1797 ); 1798 1799 } 1800 1801 delete[] data; 1802 return theTemplate; 1803} 1804 1805void wxDocManager::AssociateTemplate(wxDocTemplate *temp) 1806{ 1807 if (!m_templates.Member(temp)) 1808 m_templates.Append(temp); 1809} 1810 1811void wxDocManager::DisassociateTemplate(wxDocTemplate *temp) 1812{ 1813 m_templates.DeleteObject(temp); 1814} 1815 1816// Add and remove a document from the manager's list 1817void wxDocManager::AddDocument(wxDocument *doc) 1818{ 1819 if (!m_docs.Member(doc)) 1820 m_docs.Append(doc); 1821} 1822 1823void wxDocManager::RemoveDocument(wxDocument *doc) 1824{ 1825 m_docs.DeleteObject(doc); 1826} 1827 1828// Views or windows should inform the document manager 1829// when a view is going in or out of focus 1830void wxDocManager::ActivateView(wxView *view, bool activate) 1831{ 1832 if ( activate ) 1833 { 1834 m_currentView = view; 1835 } 1836 else // deactivate 1837 { 1838 if ( m_currentView == view ) 1839 { 1840 // don't keep stale pointer 1841 m_currentView = (wxView *) NULL; 1842 } 1843 } 1844} 1845 1846// ---------------------------------------------------------------------------- 1847// Default document child frame 1848// ---------------------------------------------------------------------------- 1849 1850BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame) 1851 EVT_ACTIVATE(wxDocChildFrame::OnActivate) 1852 EVT_CLOSE(wxDocChildFrame::OnCloseWindow) 1853END_EVENT_TABLE() 1854 1855wxDocChildFrame::wxDocChildFrame(wxDocument *doc, 1856 wxView *view, 1857 wxFrame *frame, 1858 wxWindowID id, 1859 const wxString& title, 1860 const wxPoint& pos, 1861 const wxSize& size, 1862 long style, 1863 const wxString& name) 1864 : wxFrame(frame, id, title, pos, size, style, name) 1865{ 1866 m_childDocument = doc; 1867 m_childView = view; 1868 if (view) 1869 view->SetFrame(this); 1870} 1871 1872// Extend event processing to search the view's event table 1873bool wxDocChildFrame::ProcessEvent(wxEvent& event) 1874{ 1875 if (m_childView) 1876 m_childView->Activate(true); 1877 1878 if ( !m_childView || ! m_childView->ProcessEvent(event) ) 1879 { 1880 // Only hand up to the parent if it's a menu command 1881 if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) 1882 return wxEvtHandler::ProcessEvent(event); 1883 else 1884 return true; 1885 } 1886 else 1887 return true; 1888} 1889 1890void wxDocChildFrame::OnActivate(wxActivateEvent& event) 1891{ 1892 wxFrame::OnActivate(event); 1893 1894 if (m_childView) 1895 m_childView->Activate(event.GetActive()); 1896} 1897 1898void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event) 1899{ 1900 if (m_childView) 1901 { 1902 bool ans = event.CanVeto() 1903 ? m_childView->Close(false) // false means don't delete associated window 1904 : true; // Must delete. 1905 1906 if (ans) 1907 { 1908 m_childView->Activate(false); 1909 delete m_childView; 1910 m_childView = (wxView *) NULL; 1911 m_childDocument = (wxDocument *) NULL; 1912 1913 this->Destroy(); 1914 } 1915 else 1916 event.Veto(); 1917 } 1918 else 1919 event.Veto(); 1920} 1921 1922// ---------------------------------------------------------------------------- 1923// Default parent frame 1924// ---------------------------------------------------------------------------- 1925 1926BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame) 1927 EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit) 1928 EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile) 1929 EVT_CLOSE(wxDocParentFrame::OnCloseWindow) 1930END_EVENT_TABLE() 1931 1932wxDocParentFrame::wxDocParentFrame() 1933{ 1934 m_docManager = NULL; 1935} 1936 1937wxDocParentFrame::wxDocParentFrame(wxDocManager *manager, 1938 wxFrame *frame, 1939 wxWindowID id, 1940 const wxString& title, 1941 const wxPoint& pos, 1942 const wxSize& size, 1943 long style, 1944 const wxString& name) 1945 : wxFrame(frame, id, title, pos, size, style, name) 1946{ 1947 m_docManager = manager; 1948} 1949 1950bool wxDocParentFrame::Create(wxDocManager *manager, 1951 wxFrame *frame, 1952 wxWindowID id, 1953 const wxString& title, 1954 const wxPoint& pos, 1955 const wxSize& size, 1956 long style, 1957 const wxString& name) 1958{ 1959 m_docManager = manager; 1960 return base_type::Create(frame, id, title, pos, size, style, name); 1961} 1962 1963void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) 1964{ 1965 Close(); 1966} 1967 1968void wxDocParentFrame::OnMRUFile(wxCommandEvent& event) 1969{ 1970 int n = event.GetId() - wxID_FILE1; // the index in MRU list 1971 wxString filename(m_docManager->GetHistoryFile(n)); 1972 if ( !filename.empty() ) 1973 { 1974 // verify that the file exists before doing anything else 1975 if ( wxFile::Exists(filename) ) 1976 { 1977 // try to open it 1978 if (!m_docManager->CreateDocument(filename, wxDOC_SILENT)) 1979 { 1980 // remove the file from the MRU list. The user should already be notified. 1981 m_docManager->RemoveFileFromHistory(n); 1982 1983 wxLogError(_("The file '%s' couldn't be opened.\nIt has been removed from the most recently used files list."), 1984 filename.c_str()); 1985 } 1986 } 1987 else 1988 { 1989 // remove the bogus filename from the MRU list and notify the user 1990 // about it 1991 m_docManager->RemoveFileFromHistory(n); 1992 1993 wxLogError(_("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list."), 1994 filename.c_str()); 1995 } 1996 } 1997} 1998 1999// Extend event processing to search the view's event table 2000bool wxDocParentFrame::ProcessEvent(wxEvent& event) 2001{ 2002 // Try the document manager, then do default processing 2003 if (!m_docManager || !m_docManager->ProcessEvent(event)) 2004 return wxEvtHandler::ProcessEvent(event); 2005 else 2006 return true; 2007} 2008 2009// Define the behaviour for the frame closing 2010// - must delete all frames except for the main one. 2011void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event) 2012{ 2013 if ( m_docManager && !m_docManager->Clear(!event.CanVeto()) ) 2014 { 2015 // The user decided not to close finally, abort. 2016 event.Veto(); 2017 } 2018 else 2019 { 2020 this->Destroy(); 2021 } 2022} 2023 2024#if wxUSE_PRINTING_ARCHITECTURE 2025 2026wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title) 2027 : wxPrintout(title) 2028{ 2029 m_printoutView = view; 2030} 2031 2032bool wxDocPrintout::OnPrintPage(int WXUNUSED(page)) 2033{ 2034 wxDC *dc = GetDC(); 2035 2036 // Get the logical pixels per inch of screen and printer 2037 int ppiScreenX, ppiScreenY; 2038 GetPPIScreen(&ppiScreenX, &ppiScreenY); 2039 wxUnusedVar(ppiScreenY); 2040 int ppiPrinterX, ppiPrinterY; 2041 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); 2042 wxUnusedVar(ppiPrinterY); 2043 2044 // This scales the DC so that the printout roughly represents the 2045 // the screen scaling. The text point size _should_ be the right size 2046 // but in fact is too small for some reason. This is a detail that will 2047 // need to be addressed at some point but can be fudged for the 2048 // moment. 2049 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX); 2050 2051 // Now we have to check in case our real page size is reduced 2052 // (e.g. because we're drawing to a print preview memory DC) 2053 int pageWidth, pageHeight; 2054 int w, h; 2055 dc->GetSize(&w, &h); 2056 GetPageSizePixels(&pageWidth, &pageHeight); 2057 wxUnusedVar(pageHeight); 2058 2059 // If printer pageWidth == current DC width, then this doesn't 2060 // change. But w might be the preview bitmap width, so scale down. 2061 float overallScale = scale * (float)(w/(float)pageWidth); 2062 dc->SetUserScale(overallScale, overallScale); 2063 2064 if (m_printoutView) 2065 { 2066 m_printoutView->OnDraw(dc); 2067 } 2068 return true; 2069} 2070 2071bool wxDocPrintout::HasPage(int pageNum) 2072{ 2073 return (pageNum == 1); 2074} 2075 2076bool wxDocPrintout::OnBeginDocument(int startPage, int endPage) 2077{ 2078 if (!wxPrintout::OnBeginDocument(startPage, endPage)) 2079 return false; 2080 2081 return true; 2082} 2083 2084void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) 2085{ 2086 *minPage = 1; 2087 *maxPage = 1; 2088 *selPageFrom = 1; 2089 *selPageTo = 1; 2090} 2091 2092#endif // wxUSE_PRINTING_ARCHITECTURE 2093 2094// ---------------------------------------------------------------------------- 2095// File history processor 2096// ---------------------------------------------------------------------------- 2097 2098static inline wxChar* MYcopystring(const wxString& s) 2099{ 2100 wxChar* copy = new wxChar[s.length() + 1]; 2101 return wxStrcpy(copy, s.c_str()); 2102} 2103 2104static inline wxChar* MYcopystring(const wxChar* s) 2105{ 2106 wxChar* copy = new wxChar[wxStrlen(s) + 1]; 2107 return wxStrcpy(copy, s); 2108} 2109 2110wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase) 2111{ 2112 m_fileMaxFiles = maxFiles; 2113 m_idBase = idBase; 2114 m_fileHistoryN = 0; 2115 m_fileHistory = new wxChar *[m_fileMaxFiles]; 2116} 2117 2118wxFileHistory::~wxFileHistory() 2119{ 2120 size_t i; 2121 for (i = 0; i < m_fileHistoryN; i++) 2122 delete[] m_fileHistory[i]; 2123 delete[] m_fileHistory; 2124} 2125 2126// File history management 2127void wxFileHistory::AddFileToHistory(const wxString& file) 2128{ 2129 size_t i; 2130 2131 // Check we don't already have this file 2132 for (i = 0; i < m_fileHistoryN; i++) 2133 { 2134#if defined( __WXMSW__ ) // Add any other OSes with case insensitive file names 2135 wxString testString; 2136 if ( m_fileHistory[i] ) 2137 testString = m_fileHistory[i]; 2138 if ( m_fileHistory[i] && ( file.Lower() == testString.Lower() ) ) 2139#else 2140 if ( m_fileHistory[i] && ( file == m_fileHistory[i] ) ) 2141#endif 2142 { 2143 // we do have it, move it to the top of the history 2144 RemoveFileFromHistory (i); 2145 AddFileToHistory (file); 2146 return; 2147 } 2148 } 2149 2150 // if we already have a full history, delete the one at the end 2151 if ( m_fileMaxFiles == m_fileHistoryN ) 2152 { 2153 RemoveFileFromHistory (m_fileHistoryN - 1); 2154 AddFileToHistory (file); 2155 return; 2156 } 2157 2158 // Add to the project file history: 2159 // Move existing files (if any) down so we can insert file at beginning. 2160 if (m_fileHistoryN < m_fileMaxFiles) 2161 { 2162 wxList::compatibility_iterator node = m_fileMenus.GetFirst(); 2163 while (node) 2164 { 2165 wxMenu* menu = (wxMenu*) node->GetData(); 2166 if ( m_fileHistoryN == 0 && menu->GetMenuItemCount() ) 2167 { 2168 menu->AppendSeparator(); 2169 } 2170 menu->Append(m_idBase+m_fileHistoryN, _("[EMPTY]")); 2171 node = node->GetNext(); 2172 } 2173 m_fileHistoryN ++; 2174 } 2175 // Shuffle filenames down 2176 for (i = (m_fileHistoryN-1); i > 0; i--) 2177 { 2178 m_fileHistory[i] = m_fileHistory[i-1]; 2179 } 2180 m_fileHistory[0] = MYcopystring(file); 2181 2182 // this is the directory of the last opened file 2183 wxString pathCurrent; 2184 wxSplitPath( m_fileHistory[0], &pathCurrent, NULL, NULL ); 2185 for (i = 0; i < m_fileHistoryN; i++) 2186 { 2187 if ( m_fileHistory[i] ) 2188 { 2189 // if in same directory just show the filename; otherwise the full 2190 // path 2191 wxString pathInMenu, path, filename, ext; 2192 wxSplitPath( m_fileHistory[i], &path, &filename, &ext ); 2193 if ( path == pathCurrent ) 2194 { 2195 pathInMenu = filename; 2196 if ( !ext.empty() ) 2197 pathInMenu = pathInMenu + wxFILE_SEP_EXT + ext; 2198 } 2199 else 2200 { 2201 // absolute path; could also set relative path 2202 pathInMenu = m_fileHistory[i]; 2203 } 2204 2205 // we need to quote '&' characters which are used for mnemonics 2206 pathInMenu.Replace(_T("&"), _T("&&")); 2207 wxString buf; 2208 buf.Printf(s_MRUEntryFormat, i + 1, pathInMenu.c_str()); 2209 wxList::compatibility_iterator node = m_fileMenus.GetFirst(); 2210 while (node) 2211 { 2212 wxMenu* menu = (wxMenu*) node->GetData(); 2213 menu->SetLabel(m_idBase + i, buf); 2214 node = node->GetNext(); 2215 } 2216 } 2217 } 2218} 2219 2220void wxFileHistory::RemoveFileFromHistory(size_t i) 2221{ 2222 wxCHECK_RET( i < m_fileHistoryN, 2223 wxT("invalid index in wxFileHistory::RemoveFileFromHistory") ); 2224 2225 // delete the element from the array (could use memmove() too...) 2226 delete [] m_fileHistory[i]; 2227 2228 size_t j; 2229 for ( j = i; j < m_fileHistoryN - 1; j++ ) 2230 { 2231 m_fileHistory[j] = m_fileHistory[j + 1]; 2232 } 2233 2234 wxList::compatibility_iterator node = m_fileMenus.GetFirst(); 2235 while ( node ) 2236 { 2237 wxMenu* menu = (wxMenu*) node->GetData(); 2238 2239 // shuffle filenames up 2240 wxString buf; 2241 for ( j = i; j < m_fileHistoryN - 1; j++ ) 2242 { 2243 buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j]); 2244 menu->SetLabel(m_idBase + j, buf); 2245 } 2246 2247 node = node->GetNext(); 2248 2249 // delete the last menu item which is unused now 2250 wxWindowID lastItemId = m_idBase + wx_truncate_cast(wxWindowID, m_fileHistoryN) - 1; 2251 if (menu->FindItem(lastItemId)) 2252 { 2253 menu->Delete(lastItemId); 2254 } 2255 2256 // delete the last separator too if no more files are left 2257 if ( m_fileHistoryN == 1 ) 2258 { 2259 wxMenuItemList::compatibility_iterator nodeLast = menu->GetMenuItems().GetLast(); 2260 if ( nodeLast ) 2261 { 2262 wxMenuItem *menuItem = nodeLast->GetData(); 2263 if ( menuItem->IsSeparator() ) 2264 { 2265 menu->Delete(menuItem); 2266 } 2267 //else: should we search backwards for the last separator? 2268 } 2269 //else: menu is empty somehow 2270 } 2271 } 2272 2273 m_fileHistoryN--; 2274} 2275 2276wxString wxFileHistory::GetHistoryFile(size_t i) const 2277{ 2278 wxString s; 2279 if ( i < m_fileHistoryN ) 2280 { 2281 s = m_fileHistory[i]; 2282 } 2283 else 2284 { 2285 wxFAIL_MSG( wxT("bad index in wxFileHistory::GetHistoryFile") ); 2286 } 2287 2288 return s; 2289} 2290 2291void wxFileHistory::UseMenu(wxMenu *menu) 2292{ 2293 if (!m_fileMenus.Member(menu)) 2294 m_fileMenus.Append(menu); 2295} 2296 2297void wxFileHistory::RemoveMenu(wxMenu *menu) 2298{ 2299 m_fileMenus.DeleteObject(menu); 2300} 2301 2302#if wxUSE_CONFIG 2303void wxFileHistory::Load(wxConfigBase& config) 2304{ 2305 m_fileHistoryN = 0; 2306 wxString buf; 2307 buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); 2308 wxString historyFile; 2309 while ((m_fileHistoryN < m_fileMaxFiles) && config.Read(buf, &historyFile) && (!historyFile.empty())) 2310 { 2311 m_fileHistory[m_fileHistoryN] = MYcopystring((const wxChar*) historyFile); 2312 m_fileHistoryN ++; 2313 buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); 2314 historyFile = wxEmptyString; 2315 } 2316 AddFilesToMenu(); 2317} 2318 2319void wxFileHistory::Save(wxConfigBase& config) 2320{ 2321 size_t i; 2322 for (i = 0; i < m_fileMaxFiles; i++) 2323 { 2324 wxString buf; 2325 buf.Printf(wxT("file%d"), (int)i+1); 2326 if (i < m_fileHistoryN) 2327 config.Write(buf, wxString(m_fileHistory[i])); 2328 else 2329 config.Write(buf, wxEmptyString); 2330 } 2331} 2332#endif // wxUSE_CONFIG 2333 2334void wxFileHistory::AddFilesToMenu() 2335{ 2336 if (m_fileHistoryN > 0) 2337 { 2338 wxList::compatibility_iterator node = m_fileMenus.GetFirst(); 2339 while (node) 2340 { 2341 wxMenu* menu = (wxMenu*) node->GetData(); 2342 if (menu->GetMenuItemCount()) 2343 { 2344 menu->AppendSeparator(); 2345 } 2346 2347 size_t i; 2348 for (i = 0; i < m_fileHistoryN; i++) 2349 { 2350 if (m_fileHistory[i]) 2351 { 2352 wxString buf; 2353 buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); 2354 menu->Append(m_idBase+i, buf); 2355 } 2356 } 2357 node = node->GetNext(); 2358 } 2359 } 2360} 2361 2362void wxFileHistory::AddFilesToMenu(wxMenu* menu) 2363{ 2364 if (m_fileHistoryN > 0) 2365 { 2366 if (menu->GetMenuItemCount()) 2367 { 2368 menu->AppendSeparator(); 2369 } 2370 2371 size_t i; 2372 for (i = 0; i < m_fileHistoryN; i++) 2373 { 2374 if (m_fileHistory[i]) 2375 { 2376 wxString buf; 2377 buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); 2378 menu->Append(m_idBase+i, buf); 2379 } 2380 } 2381 } 2382} 2383 2384// ---------------------------------------------------------------------------- 2385// Permits compatibility with existing file formats and functions that 2386// manipulate files directly 2387// ---------------------------------------------------------------------------- 2388 2389#if wxUSE_STD_IOSTREAM 2390 2391bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream) 2392{ 2393 wxFFile file(filename, _T("rb")); 2394 if ( !file.IsOpened() ) 2395 return false; 2396 2397 char buf[4096]; 2398 2399 size_t nRead; 2400 do 2401 { 2402 nRead = file.Read(buf, WXSIZEOF(buf)); 2403 if ( file.Error() ) 2404 return false; 2405 2406 stream.write(buf, nRead); 2407 if ( !stream ) 2408 return false; 2409 } 2410 while ( !file.Eof() ); 2411 2412 return true; 2413} 2414 2415bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename) 2416{ 2417 wxFFile file(filename, _T("wb")); 2418 if ( !file.IsOpened() ) 2419 return false; 2420 2421 char buf[4096]; 2422 do 2423 { 2424 stream.read(buf, WXSIZEOF(buf)); 2425 if ( !stream.bad() ) // fail may be set on EOF, don't use operator!() 2426 { 2427 if ( !file.Write(buf, stream.gcount()) ) 2428 return false; 2429 } 2430 } 2431 while ( !stream.eof() ); 2432 2433 return true; 2434} 2435 2436#else // !wxUSE_STD_IOSTREAM 2437 2438bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream) 2439{ 2440 wxFFile file(filename, _T("rb")); 2441 if ( !file.IsOpened() ) 2442 return false; 2443 2444 char buf[4096]; 2445 2446 size_t nRead; 2447 do 2448 { 2449 nRead = file.Read(buf, WXSIZEOF(buf)); 2450 if ( file.Error() ) 2451 return false; 2452 2453 stream.Write(buf, nRead); 2454 if ( !stream ) 2455 return false; 2456 } 2457 while ( !file.Eof() ); 2458 2459 return true; 2460} 2461 2462bool wxTransferStreamToFile(wxInputStream& stream, const wxString& filename) 2463{ 2464 wxFFile file(filename, _T("wb")); 2465 if ( !file.IsOpened() ) 2466 return false; 2467 2468 char buf[4096]; 2469 for ( ;; ) 2470 { 2471 stream.Read(buf, WXSIZEOF(buf)); 2472 2473 const size_t nRead = stream.LastRead(); 2474 if ( !nRead ) 2475 { 2476 if ( stream.Eof() ) 2477 break; 2478 2479 return false; 2480 } 2481 2482 if ( !file.Write(buf, nRead) ) 2483 return false; 2484 } 2485 2486 return true; 2487} 2488 2489#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM 2490 2491#endif // wxUSE_DOC_VIEW_ARCHITECTURE 2492