home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / owlsrc.pak / DOCMANAG.CPP < prev    next >
C/C++ Source or Header  |  1997-07-23  |  29KB  |  1,063 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // (C) Copyright 1993, 1994 by Borland International, All Rights Reserved
  4. //
  5. //   Implements class TDocManager
  6. //----------------------------------------------------------------------------
  7. #pragma hdrignore SECTION
  8. #include <owl/owlpch.h>
  9. #include <owl/docmanag.h>
  10. #include <owl/appdict.h>
  11. #include <owl/docview.rh>
  12. #include <string.h>
  13. #include <dlgs.h>  // cmb1 for file open dialog box
  14. #include <dir.h>   // MAXEXT for file open dialog default extension
  15.  
  16. #if defined(SECTION) && SECTION != 1
  17. DIAG_DECLARE_GROUP(OwlDocView);        // General Doc/View diagnostic group
  18. #endif
  19.  
  20. #if !defined(SECTION) || SECTION == 1
  21.  
  22. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlDocView, 1, 0);
  23.  
  24. //
  25. //  class TPickList
  26. //  ----- ---------
  27. //
  28. class TPickList : public TWindow {
  29.   public:
  30.     TPickList(const char far* title, TWindow* parent);
  31.     TPickList(uint sid, TWindow* parent);
  32.    ~TPickList();
  33.     int AddString(const char far* str);
  34.     int Execute();   // returns pick index (1 based), 0 if cancelled
  35.  
  36.   private:
  37.     LRESULT EvCommand(uint id, HWND hWndCtl, uint notifyCode);
  38.  
  39.     HMENU Popup;
  40.     int   Count;
  41.     int   Index;
  42. };
  43.  
  44. TPickList::TPickList(const char far* title, TWindow* parent)
  45. :
  46.   TWindow(parent, 0, 0),
  47.   Count(0)
  48. {
  49.   Popup = ::CreatePopupMenu();
  50.   if (title) {
  51.     ::AppendMenu(Popup, MF_GRAYED, 0, title);
  52.     ::AppendMenu(Popup, MF_SEPARATOR, 0, 0);
  53.   }
  54. }
  55.  
  56. TPickList::TPickList(uint sid, TWindow* parent)
  57. :
  58.   TWindow(parent, 0, 0),
  59.   Count(0)
  60. {
  61.   char buf[256];
  62.  
  63.   Popup = ::CreatePopupMenu();
  64.   if (!sid || !GetApplication()->LoadString(sid, buf, sizeof(buf)))
  65.     return;
  66.   ::AppendMenu(Popup, MF_GRAYED, 0, buf);
  67.   ::AppendMenu(Popup, MF_SEPARATOR, 0, 0);
  68. }
  69.  
  70. TPickList::~TPickList()
  71. {
  72.   if (Popup)
  73.     ::DestroyMenu(Popup);
  74. }
  75.  
  76. int
  77. TPickList::AddString(const char far* str)
  78. {
  79.   ::AppendMenu(Popup, MF_ENABLED, ++Count, str);
  80.   return Count;
  81. }
  82.  
  83. int
  84. TPickList::Execute()
  85. {
  86.   TPoint loc;
  87.   GetCursorPos(loc);
  88.   Create();
  89.   Index = 0;
  90.   ::TrackPopupMenu(Popup, 0, loc.x, loc.y, 0, HWindow, 0);
  91.   GetApplication()->PumpWaitingMessages();  // WM_COMMAND may be in queue
  92.   ::DestroyMenu(Popup);
  93.   Popup = 0;
  94.   return Index;
  95. }
  96.  
  97. LRESULT
  98. TPickList::EvCommand(uint id, HWND /*hWndCtl*/, uint /*notifyCode*/)
  99. {
  100.   WARNX(OwlDocView, id > Count, 0, "TPickList index invalid");
  101.   Index = id;
  102.   return 0;
  103. }
  104.  
  105. //----------------------------------------------------------------------------
  106. //  class TDocManager
  107. //
  108.  
  109. DEFINE_RESPONSE_TABLE (TDocManager)
  110.   EV_WM_CANCLOSE,
  111.   EV_WM_PREPROCMENU,
  112.   EV_WM_WAKEUP,
  113.   EV_COMMAND(CM_FILENEW,           CmFileNew),
  114.   EV_COMMAND(CM_FILEOPEN,          CmFileOpen),
  115.   EV_COMMAND(CM_FILESAVE,          CmFileSave),
  116.   EV_COMMAND(CM_FILESAVEAS,        CmFileSaveAs),
  117.   EV_COMMAND(CM_FILEREVERT,        CmFileRevert),
  118.   EV_COMMAND(CM_FILECLOSE,         CmFileClose),
  119.   EV_COMMAND(CM_VIEWCREATE,        CmViewCreate),
  120.   EV_COMMAND_ENABLE(CM_FILENEW,    CeFileNew),
  121.   EV_COMMAND_ENABLE(CM_FILEOPEN,   CeFileOpen),
  122.   EV_COMMAND_ENABLE(CM_FILESAVE,   CeFileSave),
  123.   EV_COMMAND_ENABLE(CM_FILESAVEAS, CeFileSaveAs),
  124.   EV_COMMAND_ENABLE(CM_FILEREVERT, CeFileRevert),
  125.   EV_COMMAND_ENABLE(CM_FILECLOSE,  CeFileClose),
  126.   EV_COMMAND_ENABLE(CM_VIEWCREATE, CeViewCreate),
  127. END_RESPONSE_TABLE;
  128.  
  129. TDocManager::TDocManager(int mode, TDocTemplate*& templateHead)
  130. :
  131.   Mode(mode),
  132.   TemplateHead(&templateHead)
  133. {
  134.   TDocTemplate* ptpl;
  135.  
  136.   TemplateList = templateHead;  // catch up with any statics
  137.   for (ptpl = TemplateList; ptpl; ptpl = ptpl->GetNextTemplate())
  138.     ptpl->DocManager = this;
  139.  
  140.   Application = GetApplicationObject();
  141.  
  142.   // setup backward compatibility entry points
  143.   //
  144.   TDocTemplate::SelectSave_ = SelectSave;
  145.   TDocTemplate::InitDoc_    = InitDoc;
  146.   TDocTemplate::InitView_   = InitView;
  147. }
  148.  
  149. TDocManager::TDocManager(int mode, TApplication* app, TDocTemplate*& templateHead)
  150. :
  151.   Mode(mode),
  152.   Application(app),
  153.   TemplateHead(&templateHead)
  154. {
  155.   TDocTemplate* ptpl;
  156.  
  157.   TemplateList = templateHead;  // catch up with any statics
  158.   for (ptpl = TemplateList; ptpl; ptpl = ptpl->GetNextTemplate())
  159.     ptpl->DocManager = this;
  160.  
  161.   // setup backward compatibility entry points
  162.   //
  163.   TDocTemplate::SelectSave_ = SelectSave;
  164.   TDocTemplate::InitDoc_    = InitDoc;
  165.   TDocTemplate::InitView_   = InitView;
  166. }
  167.  
  168. TDocManager::~TDocManager()
  169. {
  170.   TDocument* doc;
  171.   while ((doc = DocList.Next(0)) != 0) {
  172.     if (doc->IsOpen())
  173.       doc->Close();
  174.     delete doc;            // removes view, unlinks template and doc manager
  175.     Application->PumpWaitingMessages();  // force out posted MDI child destroy
  176.   }
  177.   while (TemplateList) {
  178.     TDocTemplate* ptpl = TemplateList;
  179.     TemplateList = ptpl->GetNextTemplate();
  180.     if (ptpl->RefCnt & 0x8000)  // skip over statics
  181.       ptpl->DocManager = 0;
  182.     else
  183.       delete ptpl;
  184.   }
  185. }
  186.  
  187. //
  188. //  prompts user to select a document class for a new document
  189. //  returns the template index used for the selection (1-based), 0 if failure
  190. //
  191. int
  192. TDocManager::SelectDocType(TDocTemplate** tpllist, int tplcount)
  193. {
  194.   TPickList* pickl = new TPickList(IDS_DOCLIST, Application->GetMainWindow());
  195.   while (tplcount--)
  196.     pickl->AddString((*tpllist++)->GetDescription());
  197.   int index = pickl->Execute();
  198.   delete pickl;
  199.   return index;
  200. }
  201.  
  202. //
  203. //  prompts user to select a view class for a new view on existing document
  204. //  returns the template index used for the selection (1-based), 0 if failure
  205. //
  206. int
  207. TDocManager::SelectViewType(TDocTemplate** tpllist, int tplcount)
  208. {
  209.   TPickList* pickl = new TPickList(IDS_VIEWLIST, Application->GetMainWindow());
  210.   while (tplcount--)
  211.     pickl->AddString((*tpllist++)->GetViewName());
  212.   int index = pickl->Execute();
  213.   delete pickl;
  214.   return index;
  215. }
  216.  
  217. //
  218. //  struct to pass data to the dialog hook function via OPENFILENAME.lCustData
  219. //  under Win32s the OPENFILENAME passed to WM_INITDIALOG is a temporary copy
  220. //
  221. struct TplHookData {      // pointer to this struct passed as lCustData
  222.   long Flags;             // original flags passed to SelectDocPath
  223.   unsigned long far* DlgFlags;     // pointer to dialog flags in OPENFILENAME
  224.   char far* ExtBuf;       // pointer to buffer holding the default extension
  225.   TDocTemplate** TplList; // template pointer array
  226.   int InitIndex;          // starting index, ofn.nFilterIndex is inconsistent
  227.   bool Save;              // true if saving
  228. };
  229.  
  230. //
  231. //  dialog hook function to catch template selection changes
  232. //
  233. uint CALLBACK __export
  234. TplHook(HWND hDlg, uint msg, uint wParam, int32 lParam)
  235. {
  236.   static TplHookData* hookData;  // !!update to store in dialog property
  237.   TDocTemplate** tpllist;
  238.   OPENFILENAME* ofnHook;
  239.   int idx;
  240.   switch(msg) {
  241.     case WM_COMMAND:
  242. #if defined(BI_PLAT_WIN32)
  243.       if (LOWORD(wParam) != cmb1 || HIWORD(wParam) != CBN_SELCHANGE)
  244. #else
  245.       if (wParam != cmb1 || HIWORD(lParam) != CBN_SELCHANGE)
  246. #endif
  247.         return 0;
  248.       idx = (int)::SendMessage((HWND)(uint)lParam, CB_GETCURSEL, 0, 0L);
  249.       break;
  250.  
  251.     case WM_INITDIALOG:
  252.       ofnHook = (OPENFILENAME*)lParam;
  253.       hookData = (TplHookData*)ofnHook->lCustData;
  254.       idx = hookData->InitIndex;  // can't rely upon ofnHook->nFilterIndex
  255.       break;
  256.  
  257.     default:
  258.       return 0;
  259.   }
  260.   tpllist = hookData->TplList;
  261.   long flags = tpllist[idx]->GetFlags() | hookData->Flags;
  262.   if (hookData->Save)
  263.     flags = (flags | dtNoReadOnly) & ~dtFileMustExist;
  264.   *hookData->DlgFlags = flags & ~dtProhibited;
  265.   if (tpllist[idx]->GetDefaultExt())
  266.     strcpy(hookData->ExtBuf, tpllist[idx]->GetDefaultExt());
  267.   else
  268.     hookData->ExtBuf[0] = 0;
  269.   ::SendDlgItemMessage(hDlg, chx1, BM_SETCHECK, ((flags&dtReadOnly) != 0), 0);
  270.   ::ShowWindow(GetDlgItem(hDlg, chx1), (flags&dtHideReadOnly)?SW_HIDE:SW_SHOW);
  271.   return 0;  // flag as unprocessed
  272. }
  273.  
  274. //  prompts user with one or all templates to select file to open
  275. //  returns the template index used for the selection (1-based), 0 if failure
  276. //  this is Windows-specific, using the system-defined file open dialog box
  277. //
  278. int
  279. TDocManager::SelectDocPath(TDocTemplate** tpllist, int tplcount,
  280.               char far* path, int buflen, long flags, bool save)
  281. {
  282.   char extbuf[MAXEXT-1];       // writable buffer for default file extension
  283.   OPENFILENAME ofn;            // local openfilename structure
  284.   int index, count, len;
  285.   char* filtbuf;
  286.   char* pbuf;
  287.   memset(&ofn, 0, sizeof(ofn));
  288.   TDocTemplate* ptpl;
  289.   TProcInstance TplHookProcInstance((FARPROC)TplHook);
  290.  
  291.   // Concatenate description and filters into a single string
  292.   //
  293.   for (len=2, count=0; count < tplcount; count++) {
  294.     ptpl = tpllist[count];
  295.     len += (strlen(ptpl->GetFileFilter())+2); // space for two null separators
  296.     if (ptpl->GetDescription())
  297.       len += strlen(ptpl->GetDescription());
  298.   }
  299.   filtbuf = new char[len];
  300.   for (pbuf = filtbuf, count=0; count < tplcount; count++) {
  301.     ptpl = tpllist[count];
  302.     if ((len = strlen(ptpl->GetDescription())) != 0) {
  303.       strcpy(pbuf, ptpl->GetDescription());
  304.       pbuf += len + 1;
  305.     }
  306.     else {
  307.       *pbuf++ = 0;
  308.     }
  309.     strcpy(pbuf, ptpl->GetFileFilter());
  310.     pbuf += strlen(pbuf) + 1;
  311.   }
  312.   *pbuf = 0;              // double null to signify end
  313.  
  314.   // set selection to previously selected template if present
  315.   //
  316.   for (index = count = 0; count < tplcount; count++)
  317.     if (tpllist[count]->IsFlagSet(dtSelected)) {
  318.       index = count;
  319.       break;
  320.     }
  321.  
  322.   struct TplHookData hookData = {flags,&ofn.Flags,extbuf,tpllist,index,save};
  323.   ofn.nFilterIndex = index + 1; // Note: Windows *might* decrement this by one
  324.   ofn.lpstrInitialDir = tpllist[index]->GetDirectory();
  325.   ofn.lpstrDefExt = (LPCSTR)&extbuf;  // receives string from hook function
  326.   ofn.lStructSize = sizeof(OPENFILENAME);
  327.   ofn.hwndOwner = Application->GetMainWindow()->HWindow;
  328.   ofn.lpstrFilter = filtbuf;
  329.   ofn.lpstrFile = path;
  330.   ofn.nMaxFile = buflen;
  331.   ofn.Flags = OFN_ENABLEHOOK /* | OFN_NOCHANGEDIR */;
  332.   ofn.lCustData = (LPARAM)&hookData;
  333.   (DLGPROC)ofn.lpfnHook = (DLGPROC)(FARPROC)TplHookProcInstance;
  334.  
  335.   Application->EnableCtl3dAutosubclass(true);
  336.  
  337.   if ((save ? ::GetSaveFileName(&ofn) : ::GetOpenFileName(&ofn)) == 0) {
  338.     uint32 err = ::CommDlgExtendedError();  // temp for debugging use
  339.     if (err != 0)
  340.       TRACEX(OwlDocView, 0, "OpenFileName error:" << err);
  341.     ofn.nFilterIndex = 0;
  342.   }
  343.   else {
  344.     TDocument* doc;
  345.     if (ofn.lpstrFile && (doc = FindDocument(ofn.lpstrFile)) != 0) {
  346.       PostDocError(*doc, IDS_DUPLICATEDOC);
  347.       return 0;
  348.     }
  349.  
  350.     // Set flag to remember template which was selected
  351.     //
  352.     for (index=(int)ofn.nFilterIndex-1, count=0; count < tplcount; count++) {
  353.       if (count == index)
  354.         tpllist[count]->SetFlag(dtSelected);
  355.       else
  356.         tpllist[count]->ClearFlag(dtSelected);
  357.     }
  358.     // Update template with directory from dialog if flag set
  359.     //
  360.     ptpl = tpllist[(int)ofn.nFilterIndex - 1];
  361.     if (ofn.nFileOffset && (ptpl->IsFlagSet(dtUpdateDir))
  362.                         && (ptpl->GetDirectory()==0
  363.          || memcmp(ptpl->GetDirectory(), ofn.lpstrFile,ofn.nFileOffset) != 0))
  364.       ptpl->SetDirectory(ofn.lpstrFile, ofn.nFileOffset);
  365.   }
  366.   delete [] filtbuf;
  367.   Application->EnableCtl3dAutosubclass(false);
  368.   return (int)ofn.nFilterIndex;
  369. }
  370.  
  371. void
  372. TDocManager::AttachTemplate(TDocTemplate& tpl)
  373. {
  374.   tpl.DocManager = this;
  375.   TDocTemplate::AddLink((TRegLink*&)TemplateList, tpl);
  376. }
  377.  
  378. void
  379. TDocManager::DeleteTemplate(TDocTemplate& tpl)
  380. {
  381.   if (tpl.RefCnt & 0x8000) // check for static templates
  382.     return;
  383.   if (!tpl.DocManager)    // check if has owner
  384.     return;
  385.  
  386.   if (TDocTemplate::RemoveLink((TRegLink*&)TemplateList, tpl)) {
  387.     UnRefTemplate(tpl);  // will delete unless documents still reference it
  388.     return;
  389.   }
  390.   TRACEX(OwlDocView, 0, "TDocManager::DeleteTemplate(), not in app list");
  391. }
  392.  
  393. //  initialize document using its specific doc template
  394. //  prompts for pathname if none supplied and not creating a new document
  395. //
  396. TDocument*
  397. TDocManager::InitDoc(TDocument* doc, const char far* path, long flags)
  398. {
  399.   TDocTemplate* tpl = doc->GetTemplate();
  400.   if (!tpl)
  401.     return 0;
  402.   flags ^= tpl->GetFlags();     // alter template's flags using caller's mask
  403.   if (flags & dtNewDoc) {
  404.     doc->SetDocPath(0);
  405.     if (!doc->InitDoc()) { // Give doc a chance to do its own initialization
  406.       PostDocError(*doc, IDS_UNABLEOPEN);
  407.       delete doc;
  408.       return 0;
  409.     }
  410.   }
  411.   else {
  412.     if (!path) {
  413.       char filepath[256];
  414.       if (!tpl->GetFileFilter())
  415.         return 0;
  416.       filepath[0] = 0;    // no initial file path
  417.       int index = SelectDocPath(&tpl, 1, filepath, sizeof(filepath), flags);
  418.       if (!index) {
  419.         delete doc;
  420.         return 0;
  421.       }
  422.       path = filepath;
  423.     }
  424.     doc->SetDocPath(path);
  425.     if (!doc->InitDoc()) { // Give doc a chance to do its own initialization
  426.       PostDocError(*doc, IDS_UNABLEOPEN);
  427.       delete doc;
  428.       return 0;
  429.     }
  430.  
  431.     if ((flags & dtAutoOpen)
  432.         && !doc->Open((flags & dtNoReadOnly) ? ofReadWrite : ofRead)) {
  433.       PostDocError(*doc, IDS_UNABLEOPEN);
  434.       delete doc;
  435.       return 0;
  436.     }
  437.   }
  438.   PostEvent(dnCreate, *doc);
  439.   if (!(flags & dtNoAutoView)) {
  440.     if (!doc->InitView(tpl->ConstructView(*doc))) {
  441.       if (flags & dtAutoDelete) {
  442.         if (doc->IsOpen())
  443.           doc->Close();
  444.         delete doc;
  445.       }
  446.       return 0;
  447.     }
  448.   }
  449.   return doc;
  450. }
  451.  
  452. //  create and initialize document using a specific doc template
  453. //
  454. TDocument*
  455. TDocManager::CreateDoc(TDocTemplate* tpl, const char far* path,
  456.                        TDocument* parent, long flags)
  457. {
  458.   if (!tpl)
  459.     return 0;
  460.  
  461.   TDocument dummyDoc(this);
  462.   if (parent == 0)
  463.     parent = &dummyDoc;
  464.  
  465.   TDocument* doc = tpl->ConstructDoc(parent);
  466.   if (!doc)
  467.     return 0;
  468.   doc->SetTemplate(tpl);
  469.   return InitDoc(doc, path, flags);
  470. }
  471.  
  472. TView*
  473. TDocManager::CreateView(TDocument& doc)
  474. {
  475.   return doc.InitView(doc.GetTemplate()->ConstructView(doc)); // tests view==0
  476. }
  477.  
  478. bool
  479. TDocManager::SelectSave(TDocument& doc)
  480. {
  481.   TDocTemplate* ptpl = doc.GetTemplate();
  482.   if (!ptpl || !ptpl->GetFileFilter())
  483.     return false;
  484.   char filepath[256];
  485.   if (doc.GetDocPath())
  486.     strcpy(filepath, doc.GetDocPath());
  487.   else
  488.     filepath[0] = 0;    // no initial file path
  489.   int index = SelectDocPath(&ptpl,1, filepath,sizeof(filepath), 0, true);
  490.   return index ? doc.SetDocPath(filepath) : false;
  491. }
  492.  
  493. TDocument*
  494. TDocManager::FindDocument(const char far* path)
  495. {
  496.   TDocument* doc = 0;
  497.   while ((doc = DocList.Next(doc)) != 0)
  498.     if (path) {
  499.       if (doc->GetDocPath() && strcmp(doc->GetDocPath(), path) == 0)
  500.         break;
  501.     }
  502.     else {
  503.       if (doc->GetDocPath() == 0)
  504.         break;
  505.     }
  506.   return doc;
  507. }
  508.  
  509. void
  510. TDocManager::PostEvent(int id, TDocument& doc)
  511. {
  512.   TWindow* win = Application->GetMainWindow();
  513.   if (win && win->HWindow)
  514.     win->SendMessage(WM_OWLDOCUMENT, id, (LPARAM)&doc);
  515. }
  516.  
  517. void
  518. TDocManager::PostEvent(int id, TView& view)
  519. {
  520.   TWindow* win = Application->GetMainWindow();
  521.   if (win && win->HWindow)
  522.     win->SendMessage(WM_OWLVIEW, id, (LPARAM)&view);
  523. }
  524.  
  525. bool
  526. TDocManager::EvCanClose()
  527. {
  528.   TDocument* doc = 0;
  529.   while ((doc = DocList.Next(doc)) != 0) {
  530.     if (!doc->CanClose())  // normally calls back to FlushDoc()
  531.       return false;
  532.   }
  533.   return true;
  534. }
  535.  
  536. //
  537. // Preprocess the app frame's menu to replace the file menu with one managed
  538. // by this docmanager
  539. //
  540. void
  541. TDocManager::EvPreProcessMenu(HMENU hMenuBar)
  542. {
  543.   if (Mode & dmMenu) {
  544.     HMENU hMenu = Application->LoadMenu(IDM_DOCMANAGERFILE);
  545.     if (!hMenu)
  546.       hMenu = ::Module->LoadMenu(IDM_DOCMANAGERFILE);
  547.     if (hMenu) {
  548.       char buf[40];
  549.       Application->LoadString(IDS_DOCMANAGERFILE, buf, sizeof buf);
  550.       if (Mode & dmNoRevert)
  551.         ::DeleteMenu(hMenu, CM_FILEREVERT, MF_BYCOMMAND);
  552.       ::DeleteMenu(hMenuBar, 0, MF_BYPOSITION);
  553.       ::InsertMenu(hMenuBar, 0, MF_BYPOSITION|MF_POPUP, (uint)hMenu, buf);
  554.     }
  555.   }
  556. }
  557.  
  558. void
  559. TDocManager::EvWakeUp()
  560. {
  561.   TDocument* doc = 0;
  562.   while ((doc = DocList.Next(doc)) != 0)
  563.     doc->ReindexFrames();
  564. }
  565.  
  566. bool
  567. TDocManager::FlushDoc(TDocument& doc)
  568. {
  569.   while (doc.IsDirty()) {
  570.     int saveOrNot = doc.IsEmbedded() ?
  571.                       IDYES :
  572.                       PostDocError(doc, IDS_DOCCHANGED, MB_YESNOCANCEL);
  573.  
  574.     switch (saveOrNot) {
  575.       case IDYES:
  576.         // Prompt the user for filename in save-as situation
  577.         //
  578.         if (!doc.IsEmbedded() && doc.GetDocPath() == 0) {
  579.           TDocTemplate* tpl = SelectAnySave(doc, false);
  580.           if (!tpl)
  581.             continue;
  582.           if (tpl != doc.Template)
  583.             doc.SetTemplate(tpl);
  584.         }
  585.         if (doc.Commit())
  586.           return true;
  587.         continue;
  588.  
  589.       case IDNO:
  590.         if (doc.Revert(true))
  591.           return true;
  592.         return false;
  593.  
  594.       case IDCANCEL:
  595.         return false;
  596.     }
  597.   }
  598.   return true;
  599. }
  600.  
  601. TDocument*
  602. TDocManager::GetCurrentDoc()
  603. {
  604.   TDocument* doc = 0;
  605.   HWND hwnd = GetApplication()->GetMainWindow()->GetCommandTarget();
  606.  
  607.   while ((doc = DocList.Next(doc)) != 0 && !doc->HasFocus(hwnd))
  608.     ;
  609.   return doc;
  610. }
  611.  
  612. //
  613. // event handlers
  614. //
  615. void
  616. TDocManager::CeFileNew(TCommandEnabler& ce)
  617. {
  618.   ce.Enable(TemplateList != 0);
  619. }
  620.  
  621. void
  622. TDocManager::CmFileNew()
  623. {
  624.   CreateAnyDoc(0, dtNewDoc);
  625. }
  626.  
  627. void
  628. TDocManager::CeFileOpen(TCommandEnabler& ce)
  629. {
  630.   ce.Enable(TemplateList != 0);
  631. }
  632.  
  633. void
  634. TDocManager::CmFileOpen()
  635. {
  636.   CreateAnyDoc(0, 0);
  637. }
  638.  
  639. void
  640. TDocManager::CeFileClose(TCommandEnabler& ce)
  641. {
  642.   ce.Enable(GetCurrentDoc() != 0);
  643. }
  644.  
  645. void
  646. TDocManager::CmFileClose()
  647. {
  648.   TDocument* doc = GetCurrentDoc();
  649.   if (doc && doc->CanClose()) {  // normally calls back to FlushDoc()
  650.     if (!doc->Close())
  651.       PostDocError(*doc, IDS_UNABLECLOSE);
  652.     else
  653.       delete doc;
  654.   }
  655. }
  656.  
  657. void
  658. TDocManager::CeFileSaveAs(TCommandEnabler& ce)
  659. {
  660.   TDocument* doc = GetCurrentDoc();
  661.   ce.Enable(doc != 0);
  662. }
  663.  
  664. void
  665. TDocManager::CmFileSaveAs()
  666. {
  667.   TDocument* doc = GetCurrentDoc();
  668.   if (doc) {
  669.     TDocTemplate* tpl = SelectAnySave(*doc, false);
  670.     if (tpl) {
  671.       if (tpl != doc->Template)
  672.         doc->SetTemplate(tpl);       // replace existing template
  673.       doc->Commit(true);             // force rewrite to new path
  674.     }
  675.   }
  676. }
  677.  
  678. void
  679. TDocManager::CeFileSave(TCommandEnabler& ce)
  680. {
  681.   TDocument* doc = GetCurrentDoc();
  682.   ce.Enable(doc && (doc->IsDirty() || (Mode & dmSaveEnable)));
  683. }
  684.  
  685. void
  686. TDocManager::CmFileSave()
  687. {
  688.   TDocument* doc = GetCurrentDoc();
  689.   if (doc) {
  690.     if (doc->GetDocPath() == 0) {
  691.       CmFileSaveAs();
  692.       return;
  693.     }
  694.     if (!(Mode & dmSaveEnable) && !doc->IsDirty()) {
  695.       PostDocError(*doc, IDS_NOTCHANGED);
  696.       return;
  697.     }
  698.     doc->Commit();  // should force write here?
  699.   }
  700. }
  701.  
  702. void
  703. TDocManager::CeFileRevert(TCommandEnabler& ce)
  704. {
  705.   TDocument* doc = GetCurrentDoc();
  706.   ce.Enable(doc && doc->IsDirty() && doc->GetDocPath());
  707. }
  708.  
  709. void
  710. TDocManager::CmFileRevert()
  711. {
  712.   TDocument* doc = GetCurrentDoc();
  713.   if (doc && doc->GetDocPath()) {
  714.     if (!doc->IsDirty()) {
  715.       PostDocError(*doc, IDS_NOTCHANGED);
  716.       return;
  717.     }
  718.     doc->Revert();
  719.   }
  720. }
  721.  
  722. void
  723. TDocManager::CeViewCreate(TCommandEnabler& hndlr)
  724. {
  725.   TDocument* doc = GetCurrentDoc();
  726.   hndlr.Enable(doc != 0);
  727. }
  728.  
  729. void
  730. TDocManager::CmViewCreate()
  731. {
  732.   TDocument* doc = GetCurrentDoc();
  733.   if (doc)
  734.     CreateAnyView(*doc);
  735. }
  736.  
  737. uint
  738. TDocManager::PostDocError(TDocument& doc, uint sid, uint choice)
  739. {
  740.   char buf[256];
  741.  
  742.   if (Application->LoadString(sid, buf, sizeof buf) == 0)
  743.     strcpy(buf, "Error: Message not found");  // should throw exception?
  744.   if (choice != MB_OK)
  745.     choice |= MB_ICONQUESTION;
  746.   return Application->GetMainWindow()->MessageBox(buf, doc.GetTitle(), choice);
  747. }
  748.  
  749. //
  750. //  CreateAnyDoc - selects from list of attached non-hidden doc templates
  751. //
  752. TDocument*
  753. TDocManager::CreateAnyDoc(const char far* path, long flags)
  754. {
  755.   TDocTemplate* ptpl;
  756.   TDocument* doc;
  757.   char filepath[256];
  758.   int index;
  759.   TDocTemplate* tpllist[40];  // increase number to display more templates
  760.   int tplcount = 0;
  761.  
  762.   // compose list of visible templates
  763.   //
  764.   for (ptpl = TemplateList; ptpl; ptpl = ptpl->GetNextTemplate()) {
  765.     if (ptpl->IsVisible() &&
  766.         !(ptpl->IsFlagSet(dtReadOnly) && (flags & dtNewDoc)))
  767.       tpllist[tplcount++] = ptpl;
  768.  
  769.     // prevent overflowing array
  770.     if (tplcount >= sizeof(tpllist)/sizeof(tpllist[0]))
  771.       break;
  772.   }
  773.   if (!tplcount)
  774.     return 0;         // no usable templates
  775.  
  776.   if (flags & dtNewDoc) {  // creat empty doc from any registered template
  777.     index = tplcount==1 ? 1 : SelectDocType(tpllist, tplcount);
  778.   }
  779.   else {           // select doc using filters from all registered templates
  780.     if (path)
  781.       strcpy(filepath, path);
  782.     else
  783.       filepath[0] = 0;    // no initial file path
  784.     index = SelectDocPath(tpllist, tplcount, filepath, sizeof(filepath), flags);
  785.     WARNX(OwlDocView, index > tplcount, 0,
  786.           "Invalid template index from SelectDocPath");
  787.   }
  788.   if (!index)
  789.     return 0;   // user cancel or dialog error
  790.  
  791.   if (filepath && (doc = FindDocument(filepath)) != 0) {
  792.     PostDocError(*doc, IDS_DUPLICATEDOC);
  793.     return 0;
  794.   }
  795.  
  796.   ptpl = tpllist[index-1];
  797.  
  798.   if ((Mode & dmSDI) && (doc = DocList.Next(0)) != 0) { // one at a time if SDI
  799.     if (!doc->CanClose())        // normally calls back to FlushDoc()
  800.       return 0;
  801.     if (!doc->Close()) {
  802.       PostDocError(*doc, IDS_UNABLECLOSE);
  803.       return 0;
  804.     }
  805.     delete doc;
  806.   }
  807.  
  808.   doc = ptpl->ConstructDoc(&TDocument(this));  // pass a dummy doc
  809.   doc->SetTemplate(ptpl);
  810.   return InitDoc(doc, filepath, flags);
  811. }
  812.  
  813. //
  814. //  SelectAnySave - selects from registered templates supporting this doc
  815. //
  816. TDocTemplate*
  817. TDocManager::SelectAnySave(TDocument& doc, bool samedoc)
  818. {
  819.   TDocTemplate* ptpl;
  820.   char filepath[256];
  821.   int index;
  822.   TDocTemplate* tpllist[40];
  823.   int tplcount;
  824.  
  825.   if (!TemplateList)
  826.     return 0;   // if no templates are registered
  827.   for (tplcount = 0, ptpl = TemplateList; ptpl; ptpl = ptpl->GetNextTemplate()) {
  828.     if (ptpl->IsVisible() && (!samedoc || ptpl->IsMyKindOfDoc(doc))
  829.         && !ptpl->IsFlagSet(dtReadOnly) )
  830.       tpllist[tplcount++] = ptpl;
  831.   }
  832.   if (!tplcount)
  833.     return 0;         // no usable templates
  834.   if (doc.GetDocPath())
  835.     strcpy(filepath, doc.GetDocPath());
  836.   else
  837.     filepath[0] = 0;    // no initial file path
  838.   index = SelectDocPath(tpllist, tplcount, filepath, sizeof(filepath),0,true);
  839.   if (!index)
  840.     return 0;   // user cancel or dialog error
  841.   ptpl = tpllist[index-1];
  842.   if (!doc.SetDocPath(filepath))
  843.     return 0;
  844.   return ptpl;
  845. }
  846.  
  847. //
  848. //  CreateAnyView - selects from registered templates supporting this doc
  849. //
  850. TView*
  851. TDocManager::CreateAnyView(TDocument& doc, long /*flags*/)
  852. {
  853.   const int MaxViewCount = 25;
  854.   TDocTemplate* tplList[MaxViewCount];
  855.   int tplCount;
  856.   TDocTemplate* ptpl;
  857.   int index;
  858.   const char far* viewName;
  859.  
  860.   for (ptpl=TemplateList, tplCount=0; ptpl != 0; ptpl = ptpl->GetNextTemplate()) {
  861.     if (ptpl->IsMyKindOfDoc(doc)) {
  862.       viewName = ptpl->GetViewName();
  863.       for (index = 0; index < tplCount; index++)
  864.         if (tplList[index]->GetViewName() == viewName)
  865.           break;
  866.       if (ptpl->IsFlagSet(dtSingleView)) {
  867.         TView* pview = 0;
  868.         while ((pview = doc.NextView(pview)) != 0)
  869.           if (ptpl->IsMyKindOfView(*pview))
  870.             index = -1;  // force continue in outer loop
  871.       }
  872.       if (index == tplCount) {
  873.         tplList[tplCount++] = ptpl;
  874.       }
  875.     }
  876.   }
  877.   index = (tplCount > 1) ? SelectViewType(tplList, tplCount) : tplCount;
  878.   if (index == 0)   // check if user cancelled or no valid templates
  879.     return 0;
  880.  
  881.   ptpl = tplList[index - 1];
  882.   return doc.InitView(ptpl->ConstructView(doc)); // call virtual create
  883. }
  884.  
  885. #define ANSITOUPPER(c) ( (char)(unsigned)(unsigned long)\
  886.                 ::AnsiUpper((char far*)(unsigned long)(c)) )
  887.  
  888. TDocTemplate*
  889. TDocManager::MatchTemplate(const char far* path)
  890. {
  891.   TDocTemplate* ptpl;
  892.   char name[256];
  893.  
  894.   if (FindDocument(path))
  895.     return 0;   // prevent reload of same document
  896.   if (::GetFileTitle(path, name, sizeof(name)) != 0)
  897.     return 0;   // invalid name or buffer too small
  898.   ::AnsiUpper(name);
  899.   for (ptpl = TemplateList; ptpl != 0; ptpl = ptpl->GetNextTemplate()) {
  900.     const char far* pp = ptpl->GetFileFilter();
  901.     if (!pp || ptpl->IsFlagSet(dtHidden))
  902.       continue;
  903.     char* pn = name;
  904.     char  cp;
  905.     do {
  906.       if ((cp = *pp++) != '?') {
  907.         if (cp == '*') {
  908.           while (*pn != '.' && *pn != 0)
  909.             pn++;
  910.           if (*pp == '.' && *pn == 0)  // check for missing extension
  911.             pp++;
  912.           continue;
  913.         }
  914.         if (*pn != ANSITOUPPER(cp)) {  // if mismatch
  915.           if (!(cp == ';' && *pn == 0)) { // check for successful case
  916.             while (cp != ';' && cp != 0)  // check if more patterns
  917.               cp = *pp++;
  918.             pn = name;      // rescan name
  919.             continue;
  920.           }
  921.         }
  922.       }
  923.       if (*pn++ == 0)    // reached end of name OK
  924.         return ptpl;
  925.     } while (cp != 0);
  926.   }
  927.   return 0;   // returns 0 if loop terminates with no matching templates
  928. }
  929.  
  930. #endif
  931.  
  932. #if !defined(SECTION) || SECTION == 2
  933.  
  934. IMPLEMENT_STREAMABLE(TDocManager);
  935.  
  936. void*
  937. TDocManager::Streamer::Read(ipstream& is, uint32 /*version*/) const
  938. {
  939.   TDocManager* o = GetObject();
  940.  
  941.   TDocTemplate* ptpl = o->TemplateList;
  942.   for (;;) {
  943.     int isStatic;
  944.  
  945.     is >> isStatic;
  946.     if (isStatic == -1)
  947.       break;
  948.  
  949.     if (isStatic) {
  950.       if (ptpl) {                         // if static templates available
  951.         is >> *ptpl;                      // update static template data
  952.         ptpl = o->GetNextTemplate(ptpl);
  953.       }
  954.       else {                            // have run out of static templates
  955.         char tbuf[sizeof(TDocTemplate)];  // sink for unused template data
  956.         memset(tbuf,0,sizeof(tbuf));      // force static flag off
  957.         is >> *(TDocTemplate*)tbuf;
  958.       }
  959.     }
  960.     else {                // if dynamic template, object will be constructed
  961.       TModule* module;
  962.       is >> module;
  963.       is >> ptpl;
  964.       ptpl->SetModule(module);
  965.       o->AttachTemplate(*ptpl);
  966.     }
  967.   }
  968.  
  969.   int count;
  970.   is >> count;               // document count
  971.   while (count--) {
  972.     TDocument*  doc;
  973.     is >> doc;
  974.     doc->SetDocManager(*o);  // inserts properly into list
  975.   }
  976.  
  977.   // Get application, & post ourselves a wakeup message to finish things up
  978.   // once all windows have been created, etc.
  979.   //
  980.   o->Application = GetApplicationObject();
  981.   TWindow* win = o->Application->GetMainWindow();
  982.   if (win && win->HWindow)
  983.     win->PostMessage(WM_OWLWAKEUP);
  984.  
  985.   return o;
  986. }
  987.  
  988. void
  989. TDocManager::Streamer::Write(opstream& os) const
  990. {
  991.   TDocManager* o = GetObject();
  992.  
  993.   TDocTemplate* ptpl = 0;
  994.   while ((ptpl = o->GetNextTemplate(ptpl)) != 0) {
  995.     int flag = ptpl->IsStatic();
  996.     os << flag;
  997.     if (flag) {
  998.       os << *ptpl;              // write reference to static template
  999.     }
  1000.     else {
  1001.       os << ptpl->GetModule();  // write template's module pointer first
  1002.       os << ptpl;               // write pointer to static template
  1003.     }
  1004.   }
  1005.   os << -1;   // template list terminator
  1006.  
  1007.   TDocument* doc = 0;
  1008.   int count;
  1009.   for (count = 0; (doc = o->DocList.Next(doc))!=0; count++) ;
  1010.   os << count;
  1011.  
  1012.   // Must write documents out in order created, i.e. from end of list forward
  1013.   //
  1014.   while (count) {
  1015.     int i = count--;
  1016.     for (doc = 0; i--; doc = o->DocList.Next(doc)) ;
  1017.     os << doc;
  1018.   }
  1019. }
  1020.  
  1021. //
  1022. // TDocTemplate backward compatibility code
  1023. //
  1024.  
  1025. bool TDocManager::SelectSave(TDocTemplate* ptpl, TDocument& doc)
  1026. {
  1027.   TDocManager* mgr = ptpl->GetDocManager();
  1028.   if (!mgr || !ptpl || !ptpl->GetFileFilter())
  1029.     return false;
  1030.   char filepath[256];
  1031.   if (doc.GetDocPath())
  1032.     strcpy(filepath, doc.GetDocPath());
  1033.   else
  1034.     filepath[0] = 0;    // no initial file path
  1035.   int index = mgr->SelectDocPath(&ptpl,1, filepath,sizeof(filepath), 0, true);
  1036.   return index ? doc.SetDocPath(filepath) : false;
  1037. }
  1038.  
  1039. TView* TDocManager::InitView(TView* view)
  1040. {
  1041.   if (!view)   // test in case new TView failed
  1042.     return 0;
  1043.   return view->GetDocument().InitView(view);
  1044. }
  1045.  
  1046. TDocument* TDocManager::InitDoc(TDocTemplate& tpl, TDocument* doc,
  1047.                                 const char far* path, long flags)
  1048. {
  1049.   TDocManager* mgr = tpl.GetDocManager();
  1050.   if (!mgr || !doc)
  1051.     return 0;
  1052.   doc->SetTemplate(&tpl);
  1053.   return mgr->InitDoc(doc, path, flags);
  1054. }
  1055.  
  1056. static void Obsolete() {TRACEX(OwlDocView, 0, "Obsolete function called");}
  1057. void TDocTemplate::SetFileFilter(const char far*) {Obsolete();}
  1058. void TDocTemplate::SetDescription(const char far*){Obsolete();}
  1059. void TDocTemplate::SetDefaultExt(const char far*) {Obsolete();}
  1060.  
  1061. #endif
  1062.  
  1063.