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