home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / DOCVIEW.PAK / XCPTVIEW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  12.1 KB  |  507 lines

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