home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c083 / 11.ddi / OWLSRC.PAK / DOCMANAG.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-02  |  28.3 KB  |  1,041 lines

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