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