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