home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / owlsrc.pak / DOCVIEW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  19.9 KB  |  880 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // (C) Copyright 1993, 1994 by Borland International, All Rights Reserved
  4. //
  5. //   Implements classes TDocument, TView, TWindowView
  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.  
  14. DIAG_DECLARE_GROUP(OwlDocView);        // General Doc/View diagnostic group
  15.  
  16. #if !defined(SECTION) || SECTION == 1
  17.  
  18. const uint MinUniqueViewId = 0x8000;
  19. uint TView::NextViewId = MinUniqueViewId;
  20. int TDocument::UntitledIndex = 0;
  21.  
  22. //----------------------------------------------------------------------------
  23. //  class TDocument
  24. //
  25.  
  26. TDocument*
  27. TDocument::List::Next(const TDocument* doc)
  28. {
  29.   return doc ? doc->NextDoc : DocList;
  30. }
  31.  
  32. bool
  33. TDocument::List::Insert(TDocument* doc)
  34. {
  35.   TDocument* pdoc;
  36.   for (pdoc = DocList; pdoc; pdoc = pdoc->NextDoc)
  37.     if (pdoc == doc)
  38.       return false;
  39.   doc->NextDoc = DocList;
  40.   DocList = doc;
  41.   return true;
  42. }
  43.  
  44. bool
  45. TDocument::List::Remove(TDocument* doc)
  46. {
  47.   TDocument** ppdoc;
  48.   for (ppdoc = &DocList; *ppdoc; ppdoc = &(*ppdoc)->NextDoc) {
  49.     if (*ppdoc == doc) {
  50.       *ppdoc = doc->NextDoc;
  51.       return true;
  52.     }
  53.   }
  54.   return false;
  55. }
  56.  
  57. void
  58. TDocument::List::Destroy()
  59. {
  60.   while (DocList)
  61.     delete DocList;   // removes it entry from destructor
  62. }
  63.  
  64. TDocument::TDocument(TDocument* parent)
  65. :
  66.   ParentDoc(parent), NextDoc(0), OpenMode(0),
  67.   Title(0), Template(0), ViewList(0), Tag(0), StreamList(0),
  68.   DocPath(0), DirtyFlag(false), Embedded(false)
  69. {
  70.   if (parent) {
  71.     DocManager = parent->DocManager;
  72.     if (parent->ParentDoc == parent) {// a dummy parent
  73.       ParentDoc = 0;
  74.       DocManager->DocList.Insert(this);
  75.     }
  76.     else
  77.       parent->ChildDoc.Insert(this);
  78.   }
  79.   else {
  80.     TApplication* app = GetApplicationObject();
  81.     if ((DocManager = app->DocManager) == 0)
  82.       THROW( TXOwl(IDS_NODOCMANAGER) );  // no doc manager to catch this one
  83.     DocManager->DocList.Insert(this);
  84.   }
  85. }
  86.  
  87. TDocument::~TDocument()
  88. {
  89.   if (ParentDoc == this) // a dummy doc
  90.     return;
  91.  
  92.   ChildDoc.Destroy();    // destroy children first, otherwise unnecessary
  93.   Close();               // force close (not virtual at this point!)
  94.  
  95.   //  delete all attached views, data has already been flushed
  96.   //
  97.   SetTemplate(0);   // unref tpl, prevent self autodelete when deleting views
  98.   while (ViewList)
  99.     delete ViewList;  // ~View() calls DetachView, which removes it from list
  100.  
  101.   //  delete all streams, should only be present if abort or coding error
  102.   //
  103.   while (StreamList)
  104.     delete StreamList;
  105.  
  106.   // detach from parent and doc manager
  107.   //
  108.   if (ParentDoc) {
  109.     ParentDoc->ChildDoc.Remove(this);
  110.   }
  111.   else {
  112.     DocManager->PostEvent(dnClose, *this);
  113.     DocManager->DocList.Remove(this);
  114.   }
  115.  
  116.   delete [] Title;
  117.   delete [] DocPath;
  118. }
  119.  
  120. static char* PropNames[] = {
  121.   "Document Class",  // DocumentClass
  122.   "Template Name",   // TemplateName
  123.   "View Count",      // ViewCount
  124.   "Storage Path",    // StoragePath
  125.   "Document Title",  // DocTitle
  126. };
  127.  
  128. static int PropFlags[] = {
  129.   pfGetText|pfConstant,  // DocumentClass
  130.   pfGetText,             // TemplateName
  131.   pfGetBinary|pfGetText, // ViewCount
  132.   pfGetText|pfSettable,  // StoragePath
  133.   pfGetText|pfSettable,  // DocTitle
  134. };
  135.  
  136. const char*
  137. TDocument::PropertyName(int index)
  138. {
  139.   if (index <= PrevProperty)
  140.     return 0;
  141.   else if (index < NextProperty)
  142.     return PropNames[index-PrevProperty-1];
  143.   else
  144.     return 0;
  145. }
  146.  
  147. int
  148. TDocument::PropertyFlags(int index)
  149. {
  150.   if (index <= PrevProperty)
  151.     return 0;
  152.   else if (index < NextProperty)
  153.     return PropFlags[index-PrevProperty-1];
  154.   else
  155.     return 0;
  156. }
  157.  
  158. int
  159. TDocument::FindProperty(const char far* name)
  160. {
  161.   int i;
  162.   for (i=0; i < NextProperty-PrevProperty-1; i++)
  163.     if (strcmp(PropNames[i], name) == 0)
  164.       return i+PrevProperty+1;
  165.   return 0;
  166. }
  167.  
  168. int
  169. TDocument::GetProperty(int prop, void far* dest, int textlen)
  170. {
  171.   const char far* src;
  172.   char numBuf[6];
  173.   switch (prop) {
  174.     case DocumentClass:
  175.       src = _TYPENAME(this);
  176.       break;
  177.     case TemplateName:
  178.       src = Template ? Template->GetDescription() : 0;
  179.       break;
  180.     case ViewCount: {
  181.       int cnt;
  182.       TView* view;
  183.       for (view=ViewList, cnt=0; view != 0; view=view->NextView, cnt++) ;
  184.       if (!textlen) {
  185.         *(int far*)dest = cnt;
  186.         return sizeof(int);
  187.       }
  188.       wsprintf(numBuf, "%d", cnt);
  189.       src = numBuf;
  190.       break;
  191.     }
  192.     case StoragePath:
  193.       src = DocPath;
  194.       break;
  195.     case DocTitle:
  196.       src = Title;
  197.       break;
  198.     default:
  199.       return 0;
  200.   }
  201.   if (!textlen)
  202.     return 0;
  203.   int srclen = src ? strlen(src) : 0;
  204.   if (textlen > srclen)
  205.     textlen = srclen;
  206.   if (textlen)
  207.     memcpy(dest, src, textlen);
  208.   *((char far*)dest + textlen) = 0;
  209.   return srclen;
  210. }
  211.  
  212. bool
  213. TDocument::SetProperty(int prop, const void far* src)
  214. {
  215.   switch (prop) {
  216.     case DocTitle:
  217.       SetTitle((const char far*)src);
  218.       break;
  219.     case StoragePath:
  220.       return SetDocPath((const char far*)src);
  221.     default:
  222.       return false;
  223.   }
  224.   return true;
  225. }
  226.  
  227. TDocument&
  228. TDocument::RootDocument()
  229. {
  230.   TDocument* pdoc = this;
  231.   while (pdoc->ParentDoc)
  232.     pdoc = pdoc->ParentDoc;
  233.   return *pdoc;
  234. }
  235.  
  236. void
  237. TDocument::SetDocManager(TDocManager& dm)
  238. {
  239.   if (!ParentDoc) {
  240.     if (DocManager)  // test needed for TDocManager::Streamer::Read()
  241.       DocManager->DocList.Remove(this);
  242.     dm.DocList.Insert(this);
  243.   }
  244.   DocManager = &dm;
  245. }
  246.  
  247. bool
  248. TDocument::SetDocPath(const char far* path)
  249. {
  250.   // path has been set already
  251.   //
  252.   if (path && (path == DocPath))
  253.     return true;
  254.  
  255.   delete DocPath;
  256.   DocPath = (path && *path) ? strnewdup(path) : 0;
  257.  
  258.   char title[256];
  259.   if (!DocPath || ::GetFileTitle(DocPath, title, sizeof title) != 0) {
  260.     int len = DocManager->Application->LoadString(IDS_UNTITLED, title, sizeof title);
  261.     if (DocManager->IsFlagSet(dmMDI))
  262.       wsprintf(title+len, "%d", ++UntitledIndex);
  263.   }
  264.   SetTitle(title);
  265.   return true;  // derived classes may validate path
  266. }
  267.  
  268. void
  269. TDocument::SetTitle(const char far* title)
  270. {
  271.   delete Title;
  272.   Title = title ? strnewdup(title) : 0;
  273.   ReindexFrames();
  274. }
  275.  
  276. bool
  277. TDocument::SetTemplate(TDocTemplate* tpl)
  278. {
  279.   if (Template)
  280.     DocManager->UnRefTemplate(*Template);
  281.   if (tpl)
  282.     DocManager->RefTemplate(*tpl);
  283.   Template = tpl;
  284.   return true;
  285. }
  286.  
  287. void
  288. TDocument::ReindexFrames()
  289. {
  290.   TView* view;
  291.   int seq;
  292.  
  293.   for (seq = -1, view = ViewList; view != 0; view = view->NextView) {
  294.     seq -= view->SetDocTitle(Title, seq);  // decrement if title displayed
  295.     if (seq == -3)   // need only check if more than one title displayed
  296.       break;
  297.   }
  298.   if (seq == -1)
  299.     return;
  300.   seq = (seq == -2 ? 0 : 1);
  301.   for (view = ViewList; view != 0; view = view->NextView) {
  302.     seq += view->SetDocTitle(Title, seq);  // increment if title displayed
  303.   }
  304. }
  305.  
  306. void
  307. TDocument::AttachStream(TStream& strm)
  308. {
  309.   strm.NextStream = StreamList;
  310.   StreamList = &strm;
  311. }
  312.  
  313. void
  314. TDocument::DetachStream(TStream& strm)
  315. {
  316.   TStream** plist = &StreamList;
  317.   for ( ; *plist; plist = &(*plist)->NextStream) {
  318.     if (*plist == &strm) {
  319.       *plist = strm.NextStream;
  320.       return;
  321.     }
  322.   }
  323. }
  324.  
  325. TStream*
  326. TDocument::NextStream(const TStream* strm)
  327. {
  328.   return strm ? strm->NextStream : StreamList;
  329. }
  330.  
  331. TView*
  332. TDocument::NextView(const TView* view)
  333. {
  334.   return view ? view->NextView : ViewList;
  335. }
  336.  
  337. void
  338. TDocument::AttachView(TView& view)
  339. {
  340.   TView** ppview;
  341.  
  342.   for (ppview = &ViewList; *ppview; ppview = &(*ppview)->NextView)
  343.     ;
  344.   *ppview = &view;    // insert at end of list
  345.   view.NextView = 0;
  346.   view.Doc = this;
  347.   NotifyViews(vnViewOpened, (long)&view, &view);
  348. }
  349.  
  350. TView*
  351. TDocument::InitView(TView* view)
  352. {
  353.   if (!view)           // test if new TView failed
  354.     return 0;
  355.   if (!view->IsOK()) { // test if constructor failed
  356.     delete view;
  357.     return 0;
  358.   }
  359.   DocManager->PostEvent(dnCreate, *view);
  360.   if (!view->IsOK()) {     // if failed in creation
  361.     delete view;
  362.     return 0;
  363.   }
  364.   ReindexFrames();
  365.   if (++TView::NextViewId < MinUniqueViewId)
  366.     TView::NextViewId = MinUniqueViewId;
  367.   return view;
  368. }
  369.  
  370. bool
  371. TDocument::DetachView(TView& view)
  372. {
  373.   TView** plist = &ViewList;
  374.   for (; *plist; plist = &(*plist)->NextView) {
  375.     if (*plist == &view) {
  376.       DocManager->PostEvent(dnClose, view);
  377.       *plist = view.NextView;
  378.       NotifyViews(vnViewClosed, (long)&view, &view);
  379.       if (!ViewList) {    // all views for this doc are now gone
  380.         if (Template && (Template->Flags & dtAutoDelete)) {
  381.           if (IsOpen())
  382.             Close();     // close the document streams
  383.           return view.IsOK();   // delete doc UNLESS failure in creation
  384.         }
  385.       }
  386.       else {
  387.         ReindexFrames();
  388.       }
  389.       break;
  390.     }
  391.   }
  392.   return false;
  393. }
  394.  
  395. bool
  396. TDocument::Commit(bool force)
  397. {
  398.   TDocument* pdoc = 0;
  399.   while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
  400.     if (!pdoc->Commit(force))
  401.       return false;
  402.   }
  403.  
  404.   // should we test here for DocPath==0 , or should caller have checked?
  405.   //
  406.   return NotifyViews(vnCommit, force);
  407. }
  408.  
  409. bool
  410. TDocument::Revert(bool clear)
  411. {
  412.   TDocument* pdoc = 0;
  413.   while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
  414.     if (!pdoc->Revert(clear))
  415.       return false;
  416.   }
  417.   return NotifyViews(vnRevert, clear);
  418. }
  419.  
  420. bool
  421. TDocument::NotifyViews(int event, long item, TView* exclude)
  422. {
  423.   bool answer = true;
  424.   TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
  425.  
  426.   TDocument* pdoc = 0;
  427.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  428.     answer = ToBool(answer && pdoc->NotifyViews(event, item, exclude));
  429.  
  430.   for (TView* view = ViewList; view != 0; view = view->NextView)
  431.     if (view != exclude && view->Find(eventInfo))
  432.       answer = ToBool(answer && view->Dispatch(eventInfo, 0, item));
  433.   return answer;
  434. }
  435.  
  436. TView*
  437. TDocument::QueryViews(int event, long item, TView* exclude)
  438. {
  439.   TView* view;
  440.   TDocument* pdoc = 0;
  441.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  442.     if ((view = pdoc->QueryViews(event, item, exclude)) != 0)
  443.       return view;
  444.  
  445.   TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
  446.   for (view = ViewList; view != 0; view = view->NextView)
  447.     if (view != exclude && view->Find(eventInfo)
  448.                         && view->Dispatch(eventInfo, 0, item))
  449.       return view;    // return first acknowledger
  450.  
  451.   return 0;           // if no takers
  452. }
  453.  
  454. bool
  455. TDocument::IsDirty()
  456. {
  457.   if (DirtyFlag)
  458.     return true;
  459.  
  460.   TDocument* pdoc = 0;
  461.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  462.     if (pdoc->IsDirty())
  463.       return true;
  464.  
  465.   return QueryViews(vnIsDirty) != 0;
  466. }
  467.  
  468. bool
  469. TDocument::HasFocus(HWND hwnd)
  470. {
  471.   TDocument* pdoc = 0;
  472.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  473.     if (pdoc->HasFocus(hwnd))
  474.       return true;
  475.  
  476.   return QueryViews(vnIsWindow, (long)hwnd) != 0;
  477. }
  478.  
  479. bool
  480. TDocument::CanClose()
  481. {
  482.   TDocument* pdoc = 0;
  483.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  484.     if (!pdoc->CanClose())
  485.       return false;
  486.  
  487.   return DocManager->FlushDoc(*this);  // do the UI in the doc manager
  488. }
  489.  
  490. bool
  491. TDocument::Close()
  492. {
  493.   TDocument* pdoc = 0;
  494.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  495.     if (!pdoc->Close())
  496.       return false;
  497.  
  498.   return true;
  499. }
  500.  
  501. uint
  502. TDocument::PostError(uint sid, uint choice)
  503. {
  504.   return DocManager->PostDocError(*this, sid, choice);
  505. }
  506.  
  507. //----------------------------------------------------------------------------
  508. //  class TView
  509. //
  510.  
  511. TView::TView(TDocument& doc)
  512. :
  513.   Tag(0), ViewMenu(0)
  514. {
  515.   ViewId = NextViewId;
  516.   doc.AttachView(*this);
  517. }
  518.  
  519. TView::~TView()
  520. {
  521.   delete ViewMenu;
  522.   if (Doc->DetachView(*this)) {
  523.     delete Doc;
  524.   }
  525. }
  526.  
  527. void
  528. TView::SetViewMenu(TMenuDescr* menu)
  529. {
  530.   delete ViewMenu;
  531.   ViewMenu = menu;
  532.   TDocTemplate* tpl = Doc->GetTemplate();
  533.   if (tpl && ViewMenu && *ViewMenu->GetModule() == *tpl->GetModule())
  534.     ViewMenu->SetModule(tpl->GetModule());// force same module alias as template
  535. }
  536.  
  537. static char* TView_PropertyNames[] = {
  538.   "View Class",      // ViewClass
  539.   "View Name",       // ViewName
  540. };
  541.  
  542. static int TView_PropertyFlags[] = {
  543.   pfGetText|pfConstant,  // ViewClass
  544.   pfGetText|pfConstant,  // ViewName
  545. };
  546.  
  547. const char*
  548. TView::PropertyName(int index)
  549. {
  550.   if (index <= PrevProperty)
  551.     return 0;
  552.   else if (index < NextProperty)
  553.     return TView_PropertyNames[index-PrevProperty-1];
  554.   else
  555.     return 0;
  556. }
  557.  
  558. int
  559. TView::PropertyFlags(int index)
  560. {
  561.   if (index <= PrevProperty)
  562.     return 0;
  563.   else if (index < NextProperty)
  564.     return TView_PropertyFlags[index-PrevProperty-1];
  565.   else
  566.     return 0;
  567. }
  568.  
  569. int
  570. TView::FindProperty(const char far* name)
  571. {
  572.   int i;
  573.   for (i=0; i < NextProperty-PrevProperty-1; i++)
  574.     if (strcmp(TView_PropertyNames[i], name) == 0)
  575.       return i+PrevProperty+1;
  576.   return 0;
  577. }
  578.  
  579. int
  580. TView::GetProperty(int prop, void far* dest, int textlen)
  581. {
  582.   const char far* src;
  583.   switch (prop) {
  584.     case ViewClass:
  585.       src = _TYPENAME(this);
  586.       break;
  587.     case ViewName:
  588.       src = GetViewName();
  589.       break;
  590.     default:
  591.       return 0;
  592.   }
  593.   if (!textlen)
  594.     return 0;
  595.   int srclen = src ? strlen(src) : 0;
  596.   if (textlen > srclen)
  597.     textlen = srclen;
  598.   if (textlen)
  599.     memcpy(dest, src, textlen);
  600.   *((char far*)dest + textlen) = 0;
  601.   return srclen;
  602. }
  603.  
  604. //----------------------------------------------------------------------------
  605. //  class TWindowView
  606. //
  607.  
  608. DEFINE_RESPONSE_TABLE1(TWindowView, TWindow)
  609.   EV_VN_ISWINDOW,
  610. END_RESPONSE_TABLE;
  611.  
  612. TWindowView::TWindowView(TDocument& doc, TWindow* parent)
  613.       : TView(doc), TWindow(parent, 0, doc.GetDocManager().GetApplication())
  614. {
  615. }
  616.  
  617. //
  618. // Does a given HWND belong to this view? Yes if it is us, or a child of us
  619. //
  620. bool
  621. TWindowView::VnIsWindow(HWND hWnd)
  622. {
  623.   return hWnd == HWindow || IsChild(hWnd);
  624. }
  625.  
  626. //----------------------------------------------------------------------------
  627. //  class TDateTime (eventually)
  628. //
  629.  
  630. int _OWLFUNC FormatFileTime(FILETIME* pft, void far* dest, int textlen)
  631. {
  632.   char buf[40];
  633.   int len;
  634.  
  635.   if (!textlen) {
  636.     *(FILETIME FAR*)dest = *pft;
  637.     return sizeof(FILETIME);
  638.   }
  639. #if defined(BI_PLAT_WIN32)
  640.   SYSTEMTIME dt;
  641.   FileTimeToSystemTime(pft, &dt);
  642.   len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
  643.                  dt.wMonth, dt.wDay, dt.wYear,
  644.                  dt.wHour, dt.wMinute, dt.wSecond, dt.wMilliseconds/10);
  645. #else
  646.   struct time filet;
  647.   struct date filed;
  648.   if (!(FileTimeToDateTime(pft, &filed, &filet)))
  649.     return false;
  650.   len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
  651.                  filed.da_mon,filed.da_day,filed.da_year,
  652.                  filet.ti_hour,filet.ti_min,filet.ti_sec,filet.ti_hund);
  653. #endif
  654.   if (textlen > len)
  655.     textlen = len;
  656.   memcpy(dest, buf, textlen);
  657.   *((char far*)dest + textlen) = 0;
  658.   return len;
  659. }
  660.  
  661. #if !defined(BI_PLAT_WIN32)
  662. //
  663. // Win32/OLE2 compatible FILETIME support for 16-bit applications
  664. //    these functions to be incorporated into TDateTime class
  665. //
  666.  
  667. int FormatDateTime(struct date filed, struct time filet, void far* dest, int textlen)
  668. {
  669.   char buf[40];
  670.   if (!textlen) {
  671.     DateTimeToFileTime(&filed, &filet, (FILETIME FAR*)dest);
  672.     return sizeof(FILETIME);
  673.   }
  674.   int len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
  675.                     filed.da_mon,filed.da_day,filed.da_year,
  676.                     filet.ti_hour,filet.ti_min,filet.ti_sec,filet.ti_hund);
  677.   if (textlen > len)
  678.     textlen = len;
  679.   memcpy(dest, buf, textlen);
  680.   *((char far*)dest + textlen) = 0;
  681.   return len;
  682. }
  683.  
  684. // Convert date and time structures to 64-bit FILETIME structure
  685. //  multiply seconds by 10^7 and adjust offset to Jan. 1, 1601
  686. //  adjustment from Jan.1, 1970 = 116,444,736,000,000,000 = 0x019DB1DED53E8000
  687. //  This code is for Win32 and OLE2 compatibility when using Win16
  688.  
  689. #include <dos.h>
  690.  
  691. void DateTimeToFileTime(struct date* dosd, struct time* dost, FILETIME FAR* pft)
  692. {
  693.   union {
  694.     long udt;
  695.     int  w[2];
  696.   } u;
  697.   u.udt = dostounix(dosd, dost);
  698.   _BL = dost->ti_hund;
  699.   _AX = u.w[0];
  700.   _CX = u.w[1];
  701.   asm mov  di,200
  702.   asm mul  di
  703.   asm mov  bh,0
  704.   asm add  bx,bx
  705.   asm add  ax,bx
  706.   asm adc  dl,dh
  707.   asm xchg ax,cx
  708.   asm mov  bx,dx
  709.   asm mul  di
  710.   asm add  bx,ax
  711.   asm mov  si,0
  712.   asm adc  si,dx
  713.   asm les  di,pft
  714.   asm mov  ax,50000
  715.   asm xchg ax,cx
  716.   asm mul  cx
  717.   asm add  ax,0x8000
  718.   asm adc  dx,0
  719.   asm mov  es:[di],ax
  720.   asm xchg ax,dx
  721.   asm xchg ax,bx
  722.   asm mul  cx
  723.   asm add  ax,bx
  724.   asm adc  dx,0
  725.   asm add  ax,0xD53E
  726.   asm adc  dx,0
  727.   asm mov  es:[di+2],ax
  728.   asm xchg ax,dx
  729.   asm xchg ax,si
  730.   asm mul  cx
  731.   asm add  ax,si
  732.   asm adc  dx,0
  733.   asm add  ax,0xB1DE
  734.   asm adc  dx,0x019D
  735.   asm mov  es:[di+4],ax
  736.   asm mov  es:[di+6],dx
  737. }
  738.  
  739.  
  740. //
  741. // Convert FILETIME structure to date and time structures
  742. //
  743.  
  744. bool FileTimeToDateTime(FILETIME FAR* pft, struct date* dosd, struct time* dost)
  745. {
  746.   union {
  747.     long udt;
  748.     int  w[2];
  749.   } u;
  750.   asm les  di,pft
  751.   asm mov  dx,es:[di+6]
  752.   asm mov  ax,es:[di+4]
  753.   asm sub  ax,0xB1DE
  754.   asm sbb  dx,0x019D
  755.   asm jnc OK
  756.   return false;
  757. OK:
  758.   asm mov  cx,50000
  759.   asm div  cx
  760.   asm xchg bx,ax
  761.   asm mov  ax,es:[di+2]
  762.   asm sub  ax,0xD53E
  763.   asm sbb  dx,0
  764.   asm div  cx
  765.   asm xchg si,ax
  766.   asm mov  ax,es:[di]
  767.   asm sub  ax,(0x8000-5000)
  768.   asm sbb  dx,0
  769.   asm div  cx
  770.   asm mov  dx,bx
  771.   asm xchg ax,si
  772.   asm mov  cx,200
  773.   asm div  cx
  774.   asm xchg ax,si
  775.   asm div  cx
  776.   asm shr  dx,1
  777.   asm push dx
  778.   u.w[0] = _AX;
  779.   u.w[1] = _SI;
  780.   unixtodos(u.udt, dosd, dost);
  781.   asm pop  ax
  782.   dost->ti_hund = _AL;
  783.   return true;
  784. }
  785. #endif  // !defined(BI_PLAT_WIN32)
  786.  
  787. #endif
  788. //----------------------------------------------------------------------------
  789. #if !defined(SECTION) || SECTION == 2
  790.  
  791. IMPLEMENT_ABSTRACT_STREAMABLE(TView);
  792.  
  793. void*
  794. TView::Streamer::Read(ipstream& is, uint32 /*version*/) const
  795. {
  796.   TView* o = GetObject();
  797.   bool hasViewMenu = is.readByte();
  798.   if (hasViewMenu) {
  799.     o->ViewMenu = new TMenuDescr;
  800.     is >> *o->ViewMenu;
  801.   }
  802.   else
  803.     o->ViewMenu = 0;
  804.   is >> o->ViewId;
  805.   is >> o->Doc;
  806.   is >> o->NextView;
  807.   return o;
  808. }
  809.  
  810. void
  811. TView::Streamer::Write(opstream& os) const
  812. {
  813.   TView* o = GetObject();
  814.   os.writeByte(int16(o->ViewMenu ? 1 : 0));
  815.   if (o->ViewMenu)
  816.     os << *o->ViewMenu;
  817.   os << o->ViewId;
  818.   os << o->Doc;
  819.   os << o->NextView;
  820. }
  821.  
  822.  
  823. IMPLEMENT_ABSTRACT_STREAMABLE(TDocument);
  824.  
  825. void*
  826. TDocument::Streamer::Read(ipstream& is, uint32 /*version*/) const
  827. {
  828.   TDocument* o = GetObject();
  829.  
  830.   o->NextDoc = 0;
  831.   o->StreamList = 0;
  832.   o->DocManager = 0;
  833.   o->DirtyFlag = false;
  834.  
  835.   is >> o->OpenMode;
  836.   o->DocPath = is.freadString();
  837.   o->Title   = is.freadString();
  838.   is >> o->Template;  // static templates must have been already streamed
  839.   is >> o->ParentDoc;
  840.   o->ViewList = 0;    // must init, does not get set until after view streamed
  841.   is >> o->ViewList;
  842.   is >> TView::NextViewId;  // static, but must get set by at least 1 document
  843.  
  844.   return o;
  845. }
  846.  
  847. void
  848. TDocument::Streamer::Write(opstream& os) const
  849. {
  850.   TDocument* o = GetObject();
  851.  
  852.   while (!o->CanClose())   // can't permit cancel here
  853.     ;
  854.   os << o->OpenMode;
  855.   os.fwriteString(o->DocPath);
  856.   os.fwriteString(o->Title);
  857.   os << o->Template;       // templates already streamed, must be so if static
  858.   os << o->ParentDoc;
  859.   os << o->ViewList;       // each view streams out the next
  860.   os << TView::NextViewId; // insure that this static var gets set on reload
  861. }
  862.  
  863. IMPLEMENT_STREAMABLE2(TWindowView, TWindow, TView);
  864. void*
  865. TWindowView::Streamer::Read(ipstream& is, uint32 /*version*/) const
  866. {
  867.   ReadBaseObject((TWindow*)GetObject(), is);
  868.   ReadBaseObject((TView*)GetObject(), is);
  869.   return GetObject();
  870. }
  871.  
  872. void
  873. TWindowView::Streamer::Write(opstream& os) const
  874. {
  875.   WriteBaseObject((TWindow*)GetObject(), os);
  876.   WriteBaseObject((TView*)GetObject(), os);
  877. }
  878.  
  879. #endif
  880.