]> git.saurik.com Git - wxWidgets.git/blame - src/common/docview.cpp
wxImage now uses GTK 1.2's fast rendering code if possible
[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"
50920146 42#include "wx/dialog.h"
0fb67cd1
VZ
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
50920146 95static inline wxString FindExtension(const wxChar *path);
0fb67cd1
VZ
96
97// ============================================================================
98// implementation
99// ============================================================================
100
101// ----------------------------------------------------------------------------
102// local functions
103// ----------------------------------------------------------------------------
104
50920146 105static wxString FindExtension(const wxChar *path)
0fb67cd1
VZ
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
50920146 282 ofstream store(file.fn_str());
0fb67cd1
VZ
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
50920146 313 ifstream store(file.fn_str());
0fb67cd1
VZ
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?"),
50920146 405 (const wxChar *)title);
0fb67cd1
VZ
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 596 m_documentManager = manager;
0fb67cd1
VZ
597 m_description = descr;
598 m_directory = dir;
599 m_defaultExt = ext;
600 m_fileFilter = filter;
601 m_flags = flags;
602 m_docTypeName = docTypeName;
603 m_viewTypeName = viewTypeName;
604 m_documentManager->AssociateTemplate(this);
c801d85f 605
0fb67cd1
VZ
606 m_docClassInfo = docClassInfo;
607 m_viewClassInfo = viewClassInfo;
c801d85f
KB
608}
609
0fb67cd1 610wxDocTemplate::~wxDocTemplate()
c801d85f 611{
0fb67cd1 612 m_documentManager->DisassociateTemplate(this);
c801d85f 613}
0fb67cd1
VZ
614
615// Tries to dynamically construct an object of the right class.
c801d85f
KB
616wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags)
617{
0fb67cd1
VZ
618 if (!m_docClassInfo)
619 return (wxDocument *) NULL;
620 wxDocument *doc = (wxDocument *)m_docClassInfo->CreateObject();
621 doc->SetFilename(path);
622 doc->SetDocumentTemplate(this);
623 GetDocumentManager()->AddDocument(doc);
624 doc->SetCommandProcessor(doc->OnCreateCommandProcessor());
625
626 if (doc->OnCreate(path, flags))
627 return doc;
628 else
629 {
630 delete doc;
631 return (wxDocument *) NULL;
632 }
c801d85f
KB
633}
634
635wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags)
636{
0fb67cd1
VZ
637 if (!m_viewClassInfo)
638 return (wxView *) NULL;
639 wxView *view = (wxView *)m_viewClassInfo->CreateObject();
640 view->SetDocument(doc);
641 if (view->OnCreate(doc, flags))
642 {
643 return view;
644 }
645 else
646 {
647 delete view;
648 return (wxView *) NULL;
649 }
c801d85f
KB
650}
651
0fb67cd1
VZ
652// ----------------------------------------------------------------------------
653// wxDocManager
654// ----------------------------------------------------------------------------
655
c801d85f
KB
656BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler)
657 EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen)
658 EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose)
659 EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert)
660 EVT_MENU(wxID_NEW, wxDocManager::OnFileNew)
661 EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave)
662 EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs)
663 EVT_MENU(wxID_UNDO, wxDocManager::OnUndo)
664 EVT_MENU(wxID_REDO, wxDocManager::OnRedo)
665 EVT_MENU(wxID_PRINT, wxDocManager::OnPrint)
666 EVT_MENU(wxID_PRINT_SETUP, wxDocManager::OnPrintSetup)
667 EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview)
668END_EVENT_TABLE()
669
670wxDocManager::wxDocManager(long flags, bool initialize)
671{
0fb67cd1
VZ
672 m_defaultDocumentNameCounter = 1;
673 m_flags = flags;
674 m_currentView = (wxView *) NULL;
675 m_maxDocsOpen = 10000;
676 m_fileHistory = (wxFileHistory *) NULL;
677 if (initialize)
678 Initialize();
c801d85f
KB
679}
680
0fb67cd1 681wxDocManager::~wxDocManager()
c801d85f 682{
0fb67cd1
VZ
683 Clear();
684 if (m_fileHistory)
685 delete m_fileHistory;
c801d85f
KB
686}
687
688bool wxDocManager::Clear(bool force)
689{
0fb67cd1
VZ
690 wxNode *node = m_docs.First();
691 while (node)
692 {
693 wxDocument *doc = (wxDocument *)node->Data();
694 wxNode *next = node->Next();
695
696 if (!doc->Close() && !force)
697 return FALSE;
698
699 // Implicitly deletes the document when the last
700 // view is removed (deleted)
701 doc->DeleteAllViews();
702
703 // Check document is deleted
704 if (m_docs.Member(doc))
705 delete doc;
706
707 // This assumes that documents are not connected in
708 // any way, i.e. deleting one document does NOT
709 // delete another.
710 node = next;
711 }
712 node = m_templates.First();
713 while (node)
714 {
c801d85f
KB
715 wxDocTemplate *templ = (wxDocTemplate*) node->Data();
716 wxNode* next = node->Next();
717 delete templ;
718 node = next;
0fb67cd1
VZ
719 }
720 return TRUE;
c801d85f
KB
721}
722
0fb67cd1 723bool wxDocManager::Initialize()
c801d85f 724{
0fb67cd1
VZ
725 m_fileHistory = OnCreateFileHistory();
726 return TRUE;
c801d85f
KB
727}
728
0fb67cd1 729wxFileHistory *wxDocManager::OnCreateFileHistory()
c801d85f 730{
0fb67cd1 731 return new wxFileHistory;
c801d85f
KB
732}
733
734void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event))
735{
0fb67cd1
VZ
736 wxDocument *doc = GetCurrentDocument();
737 if (!doc)
738 return;
739 if (doc->Close())
740 {
741 doc->DeleteAllViews();
742 if (m_docs.Member(doc))
743 delete doc;
744 }
c801d85f
KB
745}
746
747void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event))
748{
0fb67cd1 749 CreateDocument(wxString(""), wxDOC_NEW);
c801d85f
KB
750}
751
752void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event))
753{
0fb67cd1 754 CreateDocument(wxString(""), 0);
c801d85f
KB
755}
756
757void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event))
758{
0fb67cd1
VZ
759 wxDocument *doc = GetCurrentDocument();
760 if (!doc)
761 return;
762 doc->Revert();
c801d85f
KB
763}
764
765void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event))
766{
0fb67cd1
VZ
767 wxDocument *doc = GetCurrentDocument();
768 if (!doc)
769 return;
770 doc->Save();
c801d85f
KB
771}
772
773void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event))
774{
0fb67cd1
VZ
775 wxDocument *doc = GetCurrentDocument();
776 if (!doc)
777 return;
778 doc->SaveAs();
c801d85f
KB
779}
780
781void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event))
782{
0fb67cd1
VZ
783 wxView *view = GetCurrentView();
784 if (!view)
785 return;
c801d85f 786
0fb67cd1
VZ
787 wxPrintout *printout = view->OnCreatePrintout();
788 if (printout)
789 {
790 wxPrinter printer;
791 printer.Print(view->GetFrame(), printout, TRUE);
c801d85f 792
0fb67cd1
VZ
793 delete printout;
794 }
c801d85f
KB
795}
796
797void wxDocManager::OnPrintSetup(wxCommandEvent& WXUNUSED(event))
798{
0fb67cd1
VZ
799 wxWindow *parentWin = wxTheApp->GetTopWindow();
800 wxView *view = GetCurrentView();
801 if (view)
802 parentWin = view->GetFrame();
c801d85f 803
0fb67cd1 804 wxPrintDialogData data;
c801d85f 805
0fb67cd1
VZ
806 wxPrintDialog printerDialog(parentWin, & data);
807 printerDialog.GetPrintDialogData().SetSetupDialog(TRUE);
808 printerDialog.ShowModal();
c801d85f
KB
809}
810
811void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event))
812{
0fb67cd1
VZ
813 wxView *view = GetCurrentView();
814 if (!view)
815 return;
c801d85f 816
0fb67cd1
VZ
817 wxPrintout *printout = view->OnCreatePrintout();
818 if (printout)
819 {
820 // Pass two printout objects: for preview, and possible printing.
821 wxPrintPreviewBase *preview = (wxPrintPreviewBase *) NULL;
822 preview = new wxPrintPreview(printout, view->OnCreatePrintout());
823
824 wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"),
825 wxPoint(100, 100), wxSize(600, 650));
826 frame->Centre(wxBOTH);
827 frame->Initialize();
828 frame->Show(TRUE);
829 }
c801d85f
KB
830}
831
832void wxDocManager::OnUndo(wxCommandEvent& WXUNUSED(event))
833{
0fb67cd1
VZ
834 wxDocument *doc = GetCurrentDocument();
835 if (!doc)
836 return;
837 if (doc->GetCommandProcessor())
838 doc->GetCommandProcessor()->Undo();
c801d85f
KB
839}
840
841void wxDocManager::OnRedo(wxCommandEvent& WXUNUSED(event))
842{
0fb67cd1
VZ
843 wxDocument *doc = GetCurrentDocument();
844 if (!doc)
845 return;
846 if (doc->GetCommandProcessor())
847 doc->GetCommandProcessor()->Redo();
c801d85f
KB
848}
849
637f467a
JS
850wxView *wxDocManager::GetCurrentView(void) const
851{
852 if (m_currentView)
853 return m_currentView;
854 if (m_docs.Number() == 1)
855 {
856 wxDocument* doc = (wxDocument*) m_docs.First()->Data();
857 return doc->GetFirstView();
858 }
c67daf87 859 return (wxView *) NULL;
637f467a
JS
860}
861
862// Extend event processing to search the view's event table
863bool wxDocManager::ProcessEvent(wxEvent& event)
864{
865 wxView* view = GetCurrentView();
866 if (view)
867 {
868 if (view->ProcessEvent(event))
869 return TRUE;
870 }
871 return wxEvtHandler::ProcessEvent(event);
872}
873
c801d85f
KB
874wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags)
875{
0fb67cd1
VZ
876 wxDocTemplate **templates = new wxDocTemplate *[m_templates.Number()];
877 int i;
878 int n = 0;
879 for (i = 0; i < m_templates.Number(); i++)
c801d85f 880 {
0fb67cd1
VZ
881 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Nth(i)->Data());
882 if (temp->IsVisible())
883 {
884 templates[n] = temp;
885 n ++;
886 }
c801d85f 887 }
0fb67cd1 888 if (n == 0)
c801d85f 889 {
0fb67cd1
VZ
890 delete[] templates;
891 return (wxDocument *) NULL;
c801d85f 892 }
0fb67cd1
VZ
893
894 // If we've reached the max number of docs, close the
895 // first one.
896 if (GetDocuments().Number() >= m_maxDocsOpen)
c801d85f 897 {
0fb67cd1
VZ
898 wxDocument *doc = (wxDocument *)GetDocuments().First()->Data();
899 if (doc->Close())
900 {
901 // Implicitly deletes the document when
902 // the last view is deleted
903 doc->DeleteAllViews();
904
905 // Check we're really deleted
906 if (m_docs.Member(doc))
907 delete doc;
908 }
909 else
910 return (wxDocument *) NULL;
c801d85f
KB
911 }
912
0fb67cd1
VZ
913 // New document: user chooses a template, unless there's only one.
914 if (flags & wxDOC_NEW)
c801d85f 915 {
0fb67cd1
VZ
916 if (n == 1)
917 {
918 wxDocTemplate *temp = templates[0];
919 delete[] templates;
920 wxDocument *newDoc = temp->CreateDocument(path, flags);
921 if (newDoc)
922 {
923 newDoc->SetDocumentName(temp->GetDocumentName());
924 newDoc->SetDocumentTemplate(temp);
925 newDoc->OnNewDocument();
926 }
927 return newDoc;
928 }
929
930 wxDocTemplate *temp = SelectDocumentType(templates, n);
931 delete[] templates;
932 if (temp)
933 {
934 wxDocument *newDoc = temp->CreateDocument(path, flags);
935 if (newDoc)
936 {
937 newDoc->SetDocumentName(temp->GetDocumentName());
938 newDoc->SetDocumentTemplate(temp);
939 newDoc->OnNewDocument();
940 }
941 return newDoc;
942 }
943 else
944 return (wxDocument *) NULL;
c801d85f 945 }
c801d85f 946
0fb67cd1
VZ
947 // Existing document
948 wxDocTemplate *temp = (wxDocTemplate *) NULL;
c801d85f 949
0fb67cd1
VZ
950 wxString path2("");
951 if (path != "")
952 path2 = path;
c801d85f 953
0fb67cd1
VZ
954 if (flags & wxDOC_SILENT)
955 temp = FindTemplateForPath(path2);
956 else
957 temp = SelectDocumentPath(templates, n, path2, flags);
c801d85f 958
0fb67cd1 959 delete[] templates;
c801d85f 960
0fb67cd1 961 if (temp)
c801d85f 962 {
0fb67cd1
VZ
963 wxDocument *newDoc = temp->CreateDocument(path2, flags);
964 if (newDoc)
965 {
966 newDoc->SetDocumentName(temp->GetDocumentName());
967 newDoc->SetDocumentTemplate(temp);
968 if (!newDoc->OnOpenDocument(path2))
969 {
970 delete newDoc;
971 return (wxDocument *) NULL;
972 }
973 AddFileToHistory(path2);
974 }
975 return newDoc;
c801d85f 976 }
0fb67cd1
VZ
977 else
978 return (wxDocument *) NULL;
c801d85f
KB
979}
980
981wxView *wxDocManager::CreateView(wxDocument *doc, long flags)
982{
0fb67cd1
VZ
983 wxDocTemplate **templates = new wxDocTemplate *[m_templates.Number()];
984 int n =0;
985 int i;
986 for (i = 0; i < m_templates.Number(); i++)
987 {
988 wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Nth(i)->Data());
989 if (temp->IsVisible())
990 {
991 if (temp->GetDocumentName() == doc->GetDocumentName())
992 {
993 templates[n] = temp;
994 n ++;
995 }
996 }
997 }
998 if (n == 0)
999 {
1000 delete[] templates;
1001 return (wxView *) NULL;
1002 }
1003 if (n == 1)
1004 {
1005 wxDocTemplate *temp = templates[0];
1006 delete[] templates;
1007 wxView *view = temp->CreateView(doc, flags);
1008 if (view)
1009 view->SetViewName(temp->GetViewName());
1010 return view;
1011 }
1012
1013 wxDocTemplate *temp = SelectViewType(templates, n);
c801d85f 1014 delete[] templates;
0fb67cd1
VZ
1015 if (temp)
1016 {
1017 wxView *view = temp->CreateView(doc, flags);
1018 if (view)
1019 view->SetViewName(temp->GetViewName());
1020 return view;
1021 }
1022 else
1023 return (wxView *) NULL;
c801d85f
KB
1024}
1025
1026// Not yet implemented
1027void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags))
1028{
1029}
1030
1031// Not yet implemented
1032bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc))
1033{
0fb67cd1 1034 return FALSE;
c801d85f
KB
1035}
1036
1037wxDocument *wxDocManager::GetCurrentDocument(void) const
1038{
0fb67cd1
VZ
1039 if (m_currentView)
1040 return m_currentView->GetDocument();
1041 else
1042 return (wxDocument *) NULL;
c801d85f
KB
1043}
1044
1045// Make a default document name
1046bool wxDocManager::MakeDefaultName(wxString& name)
1047{
0fb67cd1
VZ
1048 name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter);
1049 m_defaultDocumentNameCounter++;
53c6e7cc 1050
0fb67cd1 1051 return TRUE;
c801d85f
KB
1052}
1053
1054// Not yet implemented
1055wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path))
1056{
0fb67cd1 1057 return (wxDocTemplate *) NULL;
c801d85f
KB
1058}
1059
1060// File history management
1061void wxDocManager::AddFileToHistory(const wxString& file)
1062{
0fb67cd1
VZ
1063 if (m_fileHistory)
1064 m_fileHistory->AddFileToHistory(file);
c801d85f
KB
1065}
1066
1067wxString wxDocManager::GetHistoryFile(int i) const
1068{
0fb67cd1
VZ
1069 wxString histFile;
1070
1071 if (m_fileHistory)
1072 histFile = m_fileHistory->GetHistoryFile(i);
1073
1074 return histFile;
c801d85f
KB
1075}
1076
1077void wxDocManager::FileHistoryUseMenu(wxMenu *menu)
1078{
0fb67cd1
VZ
1079 if (m_fileHistory)
1080 m_fileHistory->UseMenu(menu);
c801d85f
KB
1081}
1082
7f555861 1083void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu)
c801d85f 1084{
0fb67cd1
VZ
1085 if (m_fileHistory)
1086 m_fileHistory->RemoveMenu(menu);
c801d85f
KB
1087}
1088
702ca7c0 1089#if wxUSE_CONFIG
7f555861 1090void wxDocManager::FileHistoryLoad(wxConfigBase& config)
c801d85f 1091{
0fb67cd1
VZ
1092 if (m_fileHistory)
1093 m_fileHistory->Load(config);
7f555861
JS
1094}
1095
1096void wxDocManager::FileHistorySave(wxConfigBase& config)
1097{
0fb67cd1
VZ
1098 if (m_fileHistory)
1099 m_fileHistory->Save(config);
7f555861 1100}
ac57418f 1101#endif
7f555861
JS
1102
1103void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu)
1104{
0fb67cd1
VZ
1105 if (m_fileHistory)
1106 m_fileHistory->AddFilesToMenu(menu);
7f555861
JS
1107}
1108
1109void wxDocManager::FileHistoryAddFilesToMenu()
1110{
0fb67cd1
VZ
1111 if (m_fileHistory)
1112 m_fileHistory->AddFilesToMenu();
c801d85f
KB
1113}
1114
1115int wxDocManager::GetNoHistoryFiles(void) const
1116{
0fb67cd1
VZ
1117 if (m_fileHistory)
1118 return m_fileHistory->GetNoHistoryFiles();
c801d85f 1119 else
0fb67cd1 1120 return 0;
c801d85f
KB
1121}
1122
1123
0fb67cd1
VZ
1124// Given a path, try to find a matching template. Won't always work, of
1125// course.
c801d85f
KB
1126wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path)
1127{
0fb67cd1
VZ
1128 wxString theExt = FindExtension(path);
1129 if (!theExt)
1130 return (wxDocTemplate *) NULL;
1131 wxDocTemplate *theTemplate = (wxDocTemplate *) NULL;
c801d85f 1132
0fb67cd1
VZ
1133 if (m_templates.Number() == 1)
1134 return (wxDocTemplate *)m_templates.First()->Data();
c801d85f 1135
0fb67cd1
VZ
1136 // Find the template which this extension corresponds to
1137 int i;
1138 for (i = 0; i < m_templates.Number(); i++)
c801d85f 1139 {
0fb67cd1 1140 wxDocTemplate *temp = (wxDocTemplate *)m_templates.Nth(i)->Data();
50920146 1141 if (wxStrcmp(temp->GetDefaultExtension(), theExt) == 0)
0fb67cd1
VZ
1142 {
1143 theTemplate = temp;
1144 break;
1145 }
c801d85f 1146 }
0fb67cd1 1147 return theTemplate;
c801d85f
KB
1148}
1149
1150// Prompts user to open a file, using file specs in templates.
1151// How to implement in wxWindows? Must extend the file selector
1152// dialog or implement own; OR match the extension to the
1153// template extension.
df875e59 1154
c801d85f 1155wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates,
0fb67cd1
VZ
1156 int noTemplates,
1157 wxString& path,
1158 long WXUNUSED(flags),
1159 bool WXUNUSED(save))
c801d85f 1160{
0fb67cd1 1161 // We can only have multiple filters in Windows
2049ba38 1162#ifdef __WXMSW__
ba681060
VZ
1163 wxString descrBuf;
1164
1165 int i;
1166 for (i = 0; i < noTemplates; i++)
c801d85f 1167 {
ba681060
VZ
1168 if (templates[i]->IsVisible())
1169 {
1170 // add a '|' to separate this filter from the previous one
1171 if ( !descrBuf.IsEmpty() )
50920146 1172 descrBuf << _T('|');
ba681060
VZ
1173
1174 descrBuf << templates[i]->GetDescription()
50920146 1175 << _T(" (") << templates[i]->GetFileFilter() << _T(") |")
0fb67cd1 1176 << templates[i]->GetFileFilter();
ba681060 1177 }
c801d85f 1178 }
a4294b78 1179#else
50920146 1180 wxString descrBuf = _T("*.*");
a4294b78 1181#endif
c801d85f 1182
50920146 1183 wxString pathTmp = wxFileSelector(_("Select a file"), _T(""), _T(""), _T(""),
0fb67cd1 1184 descrBuf, 0, wxTheApp->GetTopWindow());
ba681060 1185
0fb67cd1
VZ
1186 if (!pathTmp.IsEmpty())
1187 {
1188 path = pathTmp;
1189 wxString theExt = FindExtension(path);
1190 if (!theExt)
1191 return (wxDocTemplate *) NULL;
1192
1193 // This is dodgy in that we're selecting the template on the
1194 // basis of the file extension, which may not be a standard
1195 // one. We really want to know exactly which template was
1196 // chosen by using a more advanced file selector.
1197 wxDocTemplate *theTemplate = FindTemplateForPath(path);
1198 return theTemplate;
1199 }
1200 else
1201 {
1202 path = "";
1203 return (wxDocTemplate *) NULL;
1204 }
a4294b78 1205#if 0
0fb67cd1
VZ
1206 // In all other windowing systems, until we have more advanced
1207 // file selectors, we must select the document type (template) first, and
1208 // _then_ pop up the file selector.
1209 wxDocTemplate *temp = SelectDocumentType(templates, noTemplates);
1210 if (!temp)
1211 return (wxDocTemplate *) NULL;
1212
1213 char *pathTmp = wxFileSelector(_("Select a file"), "", "",
1214 temp->GetDefaultExtension(),
1215 temp->GetFileFilter(),
1216 0, wxTheApp->GetTopWindow());
1217
1218 if (pathTmp)
1219 {
1220 path = pathTmp;
1221 return temp;
1222 }
1223 else
1224 return (wxDocTemplate *) NULL;
1225#endif // 0
c801d85f
KB
1226}
1227
1228wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates,
0fb67cd1
VZ
1229 int noTemplates)
1230{
50920146
OK
1231 wxChar **strings = new wxChar *[noTemplates];
1232 wxChar **data = new wxChar *[noTemplates];
0fb67cd1
VZ
1233 int i;
1234 int n = 0;
1235 for (i = 0; i < noTemplates; i++)
1236 {
1237 if (templates[i]->IsVisible())
1238 {
1239 strings[n] = WXSTRINGCAST templates[i]->m_description;
50920146 1240 data[n] = (wxChar *)templates[i];
0fb67cd1
VZ
1241 n ++;
1242 }
1243 }
1244 if (n == 0)
1245 {
1246 delete[] strings;
1247 delete[] data;
1248 return (wxDocTemplate *) NULL;
1249 }
1250 else if (n == 1)
1251 {
1252 wxDocTemplate *temp = (wxDocTemplate *)data[0];
1253 delete[] strings;
1254 delete[] data;
1255 return temp;
1256 }
1257
1258 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData(_("Select a document template"), _("Templates"), n,
1259 strings, data);
c801d85f
KB
1260 delete[] strings;
1261 delete[] data;
0fb67cd1 1262 return theTemplate;
c801d85f
KB
1263}
1264
1265wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates,
0fb67cd1 1266 int noTemplates)
c801d85f 1267{
50920146
OK
1268 wxChar **strings = new wxChar *[noTemplates];
1269 wxChar **data = new wxChar *[noTemplates];
0fb67cd1
VZ
1270 int i;
1271 int n = 0;
1272 for (i = 0; i < noTemplates; i++)
c801d85f 1273 {
0fb67cd1
VZ
1274 if (templates[i]->IsVisible() && (templates[i]->GetViewName() != ""))
1275 {
1276 strings[n] = WXSTRINGCAST templates[i]->m_viewTypeName;
50920146 1277 data[n] = (wxChar *)templates[i];
0fb67cd1
VZ
1278 n ++;
1279 }
c801d85f 1280 }
0fb67cd1
VZ
1281 wxDocTemplate *theTemplate = (wxDocTemplate *)wxGetSingleChoiceData(_("Select a document view"), _("Views"), n,
1282 strings, data);
1283 delete[] strings;
1284 delete[] data;
1285 return theTemplate;
c801d85f
KB
1286}
1287
1288void wxDocManager::AssociateTemplate(wxDocTemplate *temp)
1289{
0fb67cd1
VZ
1290 if (!m_templates.Member(temp))
1291 m_templates.Append(temp);
c801d85f
KB
1292}
1293
1294void wxDocManager::DisassociateTemplate(wxDocTemplate *temp)
1295{
0fb67cd1 1296 m_templates.DeleteObject(temp);
c801d85f
KB
1297}
1298
1299// Add and remove a document from the manager's list
1300void wxDocManager::AddDocument(wxDocument *doc)
1301{
0fb67cd1
VZ
1302 if (!m_docs.Member(doc))
1303 m_docs.Append(doc);
c801d85f
KB
1304}
1305
1306void wxDocManager::RemoveDocument(wxDocument *doc)
1307{
0fb67cd1 1308 m_docs.DeleteObject(doc);
c801d85f
KB
1309}
1310
1311// Views or windows should inform the document manager
1312// when a view is going in or out of focus
1313void wxDocManager::ActivateView(wxView *view, bool activate, bool WXUNUSED(deleting))
1314{
0fb67cd1
VZ
1315 // If we're deactiving, and if we're not actually deleting the view, then
1316 // don't reset the current view because we may be going to
1317 // a window without a view.
1318 // WHAT DID I MEAN BY THAT EXACTLY?
1319 /*
1320 if (deleting)
1321 {
1322 if (m_currentView == view)
1323 m_currentView = NULL;
1324 }
1325 else
1326 */
1327 {
1328 if (activate)
1329 m_currentView = view;
1330 else
1331 m_currentView = (wxView *) NULL;
1332 }
c801d85f
KB
1333}
1334
0fb67cd1
VZ
1335// ----------------------------------------------------------------------------
1336// Default document child frame
1337// ----------------------------------------------------------------------------
c801d85f
KB
1338
1339BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame)
1340 EVT_ACTIVATE(wxDocChildFrame::OnActivate)
387a3b02 1341 EVT_CLOSE(wxDocChildFrame::OnCloseWindow)
c801d85f
KB
1342END_EVENT_TABLE()
1343
0fb67cd1
VZ
1344wxDocChildFrame::wxDocChildFrame(wxDocument *doc,
1345 wxView *view,
1346 wxFrame *frame,
1347 wxWindowID id,
1348 const wxString& title,
1349 const wxPoint& pos,
1350 const wxSize& size,
1351 long style,
1352 const wxString& name)
1353 : wxFrame(frame, id, title, pos, size, style, name)
1354{
1355 m_childDocument = doc;
1356 m_childView = view;
1357 if (view)
1358 view->SetFrame(this);
c801d85f
KB
1359}
1360
0fb67cd1 1361wxDocChildFrame::~wxDocChildFrame()
c801d85f
KB
1362{
1363}
1364
1365// Extend event processing to search the view's event table
1366bool wxDocChildFrame::ProcessEvent(wxEvent& event)
1367{
1368 if (m_childView)
1369 m_childView->Activate(TRUE);
1370
0fb67cd1 1371 if ( !m_childView || ! m_childView->ProcessEvent(event) )
c801d85f
KB
1372 {
1373 // Only hand up to the parent if it's a menu command
1374 if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event))
0fb67cd1 1375 return wxEvtHandler::ProcessEvent(event);
c801d85f
KB
1376 else
1377 return TRUE;
1378 }
0fb67cd1
VZ
1379 else
1380 return TRUE;
c801d85f
KB
1381}
1382
c801d85f
KB
1383void wxDocChildFrame::OnActivate(wxActivateEvent& event)
1384{
0fb67cd1 1385 wxFrame::OnActivate(event);
c801d85f 1386
0fb67cd1
VZ
1387 if (m_childView)
1388 m_childView->Activate(event.GetActive());
c801d85f
KB
1389}
1390
387a3b02 1391void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event)
c801d85f 1392{
0fb67cd1 1393 if (m_childView)
c801d85f 1394 {
0fb67cd1
VZ
1395 bool ans = FALSE;
1396 if (!event.CanVeto())
1397 ans = TRUE; // Must delete.
1398 else
1399 ans = m_childView->Close(FALSE); // FALSE means don't delete associated window
387a3b02 1400
0fb67cd1
VZ
1401 if (ans)
1402 {
1403 m_childView->Activate(FALSE);
1404 delete m_childView;
1405 m_childView = (wxView *) NULL;
1406 m_childDocument = (wxDocument *) NULL;
1407
1408 this->Destroy();
1409 }
1410 else
1411 event.Veto();
c801d85f 1412 }
387a3b02 1413 else
0fb67cd1 1414 event.Veto();
c801d85f
KB
1415}
1416
0fb67cd1
VZ
1417// ----------------------------------------------------------------------------
1418// Default parent frame
1419// ----------------------------------------------------------------------------
c801d85f
KB
1420
1421BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame)
1422 EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit)
f7bd2698 1423 EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile)
387a3b02 1424 EVT_CLOSE(wxDocParentFrame::OnCloseWindow)
c801d85f
KB
1425END_EVENT_TABLE()
1426
0fb67cd1
VZ
1427wxDocParentFrame::wxDocParentFrame(wxDocManager *manager,
1428 wxFrame *frame,
1429 wxWindowID id,
1430 const wxString& title,
1431 const wxPoint& pos,
1432 const wxSize& size,
1433 long style,
1434 const wxString& name)
1435 : wxFrame(frame, id, title, pos, size, style, name)
c801d85f 1436{
0fb67cd1 1437 m_docManager = manager;
c801d85f
KB
1438}
1439
1440void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event))
1441{
1442 Close();
1443}
1444
1445void wxDocParentFrame::OnMRUFile(wxCommandEvent& event)
1446{
0fb67cd1
VZ
1447 wxString f(m_docManager->GetHistoryFile(event.GetSelection() - wxID_FILE1));
1448 if (f != "")
c801d85f
KB
1449 (void)m_docManager->CreateDocument(f, wxDOC_SILENT);
1450}
1451
1452// Extend event processing to search the view's event table
1453bool wxDocParentFrame::ProcessEvent(wxEvent& event)
1454{
1455 // Try the document manager, then do default processing
1456 if (!m_docManager || !m_docManager->ProcessEvent(event))
1457 return wxEvtHandler::ProcessEvent(event);
1458 else
1459 return TRUE;
1460}
1461
c801d85f
KB
1462// Define the behaviour for the frame closing
1463// - must delete all frames except for the main one.
387a3b02 1464void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event)
c801d85f 1465{
0fb67cd1
VZ
1466 if (m_docManager->Clear(!event.CanVeto()))
1467 {
1468 this->Destroy();
1469 }
1470 else
1471 event.Veto();
c801d85f
KB
1472}
1473
47d67540 1474#if wxUSE_PRINTING_ARCHITECTURE
c801d85f 1475
0fb67cd1
VZ
1476wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title)
1477 : wxPrintout(WXSTRINGCAST title)
c801d85f 1478{
0fb67cd1 1479 m_printoutView = view;
c801d85f
KB
1480}
1481
1482bool wxDocPrintout::OnPrintPage(int WXUNUSED(page))
1483{
0fb67cd1
VZ
1484 wxDC *dc = GetDC();
1485
1486 // Get the logical pixels per inch of screen and printer
1487 int ppiScreenX, ppiScreenY;
1488 GetPPIScreen(&ppiScreenX, &ppiScreenY);
1489 int ppiPrinterX, ppiPrinterY;
1490 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
1491
1492 // This scales the DC so that the printout roughly represents the
1493 // the screen scaling. The text point size _should_ be the right size
1494 // but in fact is too small for some reason. This is a detail that will
1495 // need to be addressed at some point but can be fudged for the
1496 // moment.
1497 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
1498
1499 // Now we have to check in case our real page size is reduced
1500 // (e.g. because we're drawing to a print preview memory DC)
1501 int pageWidth, pageHeight;
1502 int w, h;
1503 dc->GetSize(&w, &h);
1504 GetPageSizePixels(&pageWidth, &pageHeight);
1505
1506 // If printer pageWidth == current DC width, then this doesn't
1507 // change. But w might be the preview bitmap width, so scale down.
1508 float overallScale = scale * (float)(w/(float)pageWidth);
1509 dc->SetUserScale(overallScale, overallScale);
1510
1511 if (m_printoutView)
1512 {
1513 m_printoutView->OnDraw(dc);
1514 }
1515 return TRUE;
c801d85f
KB
1516}
1517
1518bool wxDocPrintout::HasPage(int pageNum)
1519{
0fb67cd1 1520 return (pageNum == 1);
c801d85f
KB
1521}
1522
1523bool wxDocPrintout::OnBeginDocument(int startPage, int endPage)
1524{
0fb67cd1
VZ
1525 if (!wxPrintout::OnBeginDocument(startPage, endPage))
1526 return FALSE;
c801d85f 1527
0fb67cd1 1528 return TRUE;
c801d85f
KB
1529}
1530
1531void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
1532{
0fb67cd1
VZ
1533 *minPage = 1;
1534 *maxPage = 1;
1535 *selPageFrom = 1;
1536 *selPageTo = 1;
c801d85f
KB
1537}
1538
0fb67cd1 1539#endif // wxUSE_PRINTING_ARCHITECTURE
c801d85f 1540
0fb67cd1
VZ
1541// ----------------------------------------------------------------------------
1542// Command processing framework
1543// ----------------------------------------------------------------------------
c801d85f
KB
1544
1545wxCommand::wxCommand(bool canUndoIt, const wxString& name)
1546{
0fb67cd1
VZ
1547 m_canUndo = canUndoIt;
1548 m_commandName = name;
c801d85f
KB
1549}
1550
0fb67cd1 1551wxCommand::~wxCommand()
c801d85f
KB
1552{
1553}
1554
1555// Command processor
1556wxCommandProcessor::wxCommandProcessor(int maxCommands)
1557{
0fb67cd1
VZ
1558 m_maxNoCommands = maxCommands;
1559 m_currentCommand = (wxNode *) NULL;
1560 m_commandEditMenu = (wxMenu *) NULL;
c801d85f
KB
1561}
1562
0fb67cd1 1563wxCommandProcessor::~wxCommandProcessor()
c801d85f 1564{
0fb67cd1 1565 ClearCommands();
c801d85f
KB
1566}
1567
1568// Pass a command to the processor. The processor calls Do();
1569// if successful, is appended to the command history unless
1570// storeIt is FALSE.
1571bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt)
1572{
0fb67cd1
VZ
1573 bool success = command->Do();
1574 if (success && storeIt)
c801d85f 1575 {
0fb67cd1
VZ
1576 if (m_commands.Number() == m_maxNoCommands)
1577 {
1578 wxNode *firstNode = m_commands.First();
1579 wxCommand *firstCommand = (wxCommand *)firstNode->Data();
1580 delete firstCommand;
1581 delete firstNode;
1582 }
c801d85f 1583
0fb67cd1
VZ
1584 // Correct a bug: we must chop off the current 'branch'
1585 // so that we're at the end of the command list.
1586 if (!m_currentCommand)
1587 ClearCommands();
1588 else
1589 {
1590 wxNode *node = m_currentCommand->Next();
1591 while (node)
1592 {
1593 wxNode *next = node->Next();
1594 delete (wxCommand *)node->Data();
1595 delete node;
1596 node = next;
1597 }
1598 }
1599
1600 m_commands.Append(command);
1601 m_currentCommand = m_commands.Last();
1602 SetMenuStrings();
c801d85f 1603 }
0fb67cd1 1604 return success;
c801d85f
KB
1605}
1606
0fb67cd1 1607bool wxCommandProcessor::Undo()
c801d85f 1608{
0fb67cd1 1609 if (m_currentCommand)
c801d85f 1610 {
0fb67cd1
VZ
1611 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1612 if (command->CanUndo())
1613 {
1614 bool success = command->Undo();
1615 if (success)
1616 {
1617 m_currentCommand = m_currentCommand->Previous();
1618 SetMenuStrings();
1619 return TRUE;
1620 }
1621 }
c801d85f 1622 }
0fb67cd1 1623 return FALSE;
c801d85f
KB
1624}
1625
0fb67cd1 1626bool wxCommandProcessor::Redo()
c801d85f 1627{
0fb67cd1
VZ
1628 wxCommand *redoCommand = (wxCommand *) NULL;
1629 wxNode *redoNode = (wxNode *) NULL;
1630 if (m_currentCommand && m_currentCommand->Next())
1631 {
1632 redoCommand = (wxCommand *)m_currentCommand->Next()->Data();
1633 redoNode = m_currentCommand->Next();
1634 }
1635 else
c801d85f 1636 {
0fb67cd1
VZ
1637 if (m_commands.Number() > 0)
1638 {
1639 redoCommand = (wxCommand *)m_commands.First()->Data();
1640 redoNode = m_commands.First();
1641 }
c801d85f 1642 }
c801d85f 1643
0fb67cd1 1644 if (redoCommand)
c801d85f 1645 {
0fb67cd1
VZ
1646 bool success = redoCommand->Do();
1647 if (success)
1648 {
1649 m_currentCommand = redoNode;
1650 SetMenuStrings();
1651 return TRUE;
1652 }
c801d85f 1653 }
0fb67cd1 1654 return FALSE;
c801d85f
KB
1655}
1656
7f555861 1657bool wxCommandProcessor::CanUndo(void) const
c801d85f 1658{
0fb67cd1
VZ
1659 if (m_currentCommand)
1660 return ((wxCommand *)m_currentCommand->Data())->CanUndo();
1661 return FALSE;
c801d85f
KB
1662}
1663
7f555861
JS
1664bool wxCommandProcessor::CanRedo(void) const
1665{
f97c9854
JS
1666 if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() == (wxNode*) NULL))
1667 return FALSE;
1668
1669 if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() != (wxNode*) NULL))
1670 return TRUE;
1671
1672 if ((m_currentCommand == (wxNode*) NULL) && (m_commands.Number() > 0))
1673 return TRUE;
1674
1675 return FALSE;
7f555861
JS
1676}
1677
0fb67cd1 1678void wxCommandProcessor::Initialize()
c801d85f 1679{
0fb67cd1
VZ
1680 m_currentCommand = m_commands.Last();
1681 SetMenuStrings();
c801d85f
KB
1682}
1683
0fb67cd1 1684void wxCommandProcessor::SetMenuStrings()
c801d85f 1685{
0fb67cd1 1686 if (m_commandEditMenu)
c801d85f 1687 {
0fb67cd1
VZ
1688 wxString buf;
1689 if (m_currentCommand)
1690 {
1691 wxCommand *command = (wxCommand *)m_currentCommand->Data();
1692 wxString commandName(command->GetName());
1693 if (commandName == "") commandName = _("Unnamed command");
1694 bool canUndo = command->CanUndo();
1695 if (canUndo)
1696 buf = wxString(_("&Undo ")) + commandName;
1697 else
1698 buf = wxString(_("Can't &Undo ")) + commandName;
1699
1700 m_commandEditMenu->SetLabel(wxID_UNDO, buf);
1701 m_commandEditMenu->Enable(wxID_UNDO, canUndo);
1702
1703 // We can redo, if we're not at the end of the history.
1704 if (m_currentCommand->Next())
1705 {
1706 wxCommand *redoCommand = (wxCommand *)m_currentCommand->Next()->Data();
1707 wxString redoCommandName(redoCommand->GetName());
1708 if (redoCommandName == "") redoCommandName = _("Unnamed command");
1709 buf = wxString(_("&Redo ")) + redoCommandName;
1710 m_commandEditMenu->SetLabel(wxID_REDO, buf);
1711 m_commandEditMenu->Enable(wxID_REDO, TRUE);
1712 }
1713 else
1714 {
1715 m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo"));
1716 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1717 }
1718 }
1719 else
1720 {
1721 m_commandEditMenu->SetLabel(wxID_UNDO, _("&Undo"));
1722 m_commandEditMenu->Enable(wxID_UNDO, FALSE);
c801d85f 1723
0fb67cd1
VZ
1724 if (m_commands.Number() == 0)
1725 {
1726 m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo"));
1727 m_commandEditMenu->Enable(wxID_REDO, FALSE);
1728 }
1729 else
1730 {
1731 // currentCommand is NULL but there are commands: this means that
1732 // we've undone to the start of the list, but can redo the first.
1733 wxCommand *redoCommand = (wxCommand *)m_commands.First()->Data();
1734 wxString redoCommandName(redoCommand->GetName());
1735 if (redoCommandName == "") redoCommandName = _("Unnamed command");
1736 buf = wxString(_("&Redo ")) + redoCommandName;
1737 m_commandEditMenu->SetLabel(wxID_REDO, buf);
1738 m_commandEditMenu->Enable(wxID_REDO, TRUE);
1739 }
1740 }
c801d85f 1741 }
c801d85f
KB
1742}
1743
0fb67cd1 1744void wxCommandProcessor::ClearCommands()
c801d85f 1745{
0fb67cd1
VZ
1746 wxNode *node = m_commands.First();
1747 while (node)
1748 {
1749 wxCommand *command = (wxCommand *)node->Data();
1750 delete command;
1751 delete node;
1752 node = m_commands.First();
1753 }
1754 m_currentCommand = (wxNode *) NULL;
c801d85f
KB
1755}
1756
0fb67cd1
VZ
1757// ----------------------------------------------------------------------------
1758// File history processor
1759// ----------------------------------------------------------------------------
c801d85f
KB
1760
1761wxFileHistory::wxFileHistory(int maxFiles)
1762{
0fb67cd1
VZ
1763 m_fileMaxFiles = maxFiles;
1764 m_fileHistoryN = 0;
50920146 1765 m_fileHistory = new wxChar *[m_fileMaxFiles];
c801d85f
KB
1766}
1767
0fb67cd1 1768wxFileHistory::~wxFileHistory()
c801d85f 1769{
0fb67cd1
VZ
1770 int i;
1771 for (i = 0; i < m_fileHistoryN; i++)
1772 delete[] m_fileHistory[i];
1773 delete[] m_fileHistory;
c801d85f
KB
1774}
1775
1776// File history management
1777void wxFileHistory::AddFileToHistory(const wxString& file)
1778{
0fb67cd1
VZ
1779 int i;
1780 // Check we don't already have this file
1781 for (i = 0; i < m_fileHistoryN; i++)
7f555861 1782 {
0fb67cd1
VZ
1783 if (m_fileHistory[i] && wxString(m_fileHistory[i]) == file)
1784 return;
7f555861 1785 }
0fb67cd1
VZ
1786
1787 // Add to the project file history:
1788 // Move existing files (if any) down so we can insert file at beginning.
1789
1790 // First delete filename that has popped off the end of the array (if any)
1791 if (m_fileHistoryN == m_fileMaxFiles)
1792 {
1793 delete[] m_fileHistory[m_fileMaxFiles-1];
50920146 1794 m_fileHistory[m_fileMaxFiles-1] = (wxChar *) NULL;
c801d85f 1795 }
0fb67cd1
VZ
1796 if (m_fileHistoryN < m_fileMaxFiles)
1797 {
1798 wxNode* node = m_fileMenus.First();
1799 while (node)
1800 {
1801 wxMenu* menu = (wxMenu*) node->Data();
1802 if (m_fileHistoryN == 0)
1803 menu->AppendSeparator();
1804 menu->Append(wxID_FILE1+m_fileHistoryN, _("[EMPTY]"));
1805 node = node->Next();
1806 }
1807 m_fileHistoryN ++;
1808 }
1809 // Shuffle filenames down
1810 for (i = (m_fileHistoryN-1); i > 0; i--)
1811 {
1812 m_fileHistory[i] = m_fileHistory[i-1];
1813 }
1814 m_fileHistory[0] = copystring(file);
1815
1816 for (i = 0; i < m_fileHistoryN; i++)
1817 if (m_fileHistory[i])
1818 {
1819 wxString buf;
50920146 1820 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
0fb67cd1
VZ
1821 wxNode* node = m_fileMenus.First();
1822 while (node)
1823 {
1824 wxMenu* menu = (wxMenu*) node->Data();
1825 menu->SetLabel(wxID_FILE1+i, buf);
1826 node = node->Next();
1827 }
1828 }
c801d85f
KB
1829}
1830
1831wxString wxFileHistory::GetHistoryFile(int i) const
1832{
0fb67cd1
VZ
1833 if (i < m_fileHistoryN)
1834 return wxString(m_fileHistory[i]);
1835 else
1836 return wxString("");
c801d85f
KB
1837}
1838
7f555861 1839void wxFileHistory::UseMenu(wxMenu *menu)
c801d85f 1840{
0fb67cd1
VZ
1841 if (!m_fileMenus.Member(menu))
1842 m_fileMenus.Append(menu);
c801d85f
KB
1843}
1844
7f555861
JS
1845void wxFileHistory::RemoveMenu(wxMenu *menu)
1846{
0fb67cd1 1847 m_fileMenus.DeleteObject(menu);
7f555861
JS
1848}
1849
702ca7c0 1850#if wxUSE_CONFIG
7f555861 1851void wxFileHistory::Load(wxConfigBase& config)
c801d85f 1852{
0fb67cd1
VZ
1853 m_fileHistoryN = 0;
1854 wxString buf;
50920146 1855 buf.Printf(_T("file%d"), m_fileHistoryN+1);
0fb67cd1
VZ
1856 wxString historyFile;
1857 while ((m_fileHistoryN <= m_fileMaxFiles) && config.Read(buf, &historyFile) && (historyFile != ""))
1858 {
50920146 1859 m_fileHistory[m_fileHistoryN] = copystring((const wxChar*) historyFile);
0fb67cd1 1860 m_fileHistoryN ++;
50920146 1861 buf.Printf(_T("file%d"), m_fileHistoryN+1);
0fb67cd1
VZ
1862 historyFile = "";
1863 }
1864 AddFilesToMenu();
c801d85f
KB
1865}
1866
7f555861 1867void wxFileHistory::Save(wxConfigBase& config)
c801d85f 1868{
0fb67cd1
VZ
1869 int i;
1870 for (i = 0; i < m_fileHistoryN; i++)
1871 {
1872 wxString buf;
50920146 1873 buf.Printf(_T("file%d"), i+1);
0fb67cd1
VZ
1874 config.Write(buf, wxString(m_fileHistory[i]));
1875 }
7f555861 1876}
0fb67cd1 1877#endif // wxUSE_CONFIG
7f555861
JS
1878
1879void wxFileHistory::AddFilesToMenu()
1880{
1881 if (m_fileHistoryN > 0)
1882 {
1883 wxNode* node = m_fileMenus.First();
1884 while (node)
1885 {
1886 wxMenu* menu = (wxMenu*) node->Data();
1887 menu->AppendSeparator();
1888 int i;
1889 for (i = 0; i < m_fileHistoryN; i++)
1890 {
1891 if (m_fileHistory[i])
1892 {
1893 wxString buf;
50920146 1894 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
7f555861
JS
1895 menu->Append(wxID_FILE1+i, buf);
1896 }
1897 }
1898 node = node->Next();
1899 }
1900 }
1901}
1902
1903void wxFileHistory::AddFilesToMenu(wxMenu* menu)
1904{
1905 if (m_fileHistoryN > 0)
1906 {
1907 menu->AppendSeparator();
1908 int i;
1909 for (i = 0; i < m_fileHistoryN; i++)
1910 {
1911 if (m_fileHistory[i])
1912 {
1913 wxString buf;
50920146 1914 buf.Printf(_T("&%d %s"), i+1, m_fileHistory[i]);
7f555861
JS
1915 menu->Append(wxID_FILE1+i, buf);
1916 }
1917 }
1918 }
c801d85f
KB
1919}
1920
0fb67cd1
VZ
1921// ----------------------------------------------------------------------------
1922// Permits compatibility with existing file formats and functions that
1923// manipulate files directly
1924// ----------------------------------------------------------------------------
c801d85f 1925
c801d85f
KB
1926bool wxTransferFileToStream(const wxString& filename, ostream& stream)
1927{
0fb67cd1
VZ
1928 FILE *fd1;
1929 int ch;
c801d85f 1930
50920146 1931 if ((fd1 = fopen (filename.fn_str(), "rb")) == NULL)
0fb67cd1 1932 return FALSE;
c801d85f 1933
0fb67cd1
VZ
1934 while ((ch = getc (fd1)) != EOF)
1935 stream << (unsigned char)ch;
c801d85f 1936
0fb67cd1
VZ
1937 fclose (fd1);
1938 return TRUE;
c801d85f
KB
1939}
1940
1941bool wxTransferStreamToFile(istream& stream, const wxString& filename)
1942{
0fb67cd1
VZ
1943 FILE *fd1;
1944 int ch;
c801d85f 1945
50920146 1946 if ((fd1 = fopen (filename.fn_str(), "wb")) == NULL)
c801d85f 1947 {
0fb67cd1 1948 return FALSE;
c801d85f
KB
1949 }
1950
0fb67cd1
VZ
1951 while (!stream.eof())
1952 {
1953 ch = stream.get();
1954 if (!stream.eof())
1955 putc (ch, fd1);
1956 }
1957 fclose (fd1);
1958 return TRUE;
c801d85f
KB
1959}
1960
0fb67cd1
VZ
1961#endif // wxUSE_DOC_VIEW_ARCHITECTURE
1962