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