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