home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c083 / 20.ddi / DOCVIEW.PAK / XCPTVIEW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-02  |  11.9 KB  |  485 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1993 by Borland International
  3. //   Implements class TExceptionView
  4. //----------------------------------------------------------------------------
  5. #include <owl\owlpch.h>
  6. #include <owl\docmanag.h>
  7. #include "xcptview.rc"
  8. #include <owl\docview.rc>
  9. #include <owl\inputdia.h>
  10. #include <owl\compat.h>
  11. #include <owl\listbox.h>
  12. #include <owl\filedoc.h>
  13. #include "xcptview.rc"
  14.  
  15. class XVLink;
  16.  
  17. class _DOCVIEWCLASS TExceptionView : public TListBox, public TView {
  18.   public:
  19.     TExceptionView(TDocument& doc, TWindow* parent = 0);
  20.    ~TExceptionView();
  21.     static LPCSTR StaticName() {return "Exception Log";}  // put in resource
  22.     BOOL DirtyFlag;
  23.     int CurIndex;
  24.     void LogThrow(char* str);
  25.     void Annotate(int index, char chr, BOOL cache = FALSE);
  26.  
  27.     //
  28.     // overridden virtuals from TView
  29.     //
  30.     LPCSTR   GetViewName(){return StaticName();}
  31.     TWindow* GetWindow()  {return (TWindow*)this;}
  32.     BOOL     SetDocTitle(LPCSTR docname, int index)
  33.                           {return TListBox::SetDocTitle(docname, index); }
  34.     //
  35.     // overridden virtuals from TWindow
  36.     //
  37.     BOOL CanClose()   {return TListBox::CanClose() && Doc->CanClose();}
  38.     BOOL Create();
  39.  
  40.   protected:
  41.     long Origin;
  42.     int  MaxWidth;    // maximum horizontal extent
  43.     XVLink* Link;
  44.     char Cache;
  45.     unexpected_function OldUnexpectedHandler;
  46.     void Init();
  47.     void SetExtent(LPSTR str);
  48.     BOOL LoadData(int top, int sel);
  49.     //
  50.     // message response functions
  51.     //
  52.     BOOL VnDocClosed(int omode);
  53.     BOOL VnCommit(BOOL force);
  54.     BOOL VnRevert(BOOL clear);
  55.     BOOL VnIsWindow(HWND hWnd) {return HWindow == hWnd;}
  56.     BOOL VnIsDirty()       {return DirtyFlag;}
  57.     void CmSelChange(){} // to prevent interpreting as unprocessed accelerator
  58.     void CmTXOwl();
  59.     void CmTXTest();
  60.     void CmTXComp();
  61.     void CmTXMem();
  62.     void CmXalloc();
  63.     void CmXmsg();
  64.     void CmForeign();
  65.     void CmUnexpected() throw (xalloc);
  66.     void CmBadCast();
  67.     void CmBadTypeid();
  68.     void CmOwlSend();
  69.     void CmClear();
  70.     void EvTimeChange();
  71.   DECLARE_RESPONSE_TABLE(TExceptionView);
  72.   DECLARE_STREAMABLE(,TExceptionView,1);
  73. };
  74.  
  75. class XVLink{  // access class to prevent calling deleted view
  76.   public:
  77.     XVLink(TExceptionView* view) : View(view), RefCnt(1), Suspended(FALSE) {}
  78.     TExceptionView* View;
  79.     int RefCnt;
  80.     BOOL Suspended;
  81.     void Annotate(int index, char chr)
  82.       {if (View) View->Annotate(index, chr, Suspended);}
  83.     void AddRef() {RefCnt++;}
  84.     void SubRef() {if (--RefCnt == 0) delete this;}
  85. };
  86.  
  87. class TXTest : public TXOwl {
  88.   public:
  89.     TXTest(UINT resId, XVLink* view, int index);
  90.     TXTest(const TXTest&);
  91.     const TXTest& operator = (const TXTest&);
  92.    ~TXTest();
  93.     TXOwl* Clone();
  94.     void Throw();
  95.     int Unhandled(TModule* app, unsigned promptResId);
  96.     XVLink* View;
  97.     int Index;
  98. };
  99.  
  100. DEFINE_RESPONSE_TABLE1(TExceptionView, TListBox)
  101.   EV_COMMAND(CM_TXOWL,      CmTXOwl),
  102.   EV_COMMAND(CM_TXTEST,     CmTXTest),
  103.   EV_COMMAND(CM_TXCOMP,     CmTXComp),
  104.   EV_COMMAND(CM_TXMEM,      CmTXMem),
  105.   EV_COMMAND(CM_XALLOC,     CmXalloc),
  106.   EV_COMMAND(CM_XMSG,       CmXmsg),
  107.   EV_COMMAND(CM_FOREIGN,    CmForeign),
  108.   EV_COMMAND(CM_UNEXPECTED, CmUnexpected),
  109.   EV_COMMAND(CM_BADCAST,    CmBadCast),
  110.   EV_COMMAND(CM_BADTYPEID,  CmBadTypeid),
  111.   EV_COMMAND(CM_OWLSEND,    CmOwlSend),
  112.   EV_COMMAND(CM_XCLEAR,     CmClear),
  113.   EV_NOTIFY_AT_CHILD(LBN_SELCHANGE, CmSelChange),
  114.   EV_VN_DOCCLOSED,
  115.   EV_VN_ISWINDOW,
  116.   EV_VN_ISDIRTY,
  117.   EV_VN_COMMIT,
  118.   EV_VN_REVERT,
  119.   EV_WM_TIMECHANGE,
  120. END_RESPONSE_TABLE;
  121.  
  122. void XUnexpectedHandler()
  123. {
  124.   throw xmsg(string(*::Module,XM_UNEXPECTED));
  125. }
  126.  
  127. TExceptionView::TExceptionView(TDocument& doc, TWindow* parent)
  128.    : TView(doc), TListBox(parent, GetNextViewId(), 0,0,0,0),
  129.      Origin(0), MaxWidth(0)
  130. {
  131.   Attr.Style &= ~(WS_BORDER | LBS_SORT);
  132.   Attr.Style |= (WS_HSCROLL | LBS_NOINTEGRALHEIGHT);
  133.   Attr.AccelTable = IDA_XCPTVIEW;
  134.   SetViewMenu(new TMenuDescr(IDM_XCPTVIEW,0,2,0,0,0,1));
  135.   Init();
  136. }
  137.  
  138. void TExceptionView::Init()
  139. {
  140.   Link = new XVLink(this);
  141.   OldUnexpectedHandler = set_unexpected(XUnexpectedHandler);
  142.   DirtyFlag = FALSE;
  143.   Cache = 0;
  144. }
  145.  
  146. TExceptionView::~TExceptionView()
  147. {
  148.   Link->View = 0;  // prevent calling into destructed view
  149.   Link->SubRef();  // will destruct when no outstanding exceptions
  150.   set_unexpected(OldUnexpectedHandler);
  151. }
  152.  
  153. struct XTest {  // class with destructor for testing TPointer
  154.   char* P;
  155.   XTest() {P = new char[4];}
  156.   virtual ~XTest();     // non inline to allow breakpoint set
  157. };
  158. XTest::~XTest(){delete P;}
  159.  
  160. struct XTestD : public XTest {  // class derived from XTest
  161.   XTestD() : XTest(), Q(0) {}
  162.   char* Q;
  163.  ~XTestD() {delete Q;}
  164. };
  165.  
  166. static ThrowTXOwl()  // extra call level to allow TPointer testing
  167. {
  168.   throw TXOwl(XM_TXOWL);
  169. }
  170.  
  171. void TExceptionView::CmTXOwl()
  172. {
  173.   TPointer<char> ptr = new char[20];
  174.   ptr[0] = 0;
  175.   TPointer<XTest> x;
  176.   x = new XTest();
  177.   LogThrow("TXOwl thrown");
  178.   XTest* xt = new XTestD();
  179.   delete xt;
  180.   ThrowTXOwl();
  181.   delete &x;
  182. }
  183.  
  184. void TExceptionView::CmTXTest()
  185. {
  186.   LogThrow("TXTest thrown");
  187.   throw TXTest(XM_TXTEST, Link, CurIndex);
  188. }
  189.  
  190. void TExceptionView::CmTXComp()
  191. {
  192.   LogThrow("TXCompatibility throw by setting Status");
  193.   Status = EM_INVALIDWINDOW;
  194. }
  195.  
  196. void TExceptionView::CmTXMem()
  197. {
  198.   LogThrow("TXOutOfMemory thrown");
  199.   throw TXOutOfMemory();
  200. }
  201.  
  202. void TExceptionView::CmXalloc()
  203. {
  204.   LogThrow("xalloc thrown");
  205.   throw xalloc(string(*::Module,XM_XALLOC),1234);
  206. }
  207.  
  208. void TExceptionView::CmXmsg()
  209. {
  210.   LogThrow("xmsg thrown");
  211.   throw xmsg(string(*::Module,XM_XMSG));
  212. }
  213.  
  214. void TExceptionView::CmForeign()
  215. {
  216.   LogThrow("int thrown");
  217.   throw (int)35;
  218. }
  219.  
  220. void TExceptionView::CmUnexpected() throw (xalloc)
  221. {
  222.   LogThrow("Unexpected xmsg thrown");
  223.   throw xmsg(string(*::Module,XM_UNEXPECTED));
  224. }
  225.  
  226. static xmsg* XVRef(xmsg&) {return 0;}
  227.  
  228. void TExceptionView::CmBadCast()
  229. {
  230.   LogThrow("Failed dynamic_cast<>");
  231.   XVRef(dynamic_cast<xmsg&>(*this));
  232. }
  233.  
  234. void TExceptionView::CmBadTypeid()
  235. {
  236.   LogThrow("type_id() called on invalid object");
  237.   class __rtti C {int i; virtual ~C(){}};
  238.   C* o = 0;
  239.   static const char* n;
  240.   n = typeid(*o).name();
  241. }
  242.  
  243. void TExceptionView::CmOwlSend()
  244. {
  245.   ::SendMessage(HWindow, WM_TIMECHANGE,0,0); // any strange message will do
  246.   GetApplication()->ResumeThrow();
  247. }
  248.  
  249. void TExceptionView::EvTimeChange()
  250. {
  251.   LogThrow("TXTest thrown from event handler");
  252.   throw TXTest(XM_OWLSEND, Link, CurIndex);
  253. }
  254.  
  255. void TExceptionView::CmClear()
  256. {
  257.   ClearList();
  258.   DirtyFlag = FALSE;
  259.   SetHorizontalExtent(MaxWidth = 0);
  260. }
  261.  
  262. void TExceptionView::LogThrow(char* str)
  263. {
  264.   SetSelIndex(CurIndex = AddString(str));
  265.   SetExtent(str);
  266.   DirtyFlag = TRUE;
  267. }
  268.  
  269. void TExceptionView::Annotate(int index, char chr, BOOL cache)
  270. {
  271.   if (Cache) {  // check if character logged during exception processing
  272.     char chr = Cache;
  273.     Cache = 0;
  274.     Annotate(index, chr);  // we assume here we're still at the same index
  275.   }
  276.   if (cache && chr == '~') {  // check if in destructor with cloned exception
  277.     Cache = chr;
  278.     return;
  279.   }
  280.   char buf[100];
  281.   int len = GetStringLen(index);
  282.   GetString(buf, index);
  283.   buf[len]   = ' ';
  284.   buf[len+1] = chr;
  285.   buf[len+2] = 0;
  286.   DeleteString(index);
  287.   InsertString(buf, index);
  288.   SetSelIndex(index);
  289. }
  290.  
  291. void TExceptionView::SetExtent(LPSTR str)
  292. {
  293.   HDC hdc;
  294.   int len;
  295.   TSize extent;
  296.   if ((len = strlen(str)) == 0)
  297.     return;
  298.   hdc = ::GetDC(HWindow);
  299.   ::GetTextExtentPoint(hdc, str, len, &extent);
  300.   extent.cx += 2; // room for focus rectangle
  301.  
  302.   if (extent.cx > MaxWidth){
  303.     SetHorizontalExtent(MaxWidth = extent.cx);
  304.   }
  305.   ::ReleaseDC(HWindow, hdc);
  306. }
  307.  
  308. BOOL TExceptionView::VnDocClosed(int omode)
  309. {
  310.   int top;
  311.   int sel;
  312.   if (DirtyFlag == 2 || !(omode & ofWrite))  // make sure someone else's write
  313.     return FALSE;
  314.   top = GetTopIndex();
  315.   sel = GetSelIndex();
  316.   LoadData(top, sel);
  317.   return TRUE;
  318. }
  319.  
  320. BOOL TExceptionView::LoadData(int top, int sel)
  321. {
  322.   char buf[100+1];
  323.   istream* inStream;
  324.   BOOL status = TRUE;
  325.  
  326.   CmClear();
  327.   DirtyFlag = FALSE;
  328.   if ((inStream = Doc->InStream(ios::in)) == 0) {
  329.     Doc->PostError(IDS_UNABLEOPEN, MB_OK);
  330.     return FALSE;
  331.   }
  332.   for (;;) {
  333.     inStream->getline(buf, sizeof(buf)-1);
  334.     if (!inStream->gcount() && !inStream->good()) {
  335.       status = inStream->eof();
  336.       break;
  337.     }
  338.     AddString(buf);
  339.     SetExtent(buf);
  340.   }
  341.   SetTopIndex(top);
  342.   SetSelIndex(sel);
  343.   delete inStream;   // close file in case process switch
  344.   if (!status)
  345.     Doc->PostError(IDS_READERROR, MB_OK);
  346.   return status;
  347. }
  348.  
  349. BOOL TExceptionView::Create()
  350. {
  351.   try {
  352.     TListBox::Create();   // throws exception TWindow::TXWindow
  353.   }
  354.   catch (TXOwl& x) {
  355.     Doc->PostError(IDS_NOMEMORYFORVIEW, MB_OK);
  356.     return TRUE;   // cannot return FALSE - throws another exception
  357.   }
  358.   if (Doc->GetDocPath() == 0) {  
  359.     return TRUE;           // new file, no data to display
  360.   }
  361.   if (!LoadData(0, 0))
  362.     NotOK();
  363.   return TRUE;
  364. }
  365.  
  366. BOOL TExceptionView::VnCommit(BOOL force)
  367. {
  368.   int count;
  369.   int index;
  370.   int len;
  371.   char* buf;
  372.   ostream* outStream;
  373.   BOOL status;
  374.  
  375.   if (!force && !DirtyFlag)
  376.     return TRUE;
  377.   if ((outStream = Doc->OutStream(ios::out)) == 0) {
  378.     Doc->PostError(IDS_UNABLEOPEN, MB_OK);
  379.     return FALSE;
  380.   }
  381.   outStream->seekp(Origin);
  382.   count = GetCount();
  383.   for (index = 0; index < count; index++) {
  384.     len = GetStringLen(index);
  385.     buf = new char[len+1];
  386.     GetString(buf, index);
  387.     *outStream << buf << '\n';
  388.     delete buf;
  389.   }
  390.   DirtyFlag = 2;           // to detect our own close notification
  391.   status = outStream->good();
  392.   delete outStream;
  393.   DirtyFlag = FALSE;
  394.   if (!status)
  395.     Doc->PostError(IDS_WRITEERROR, MB_OK);
  396.   return status;
  397. }
  398.  
  399. BOOL TExceptionView::VnRevert(BOOL clear)
  400. {
  401.   if (!clear && Doc->GetDocPath() != 0)
  402.     return LoadData(0,0);
  403.   CmClear();
  404.   return TRUE;
  405. }
  406.  
  407. // Exception class for monitoring exception progress
  408.  
  409. TXTest::TXTest(UINT resId, XVLink* view, int index)
  410.        : TXOwl(resId), View(view), Index(index)
  411. {
  412.   View->AddRef();
  413.   View->Annotate(Index, '#');
  414. }
  415.  
  416. TXTest::TXTest(const TXTest& s) : TXOwl(s), View(s.View),Index(s.Index)
  417. {
  418.   View->AddRef();
  419.   View->Annotate(Index, '+');
  420. }
  421.  
  422. TXTest::~TXTest()
  423. {
  424. // We cannot do any action here that would cause an exeption to be thrown
  425. // since this object may have just been caught and cloned, a call involving
  426. // messaging through windows would cause the cloned exception to be rethrown
  427.   View->Annotate(Index, '~');
  428.   View->SubRef();
  429. }
  430.  
  431. const TXTest& TXTest::operator = (const TXTest& src)
  432. {
  433.   *(TXOwl*)this = src;
  434.   View = src.View;   
  435.   Index = src.Index;
  436.   View->AddRef();
  437.   View->Annotate(Index, '=');
  438.   return *this;
  439. }
  440.  
  441. TXOwl* TXTest::Clone()
  442. {
  443.   View->Suspended = TRUE;  // prevent rethrow during logging Windows call
  444.   View->Annotate(Index, '&');
  445.   return new TXTest(*this);  // will do the AddRef
  446. }
  447.  
  448. void TXTest::Throw()
  449. {
  450.   View->Suspended = FALSE;
  451.   View->Annotate(Index, '!');
  452.   throw *this;
  453. }
  454.  
  455. int TXTest::Unhandled(TModule* app, unsigned promptResId)
  456. {
  457.   View->Annotate(Index, '?');
  458.   return TXOwl::Unhandled(app, promptResId);
  459. }
  460.  
  461. IMPLEMENT_STREAMABLE2(TExceptionView, TListBox, TView);
  462.  
  463. void* TExceptionView::Streamer::Read(ipstream& is, uint32 /*version*/) const
  464. {
  465.   TExceptionView* o = GetObject();
  466.   ReadBaseObject((TListBox*)o, is);
  467.   ReadBaseObject((TView*)o, is);
  468.   o->Init();
  469.   is >> o->Origin;
  470.   is >> o->MaxWidth;
  471.   return o;
  472. }
  473.  
  474. void TExceptionView::Streamer::Write(opstream &os) const
  475. {
  476.   WriteBaseObject((TListBox*)GetObject(), os);
  477.   WriteBaseObject((TView*)GetObject(), os);
  478.   os << GetObject()->Origin;
  479.   os << GetObject()->MaxWidth;
  480. }
  481.  
  482. DEFINE_DOC_TEMPLATE_CLASS(TFileDocument, TExceptionView, XcptTemplate);
  483. XcptTemplate xcptTpl("Exception Log File","*.xlg", 0, "XLG",dtAutoDelete|dtUpdateDir);
  484.  
  485.