]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/docview/docview.cpp
Support using GetTextExtent() with empty string to get descent in wxOSX.
[wxWidgets.git] / samples / docview / docview.cpp
index 53699369c12304a9627f27f813998cf808482ee6..c8d4adcf7368e737efbdcbae27e2f1e24bc85836 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
-// Name:        docview.cpp
+// Name:        samples/docview/docview.cpp
 // Purpose:     Document/view demo
 // Author:      Julian Smart
 // Purpose:     Document/view demo
 // Author:      Julian Smart
-// Modified by:
+// Modified by: Vadim Zeitlin: merge with the MDI version and general cleanup
 // Created:     04/01/98
 // RCS-ID:      $Id$
 // Created:     04/01/98
 // RCS-ID:      $Id$
-// Copyright:   (c) Julian Smart and Markus Holzem
-// Licence:    wxWindows license
+// Copyright:   (c) 1998 Julian Smart
+//              (c) 2008 Vadim Zeitlin
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
-// #pragma implementation "docview.h"
-#endif
-
 /*
 /*
- * Purpose:  Document/view architecture demo for wxWindows class library
- *           Run with no arguments for multiple top-level windows, -single
- *           for a single window.
+    This sample show document/view support in wxWidgets.
+
+    It can be run in several ways:
+        * With "--mdi" command line option to use multiple MDI child frames
+          for the multiple documents (this is the default).
+        * With "--sdi" command line option to use multiple top level windows
+          for the multiple documents
+        * With "--single" command line option to support opening a single
+          document only
+
+    Notice that doing it like this somewhat complicates the code, you could
+    make things much simpler in your own programs by using either
+    wxDocParentFrame or wxDocMDIParentFrame unconditionally (and never using
+    the single mode) instead of supporting all of them as this sample does.
  */
 
  */
 
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
 
 // For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
 
 // For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#pragma hdrstop
+    #pragma hdrstop
 #endif
 
 #ifndef WX_PRECOMP
 #endif
 
 #ifndef WX_PRECOMP
-#include "wx/wx.h"
+    #include "wx/wx.h"
+    #include "wx/stockitem.h"
 #endif
 
 #if !wxUSE_DOC_VIEW_ARCHITECTURE
 #endif
 
 #if !wxUSE_DOC_VIEW_ARCHITECTURE
-#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
+    #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
 #endif
 
 #include "wx/docview.h"
 #endif
 
 #include "wx/docview.h"
+#include "wx/docmdi.h"
 
 #include "docview.h"
 #include "doc.h"
 #include "view.h"
 
 
 #include "docview.h"
 #include "doc.h"
 #include "view.h"
 
-MyFrame *frame = (MyFrame *) NULL;
+#include "wx/cmdline.h"
+#include "wx/config.h"
+
+#ifdef __WXMAC__
+    #include "wx/filename.h"
+#endif
+
+#ifndef wxHAS_IMAGES_IN_RESOURCES
+    #include "doc.xpm"
+    #include "chart.xpm"
+    #include "notepad.xpm"
+#endif
 
 
-// In single window mode, don't have any child windows; use
-// main window.
-bool singleWindowMode = FALSE;
+// ----------------------------------------------------------------------------
+// MyApp implementation
+// ----------------------------------------------------------------------------
 
 IMPLEMENT_APP(MyApp)
 
 
 IMPLEMENT_APP(MyApp)
 
-MyApp::MyApp(void)
+BEGIN_EVENT_TABLE(MyApp, wxApp)
+    EVT_MENU(wxID_ABOUT, MyApp::OnAbout)
+END_EVENT_TABLE()
+
+MyApp::MyApp()
 {
 {
-    m_docManager = (wxDocManager *) NULL;
+#if wxUSE_MDI_ARCHITECTURE
+    m_mode = Mode_MDI;
+#else
+    m_mode = Mode_SDI;
+#endif
+
+    m_canvas = NULL;
+    m_menuEdit = NULL;
 }
 
 }
 
-bool MyApp::OnInit(void)
+// constants for the command line options names
+namespace CmdLineOption
 {
 {
-  //// Find out if we're:
-  ////  SDI : multiple windows and documents but not MDI
-  ////  MDI : multiple windows and documents with containing frame - MSW only)
-  ///   single window : (one document at a time, only one frame, as in Windows Write)
-  if (argc > 1)
-  {
-    if (strcmp(argv[1], "-single") == 0)
-    {
-      singleWindowMode = TRUE;
-    }
-  }
-
-  //// Create a document manager
-  m_docManager = new wxDocManager;
-
-  //// Create a template relating drawing documents to their views
-  (void) new wxDocTemplate(m_docManager, "Drawing", "*.drw", "", "drw", "Drawing Doc", "Drawing View",
-          CLASSINFO(DrawingDocument), CLASSINFO(DrawingView));
-
-  if (singleWindowMode)
-  {
-    // If we've only got one window, we only get to edit
-    // one document at a time. Therefore no text editing, just
-    // doodling.
-    m_docManager->SetMaxDocsOpen(1);
-  }
-  else
-    //// Create a template relating text documents to their views
-    (void) new wxDocTemplate(m_docManager, "Text", "*.txt", "", "txt", "Text Doc", "Text View",
-          CLASSINFO(TextEditDocument), CLASSINFO(TextEditView));
-
-  //// Create the main frame window
-  frame = new MyFrame(m_docManager, (wxFrame *) NULL, -1, "DocView Demo", wxPoint(0, 0), wxSize(500, 400), wxDEFAULT_FRAME_STYLE);
-
-  //// Give it an icon (this is ignored in MDI mode: uses resources)
-#ifdef __WXMSW__
-  frame->SetIcon(wxIcon("doc_icn"));
-#endif
 
 
-  //// Make a menubar
-  wxMenu *file_menu = new wxMenu;
-  wxMenu *edit_menu = (wxMenu *) NULL;
-
-  file_menu->Append(wxID_NEW, "&New...");
-  file_menu->Append(wxID_OPEN, "&Open...");
-
-  if (singleWindowMode)
-  {
-    file_menu->Append(wxID_CLOSE, "&Close");
-    file_menu->Append(wxID_SAVE, "&Save");
-    file_menu->Append(wxID_SAVEAS, "Save &As...");
-    file_menu->AppendSeparator();
-    file_menu->Append(wxID_PRINT, "&Print...");
-    file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
-    file_menu->Append(wxID_PREVIEW, "Print Pre&view");
-
-    edit_menu = new wxMenu;
-    edit_menu->Append(wxID_UNDO, "&Undo");
-    edit_menu->Append(wxID_REDO, "&Redo");
-    edit_menu->AppendSeparator();
-    edit_menu->Append(DOCVIEW_CUT, "&Cut last segment");
-
-    frame->editMenu = edit_menu;
-  }
-  
-  file_menu->AppendSeparator();
-  file_menu->Append(wxID_EXIT, "E&xit");
-  
-  // A nice touch: a history of files visited. Use this menu.
-  m_docManager->FileHistoryUseMenu(file_menu);
-
-  wxMenu *help_menu = new wxMenu;
-  help_menu->Append(DOCVIEW_ABOUT, "&About");
-
-  wxMenuBar *menu_bar = new wxMenuBar;
-
-  menu_bar->Append(file_menu, "&File");
-  if (edit_menu)
-    menu_bar->Append(edit_menu, "&Edit");
-  menu_bar->Append(help_menu, "&Help");
-
-  if (singleWindowMode)
-    frame->canvas = frame->CreateCanvas((wxView *) NULL, frame);
-
-  //// Associate the menu bar with the frame
-  frame->SetMenuBar(menu_bar);
-
-  frame->Centre(wxBOTH);
-  frame->Show(TRUE);
-
-  SetTopWindow(frame);
-  return TRUE;
+const char * const MDI = "mdi";
+const char * const SDI = "sdi";
+const char * const SINGLE = "single";
+
+} // namespace CmdLineOption
+
+void MyApp::OnInitCmdLine(wxCmdLineParser& parser)
+{
+    wxApp::OnInitCmdLine(parser);
+
+    parser.AddSwitch("", CmdLineOption::MDI,
+                     "run in MDI mode: multiple documents, single window");
+    parser.AddSwitch("", CmdLineOption::SDI,
+                     "run in SDI mode: multiple documents, multiple windows");
+    parser.AddSwitch("", CmdLineOption::SINGLE,
+                     "run in single document mode");
 }
 
 }
 
-int MyApp::OnExit(void)
+bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser)
 {
 {
-    delete m_docManager;
-    return 0;
+    int numModeOptions = 0;
+
+#if wxUSE_MDI_ARCHITECTURE
+    if ( parser.Found(CmdLineOption::MDI) )
+    {
+        m_mode = Mode_MDI;
+        numModeOptions++;
+    }
+#endif // wxUSE_MDI_ARCHITECTURE
+
+    if ( parser.Found(CmdLineOption::SDI) )
+    {
+        m_mode = Mode_SDI;
+        numModeOptions++;
+    }
+
+    if ( parser.Found(CmdLineOption::SINGLE) )
+    {
+        m_mode = Mode_Single;
+        numModeOptions++;
+    }
+
+    if ( numModeOptions > 1 )
+    {
+        wxLogError("Only a single option choosing the mode can be given.");
+        return false;
+    }
+
+    return wxApp::OnCmdLineParsed(parser);
 }
 
 }
 
-/*
- * Centralised code for creating a document frame.
- * Called from view.cpp, when a view is created, but not used at all
- * in 'single window' mode.
- */
-wxFrame *MyApp::CreateChildFrame(wxDocument *doc, wxView *view, bool isCanvas)
+bool MyApp::OnInit()
 {
 {
-  //// Make a child frame
-  wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, GetMainFrame(), -1, "Child Frame",
-        wxPoint(10, 10), wxSize(300, 300), wxDEFAULT_FRAME_STYLE);
+    if ( !wxApp::OnInit() )
+        return false;
+
+    ::wxInitAllImageHandlers();
+
+    // Fill in the application information fields before creating wxConfig.
+    SetVendorName("wxWidgets");
+    SetAppName("wx_docview_sample");
+    SetAppDisplayName("wxWidgets DocView Sample");
 
 
-#ifdef __WXMSW__
-  subframe->SetIcon(wxString(isCanvas ? "chrt_icn" : "notepad_icn"));
+    //// Create a document manager
+    wxDocManager *docManager = new wxDocManager;
+
+    //// Create a template relating drawing documents to their views
+    new wxDocTemplate(docManager, "Drawing", "*.drw", "", "drw",
+                      "Drawing Doc", "Drawing View",
+                      CLASSINFO(DrawingDocument), CLASSINFO(DrawingView));
+#if defined( __WXMAC__ )  && wxOSX_USE_CARBON
+    wxFileName::MacRegisterDefaultTypeAndCreator("drw" , 'WXMB' , 'WXMA');
 #endif
 
 #endif
 
-  //// Make a menubar
-  wxMenu *file_menu = new wxMenu;
+    if ( m_mode == Mode_Single )
+    {
+        // If we've only got one window, we only get to edit one document at a
+        // time. Therefore no text editing, just doodling.
+        docManager->SetMaxDocsOpen(1);
+    }
+    else // multiple documents mode: allow documents of different types
+    {
+        // Create a template relating text documents to their views
+        new wxDocTemplate(docManager, "Text", "*.txt;*.text", "", "txt;text",
+                          "Text Doc", "Text View",
+                          CLASSINFO(TextEditDocument), CLASSINFO(TextEditView));
+#if defined( __WXMAC__ ) && wxOSX_USE_CARBON
+        wxFileName::MacRegisterDefaultTypeAndCreator("txt" , 'TEXT' , 'WXMA');
+#endif
+        // Create a template relating image documents to their views
+        new wxDocTemplate(docManager, "Image", "*.png;*.jpg", "", "png;jpg",
+                          "Image Doc", "Image View",
+                          CLASSINFO(ImageDocument), CLASSINFO(ImageView));
+    }
 
 
-  file_menu->Append(wxID_NEW, "&New...");
-  file_menu->Append(wxID_OPEN, "&Open...");
-  file_menu->Append(wxID_CLOSE, "&Close");
-  file_menu->Append(wxID_SAVE, "&Save");
-  file_menu->Append(wxID_SAVEAS, "Save &As...");
+    // create the main frame window
+    wxFrame *frame;
+#if wxUSE_MDI_ARCHITECTURE
+    if ( m_mode == Mode_MDI )
+    {
+        frame = new wxDocMDIParentFrame(docManager, NULL, wxID_ANY,
+                                        GetAppDisplayName(),
+                                        wxDefaultPosition,
+                                        wxSize(500, 400));
+    }
+    else
+#endif // wxUSE_MDI_ARCHITECTURE
+    {
+        frame = new wxDocParentFrame(docManager, NULL, wxID_ANY,
+                                     GetAppDisplayName(),
+                                     wxDefaultPosition,
+                                     wxSize(500, 400));
+    }
 
 
-  if (isCanvas)
-  {
-    file_menu->AppendSeparator();
-    file_menu->Append(wxID_PRINT, "&Print...");
-    file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
-    file_menu->Append(wxID_PREVIEW, "Print Pre&view");
-  }
+    // and its menu bar
+    wxMenu *menuFile = new wxMenu;
 
 
-  wxMenu *edit_menu = (wxMenu *) NULL;
+    menuFile->Append(wxID_NEW);
+    menuFile->Append(wxID_OPEN);
 
 
-  if (isCanvas)
-  {
-    edit_menu = new wxMenu;
-    edit_menu->Append(wxID_UNDO, "&Undo");
-    edit_menu->Append(wxID_REDO, "&Redo");
-    edit_menu->AppendSeparator();
-    edit_menu->Append(DOCVIEW_CUT, "&Cut last segment");
+    if ( m_mode == Mode_Single )
+        AppendDocumentFileCommands(menuFile, true);
 
 
-    doc->GetCommandProcessor()->SetEditMenu(edit_menu);
-  }
+    menuFile->AppendSeparator();
+    menuFile->Append(wxID_EXIT);
 
 
-  wxMenu *help_menu = new wxMenu;
-  help_menu->Append(DOCVIEW_ABOUT, "&About");
+    // A nice touch: a history of files visited. Use this menu.
+    docManager->FileHistoryUseMenu(menuFile);
+#if wxUSE_CONFIG
+    docManager->FileHistoryLoad(*wxConfig::Get());
+#endif // wxUSE_CONFIG
 
 
-  wxMenuBar *menu_bar = new wxMenuBar;
 
 
-  menu_bar->Append(file_menu, "&File");
-  if (isCanvas)
-    menu_bar->Append(edit_menu, "&Edit");
-  menu_bar->Append(help_menu, "&Help");
+    if ( m_mode == Mode_Single )
+    {
+        m_canvas = new MyCanvas(NULL, frame);
+        m_menuEdit = CreateDrawingEditMenu();
+        docManager->CreateNewDocument();
+    }
 
 
-  //// Associate the menu bar with the frame
-  subframe->SetMenuBar(menu_bar);
+    CreateMenuBarForFrame(frame, menuFile, m_menuEdit);
 
 
-  subframe->Centre(wxBOTH);
+    frame->SetIcon(wxICON(doc));
+    frame->Centre();
+    frame->Show();
 
 
-  return subframe;
+    return true;
 }
 
 }
 
-/*
- * This is the top-level window of the application.
- */
-IMPLEMENT_CLASS(MyFrame, wxDocParentFrame)
-BEGIN_EVENT_TABLE(MyFrame, wxDocParentFrame)
-    EVT_MENU(DOCVIEW_ABOUT, MyFrame::OnAbout)
-END_EVENT_TABLE()
+int MyApp::OnExit()
+{
+    wxDocManager * const manager = wxDocManager::GetDocumentManager();
+#if wxUSE_CONFIG
+    manager->FileHistorySave(*wxConfig::Get());
+#endif // wxUSE_CONFIG
+    delete manager;
 
 
-MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title,
-    const wxPoint& pos, const wxSize& size, const long type):
-  wxDocParentFrame(manager, frame, id, title, pos, size, type)
+    return wxApp::OnExit();
+}
+
+void MyApp::AppendDocumentFileCommands(wxMenu *menu, bool supportsPrinting)
 {
 {
-  // This pointer only needed if in single window mode
-  canvas = (MyCanvas *) NULL;
-  editMenu = (wxMenu *) NULL;
+    menu->Append(wxID_CLOSE);
+    menu->Append(wxID_SAVE);
+    menu->Append(wxID_SAVEAS);
+    menu->Append(wxID_REVERT, _("Re&vert..."));
+
+    if ( supportsPrinting )
+    {
+        menu->AppendSeparator();
+        menu->Append(wxID_PRINT);
+        menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
+        menu->Append(wxID_PREVIEW);
+    }
 }
 
 }
 
-void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
+wxMenu *MyApp::CreateDrawingEditMenu()
 {
 {
-    (void)wxMessageBox("DocView Demo\nAuthor: Julian Smart julian.smart@ukonline.co.uk\nUsage: docview.exe [-single]", "About DocView");
+    wxMenu * const menu = new wxMenu;
+    menu->Append(wxID_UNDO);
+    menu->Append(wxID_REDO);
+    menu->AppendSeparator();
+    menu->Append(wxID_CUT, "&Cut last segment");
+
+    return menu;
 }
 
 }
 
-// Creates a canvas. Called either from view.cc when a new drawing
-// view is created, or in OnInit as a child of the main window,
-// if in 'single window' mode.
-MyCanvas *MyFrame::CreateCanvas(wxView *view, wxFrame *parent)
+void MyApp::CreateMenuBarForFrame(wxFrame *frame, wxMenu *file, wxMenu *edit)
 {
 {
-  int width, height;
-  parent->GetClientSize(&width, &height);
+    wxMenuBar *menubar = new wxMenuBar;
+
+    menubar->Append(file, wxGetStockLabel(wxID_FILE));
 
 
-  // Non-retained canvas
-  MyCanvas *canvas = new MyCanvas(view, parent, wxPoint(0, 0), wxSize(width, height), 0);
-  canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
+    if ( edit )
+        menubar->Append(edit, wxGetStockLabel(wxID_EDIT));
 
 
-  // Give it scrollbars
-  canvas->SetScrollbars(20, 20, 50, 50);
+    wxMenu *help= new wxMenu;
+    help->Append(wxID_ABOUT);
+    menubar->Append(help, wxGetStockLabel(wxID_HELP));
 
 
-  return canvas;
+    frame->SetMenuBar(menubar);
 }
 
 }
 
-MyFrame *GetMainFrame(void)
+wxFrame *MyApp::CreateChildFrame(wxView *view, bool isCanvas)
 {
 {
-  return frame;
+    // create a child frame of appropriate class for the current mode
+    wxFrame *subframe;
+    wxDocument *doc = view->GetDocument();
+#if wxUSE_MDI_ARCHITECTURE
+    if ( GetMode() == Mode_MDI )
+    {
+        subframe = new wxDocMDIChildFrame
+                       (
+                            doc,
+                            view,
+                            wxStaticCast(GetTopWindow(), wxDocMDIParentFrame),
+                            wxID_ANY,
+                            "Child Frame",
+                            wxDefaultPosition,
+                            wxSize(300, 300)
+                       );
+    }
+    else
+#endif // wxUSE_MDI_ARCHITECTURE
+    {
+        subframe = new wxDocChildFrame
+                       (
+                            doc,
+                            view,
+                            wxStaticCast(GetTopWindow(), wxDocParentFrame),
+                            wxID_ANY,
+                            "Child Frame",
+                            wxDefaultPosition,
+                            wxSize(300, 300)
+                       );
+
+        subframe->Centre();
+    }
+
+    wxMenu *menuFile = new wxMenu;
+
+    menuFile->Append(wxID_NEW);
+    menuFile->Append(wxID_OPEN);
+    AppendDocumentFileCommands(menuFile, isCanvas);
+    menuFile->AppendSeparator();
+    menuFile->Append(wxID_EXIT);
+
+    wxMenu *menuEdit;
+    if ( isCanvas )
+    {
+        menuEdit = CreateDrawingEditMenu();
+
+        doc->GetCommandProcessor()->SetEditMenu(menuEdit);
+        doc->GetCommandProcessor()->Initialize();
+    }
+    else // text frame
+    {
+        menuEdit = new wxMenu;
+        menuEdit->Append(wxID_COPY);
+        menuEdit->Append(wxID_PASTE);
+        menuEdit->Append(wxID_SELECTALL);
+    }
+
+    CreateMenuBarForFrame(subframe, menuFile, menuEdit);
+
+    subframe->SetIcon(isCanvas ? wxICON(chrt) : wxICON(notepad));
+
+    return subframe;
 }
 
 }
 
+void MyApp::OnAbout(wxCommandEvent& WXUNUSED(event))
+{
+    wxString modeName;
+    switch ( m_mode )
+    {
+#if wxUSE_MDI_ARCHITECTURE
+        case Mode_MDI:
+            modeName = "MDI";
+            break;
+#endif // wxUSE_MDI_ARCHITECTURE
+
+        case Mode_SDI:
+            modeName = "SDI";
+            break;
+
+        case Mode_Single:
+            modeName = "single document";
+            break;
+
+        default:
+            wxFAIL_MSG( "unknown mode ");
+    }
+
+#ifdef __VISUALC6__
+    const int docsCount =
+        wxDocManager::GetDocumentManager()->GetDocuments().GetCount();
+#else
+    const int docsCount =
+        wxDocManager::GetDocumentManager()->GetDocumentsVector().size();
+#endif
+
+    wxLogMessage
+    (
+        "This is the wxWidgets Document/View Sample\n"
+        "running in %s mode.\n"
+        "%d open documents.\n"
+        "\n"
+        "Authors: Julian Smart, Vadim Zeitlin\n"
+        "\n"
+        "Usage: docview [--{mdi,sdi,single}]",
+        modeName,
+        docsCount
+    );
+}