home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / docview.pak / DUMPVIEW.CPP < prev    next >
C/C++ Source or Header  |  1997-07-23  |  14KB  |  550 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1993 by Borland International
  3. //   Implements class TDumpView
  4. //----------------------------------------------------------------------------
  5. #include <owl\owlpch.h>
  6. #include <owl\docmanag.h>
  7. #include <owl\filedoc.h>
  8. #include <owl\listbox.h>
  9. #include <owl\inputdia.h>
  10. #include <owl\dc.h>
  11. #include "dumpview.rc"
  12.  
  13. struct TDumpData;
  14.  
  15. class _DOCVIEWCLASS TDumpView : public TListBox, public TView {
  16.   public:
  17.     TDumpView(TDocument& doc, TWindow* parent = 0);
  18.    ~TDumpView();
  19.     static LPCSTR StaticName() {return "Dump View";}  // put in resource
  20.  
  21.     //
  22.     // overridden virtuals from TView
  23.     //
  24.     LPCSTR   GetViewName(){return StaticName();}
  25. //    const char far*   GetViewName(){return StaticName();}
  26.     TWindow* GetWindow()  {return (TWindow*)this;}
  27.     BOOL     SetDocTitle(LPCSTR docname, int index)
  28. //    BOOL     SetDocTitle(const char far* docname, int index)
  29.                           {return TListBox::SetDocTitle(docname, index);}
  30.     //
  31.     // overridden virtuals from TWindow
  32.     //
  33.     BOOL     Create();
  34.     BOOL     CanClose()   {return TListBox::CanClose() && Doc->CanClose();}
  35.     int    MaxWidth;    // maximum horizontal extent
  36.  
  37.   protected:
  38.     long Origin;
  39.     long FileSize;
  40.     int  UpdateMode; // 0=NotEditing, 1=HighNibble, 2=LowNibble, -1=Flushing
  41.     int  CharWidth;
  42.     int  CharHeight;
  43.     int  EditByte;
  44.     int  EditLine;
  45.     TDumpData* Changes;
  46.     void Init();
  47.     BOOL LoadData(int top, int sel);
  48.     void FormatLine(int index, TDumpData* data);
  49.     BOOL NewEditLine(int line, int byte);
  50.     void EndEditLine();
  51.     void KillChanges();
  52.         
  53.   private:
  54.     //
  55.     // message response functions
  56.     //
  57.     BOOL VnCommit(BOOL force);
  58.     BOOL VnRevert(BOOL clear);
  59.     BOOL VnIsWindow(HWND hWnd) {return HWindow == hWnd;}
  60.     BOOL VnIsDirty();
  61.     BOOL VnDocClosed(int omode);
  62.     void CmEditUndo();
  63.     void CmEditItem();
  64.     void EvPaint();
  65.     void EvKeyDown(UINT key, UINT repeatCount, UINT flags);
  66.     void EvLButtonDown(UINT modKeys, TPoint& point);
  67.     void EvLButtonDblClk(UINT modKeys, TPoint& point);
  68.     void CmSelChange(){} // to prevent interpreting as unprocessed accelerator
  69.  
  70.   DECLARE_RESPONSE_TABLE(TDumpView);
  71.   DECLARE_STREAMABLE(,TDumpView,1);
  72. };
  73.  
  74. DIAG_DECLARE_GROUP(OwlDocView);        // General Doc/View diagnostic group
  75.  
  76. const int DisplayLines = 16;   // initial list box size
  77. const int ListBoxMax = 100;    // max number of lines stored in list box
  78. const int DataWidth = 8;       // number of data bytes per line
  79. const int AddrWidth = 2;       // number of bytes in address
  80. const int LineWidth = AddrWidth*2 + 1 + DataWidth*3 + DataWidth;
  81.  
  82. struct TDumpData {
  83.    long       Addr;
  84.    char       Old[DataWidth];
  85.    char       New[DataWidth];
  86.    int        Count;
  87.    TDumpData* Next;
  88. };
  89.  
  90. DEFINE_RESPONSE_TABLE1(TDumpView, TListBox)
  91.   EV_WM_KEYDOWN,
  92.   EV_COMMAND(CM_DUMPUNDO,    CmEditUndo),
  93.   EV_COMMAND(CM_DUMPEDIT,    CmEditItem),
  94.   EV_WM_PAINT,
  95.   EV_WM_LBUTTONDOWN,
  96.   EV_WM_LBUTTONDBLCLK,
  97.   EV_VN_DOCCLOSED,
  98.   EV_VN_ISWINDOW,
  99.   EV_VN_ISDIRTY,
  100.   EV_VN_COMMIT,
  101.   EV_VN_REVERT,
  102.   EV_NOTIFY_AT_CHILD(LBN_SELCHANGE, CmSelChange),
  103. END_RESPONSE_TABLE;
  104.  
  105. TDumpView::TDumpView(TDocument& doc, TWindow* parent)
  106.          : TView(doc), TListBox(parent, GetNextViewId(), 0,0,0,0)
  107. {
  108.   Init();
  109. //  Attr.Style &= ~(WS_BORDER | LBS_SORT);
  110.   Attr.Style &= ~(LBS_SORT);
  111.   Attr.Style |= LBS_DISABLENOSCROLL | LBS_NOINTEGRALHEIGHT;
  112.   Attr.AccelTable = IDA_DUMPVIEW;
  113.   SetViewMenu(new TMenuDescr(IDM_DUMPVIEW,0,1,0,0,0,1));
  114. }
  115.  
  116. void
  117. TDumpView::Init()
  118. {
  119.   Origin = 0;
  120.   UpdateMode = 0;
  121.   Changes = 0;
  122. }
  123.  
  124. BOOL
  125. TDumpView::VnDocClosed(int omode)
  126. {
  127.   if (UpdateMode == -1 || !(omode & ofWrite))  // make sure someone else's write
  128.     return FALSE;
  129.  
  130.   int top = GetTopIndex();
  131.   int sel = GetSelIndex();
  132.   ClearList();
  133.   LoadData(top, sel);
  134.   return TRUE;
  135. }
  136.  
  137. static char HexDigit(int i)
  138. {
  139.   char c = char((i & 15) + '0');
  140.   if (c > '9')
  141.     c += char('A' - ('9' + 1));
  142.   return c;
  143. }
  144.  
  145. void
  146. TDumpView::FormatLine(int line, TDumpData* data)
  147. {
  148.   char buf[LineWidth + 2];
  149.   int index;
  150.   char* pbuf;
  151.   char* pasc;
  152.   unsigned char chr;
  153.   long addr = data->Addr;
  154.  
  155.   for (index = AddrWidth*2; --index >= 0; addr >>= 4)
  156.     buf[index] = HexDigit((int)addr);
  157.   pbuf = buf + AddrWidth*2;
  158.   *pbuf++ = ' ';
  159.   pasc = pbuf + DataWidth*3;
  160.   for (index = 0; index < DataWidth; index++) {
  161.     if (index < data->Count) {
  162.       chr = data->New[index];
  163.       *pbuf++ = HexDigit(chr >> 4);
  164.       *pbuf++ = HexDigit(chr);
  165.       pasc[index] = char((chr >= 0x20 && chr < 0x7F) ? chr : 0x7F);
  166.     } else {
  167.       *pbuf++ = ' ';
  168.       *pbuf++ = ' ';
  169.       pasc[index] = ' ';
  170.     }
  171.     *pbuf++ = ' ';
  172.   }
  173.   pasc[DataWidth] = 0;  // null terminate buffer
  174.   InsertString(buf, line);
  175. }
  176.  
  177. static long GetAddr(int index)
  178. {
  179.    return index * DataWidth;
  180.    // need to add origin!
  181. }
  182.  
  183. static int GetIndex(long addr)
  184. {
  185.    return int(addr / DataWidth);
  186.    // need to subtract origin!
  187. }
  188.  
  189. BOOL
  190. TDumpView::LoadData(int top, int sel)
  191. {
  192.   TDumpData data;
  193.   istream* inStream;
  194.   int count;
  195.  
  196.   if ((inStream = Doc->InStream(ofRead | ofBinary)) == 0)
  197.     return FALSE;
  198.  
  199.   for (count=0, data.Addr=0; count<ListBoxMax; count++,data.Addr+=DataWidth) {
  200.     inStream->read(data.New, DataWidth);
  201.     if ((data.Count = inStream->gcount()) == 0)
  202.       break;
  203.     FormatLine(-1, &data);
  204.     if (data.Count != DataWidth)
  205.       break;
  206.   }
  207.   SetTopIndex(top);
  208.   SetSelIndex(sel);
  209.   delete inStream;   // close file in case process switch
  210.   return TRUE;
  211. }
  212.  
  213. BOOL
  214. TDumpView::Create()
  215. {
  216.   TRect rect;
  217.   LOGFONT fontinfo;
  218.   HGDIOBJ font = GetStockObject(SYSTEM_FIXED_FONT);
  219.   TListBox::Create();   // throws exception TXInvalidWindow
  220.   SendMessage(WM_SETFONT, (UINT)font, 0L);
  221.   GetObject(font, sizeof(LOGFONT), &fontinfo);
  222.   CharWidth  = fontinfo.lfWidth;
  223.   CharHeight = fontinfo.lfHeight;
  224.   GetClientRect(rect);   // created with 0,0 size, .right is -scroll bar size
  225.   if (rect.right < 0) {  // if new view, else streaming in presized window
  226.     rect.right = LineWidth * CharWidth + (-rect.right+2) + CharWidth/2;
  227.     rect.bottom = CharHeight * DisplayLines;
  228.     MoveWindow(rect);
  229.   //if (!Parent->IsFlagSet(wfMainWindow))// prevent parent shrink if main window
  230.       Parent->SetFlag(wfShrinkToClient);
  231.   }
  232.   if (!Doc->GetDocPath())  
  233.     return TRUE;           // new file, no data to display
  234.  
  235.   if (!LoadData(0, 0))
  236.     NotOK();
  237.   return TRUE;
  238. }
  239.  
  240. BOOL
  241. TDumpView::VnCommit(BOOL /*force*/)
  242. {
  243.   TDumpData* edit;
  244.   ostream* outStream;
  245.  
  246.   EndEditLine();
  247.   if (!Changes)
  248.     return TRUE;
  249.   if ((outStream = Doc->OutStream(ofReadWrite | ofBinary)) == 0)
  250.     return FALSE;
  251.   while ((edit = Changes) != 0) {
  252.     outStream->seekp(edit->Addr);
  253.     outStream->write(edit->New, edit->Count);
  254.     // test goodbit
  255.     Changes = Changes->Next;
  256.     delete edit;
  257.   }
  258.   UpdateMode = -1;         // to detect our own close notification
  259.   outStream->seekp(0,ios::end);
  260.   delete outStream;
  261.   return TRUE;
  262. }
  263.  
  264. BOOL
  265. TDumpView::VnRevert(BOOL clear)
  266. {
  267.   EndEditLine();
  268.   KillChanges();
  269.   ClearList();
  270.   return (!clear && Doc->GetDocPath() != 0) ? LoadData(0, 0) : TRUE;
  271. }
  272.  
  273. TDumpView::~TDumpView()
  274. {
  275.   KillChanges();
  276. }
  277.  
  278. BOOL
  279. TDumpView::NewEditLine(int line, int byte)
  280. {
  281.   istream* inStream;
  282.   TDumpData* edit;
  283.   TRect rect;
  284.   BOOL stat = TRUE;
  285.   if (line < 0)
  286.     return FALSE;
  287.   SetSelIndex(line);  // restore index in case changes
  288.   if (UpdateMode > 0) {
  289.     return FALSE;
  290.   }
  291.   if ((inStream = Doc->InStream(ofRead | ofBinary)) == 0)
  292.     return FALSE;
  293.   if ((edit = new TDumpData) == 0)
  294.     return FALSE;
  295.   edit->Addr = GetAddr(line);
  296.   inStream->seekg(edit->Addr);
  297.   // test goodbit
  298.   inStream->read(edit->Old, DataWidth);
  299.   if ((edit->Count = inStream->gcount()) > 0) {
  300.     memcpy(edit->New, edit->Old, edit->Count);
  301.     UpdateMode = 1;
  302.     GetItemRect(line, rect);
  303.     InvalidateRect(rect);
  304.     edit->Next = Changes;
  305.     Changes = edit;
  306.     while (byte >= edit->Count)
  307.       byte--;
  308.     EditByte = byte;
  309.     EditLine = line;
  310.   } else {
  311.     delete edit;
  312.     stat = FALSE;
  313.   }
  314.   delete inStream;
  315.   return stat;
  316. }
  317.  
  318. BOOL
  319. TDumpView::VnIsDirty()
  320. {
  321.   return (Changes
  322.           && (Changes->Next
  323.               || memcmp(Changes->New, Changes->Old, Changes->Count) != 0));
  324. }
  325.  
  326. void
  327. TDumpView::EndEditLine()
  328. {
  329.   TDumpData* edit = Changes;
  330.   if (UpdateMode > 0) {
  331.     TRect rect;
  332.     GetItemRect(EditLine, rect);
  333.     InvalidateRect(rect);
  334.     if (memcmp(edit->New, edit->Old, edit->Count) == 0) {
  335.       Changes = Changes->Next;
  336.       delete edit;
  337.     }
  338.   }
  339.   UpdateMode = 0;
  340. }
  341.  
  342. void
  343. TDumpView::KillChanges()
  344. {
  345.   TDumpData* edit;
  346.   while ((edit = Changes) != 0) {
  347.     Changes = Changes->Next;
  348.     delete edit;
  349.   }
  350. }
  351.  
  352. void
  353. TDumpView::EvLButtonDown(UINT modKeys, TPoint& point)
  354. {
  355.   if (UpdateMode > 0) {
  356.     int line = point.y/CharHeight + GetTopIndex();
  357.     if (line != EditLine) {
  358.       EndEditLine();
  359.       TListBox::EvLButtonDown(modKeys, point);
  360.       return;
  361.     }
  362.  
  363.     int index = ((point.x*2 - CharWidth)/(CharWidth*2) - AddrWidth*2)/3;
  364.     if (index >= 0 && index < Changes->Count) {
  365.       EditByte = index;
  366.       UpdateMode = 1;
  367.       TRect rect;
  368.       GetItemRect(EditLine, rect);
  369.       InvalidateRect(rect);
  370.     }
  371.  
  372.   } else
  373.     TListBox::EvLButtonDown(modKeys, point);
  374. }
  375.  
  376. void
  377. TDumpView::EvLButtonDblClk(UINT /*modKeys*/, TPoint& point)
  378. {
  379.   int index = ((point.x*2 - CharWidth)/(CharWidth*2) - AddrWidth*2)/3;
  380.   if (index < 0 || index >= DataWidth)
  381.     index = 0;
  382.   int line = point.y/CharHeight + GetTopIndex();
  383.   if (UpdateMode <= 0 || line != EditLine) {
  384. //    EndEditLine();
  385.     NewEditLine(line, index);
  386.   }
  387. }
  388.  
  389. void
  390. TDumpView::EvKeyDown(UINT key, UINT repeatCount, UINT flags)
  391. {
  392.   char oldchr, newchr;
  393.   MSG msg;
  394.  
  395.   if (UpdateMode <= 0) {
  396.     if (key != VK_LEFT && key != VK_RIGHT)
  397.       TListBox::EvKeyDown(key, repeatCount, flags);
  398.     return;
  399.   }
  400.   switch (key) {
  401.     case VK_ESCAPE:  // abort changes to current line
  402.       CmEditUndo();
  403.       return;
  404.  
  405.     case VK_RETURN:  // enter changes for current line, not committed yet
  406.       EndEditLine();
  407.       break;
  408.  
  409.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  410.       key += ('0' + 10) - 'A';  // fall through to digit cases
  411.     case '0': case '1': case '2': case '3': case '4':
  412.     case '5': case '6': case '7': case '8': case '9':
  413.       newchr = char(key - '0');
  414.       oldchr = Changes->New[EditByte];
  415.       ::PeekMessage(&msg, HWindow, WM_CHAR, WM_CHAR, PM_REMOVE);
  416.       switch(UpdateMode) {
  417.         case 1:
  418.           newchr = char((oldchr & 0x0F) + (newchr<<4));
  419.           break;
  420.         case 2:
  421.           newchr = char((oldchr & 0xF0) + newchr);
  422.           break;
  423.         default:
  424.           return;
  425.       } 
  426.       Changes->New[EditByte] = newchr;
  427.       DeleteString(EditLine);
  428.       FormatLine(EditLine, Changes);
  429.       SetSelIndex(EditLine);
  430.       if (UpdateMode++ == 2 && EditByte < Changes->Count-1) {
  431.         EditByte++;
  432.         UpdateMode = 1;
  433.       }
  434.       break;
  435.     case VK_UP:  
  436.     case VK_DOWN:
  437.     case VK_PRIOR:
  438.     case VK_NEXT:
  439.     case VK_END:
  440.     case VK_HOME:
  441.       if (UpdateMode > 0)
  442.         return;       
  443.       break;
  444.     case VK_LEFT:
  445.       if (UpdateMode <= 0 || EditByte == 0)
  446.         return;       
  447.       UpdateMode = 1;
  448.       EditByte--;
  449.       break;
  450.     case VK_RIGHT:
  451.       if (UpdateMode <= 0 || EditByte >= (Changes->Count-1))
  452.         return;
  453.       UpdateMode = 1;
  454.       EditByte++;
  455.       break;
  456.     default:
  457.       break;
  458.   }
  459.   TRect rect;
  460.   GetItemRect(EditLine, rect);
  461.   InvalidateRect(rect);
  462. }
  463.  
  464. void
  465. TDumpView::EvPaint()
  466. {
  467.   TRegion updateRgn;
  468.   GetUpdateRgn(updateRgn);
  469.   
  470.   DefaultProcessing();  // predefined listbox class will paint, don't call TWindow
  471.  
  472.   if (UpdateMode <= 0)
  473.     return;
  474.   if (GetSelIndex() != EditLine) {
  475.     //::MessageBeep(MB_ICONEXCLAMATION);
  476.     return;
  477.   }
  478.   if (GetTopIndex() > EditLine || (GetTopIndex()+DisplayLines) <= EditLine)
  479.     return;
  480.  
  481.   TRect rect;
  482.   GetItemRect(EditLine, rect);
  483.   rect.left += CharWidth * (AddrWidth*2+1+EditByte*3) + 1;
  484.   rect.right = rect.left + CharWidth * 2;
  485.  
  486.   // should check if in update region!
  487.   TClientDC dc(HWindow);
  488. //  dc.SelectClipRgn(updateRgn);
  489. //  dc.IntersectClipRect(rect);
  490. //  dc.InvertRgn(updateRgn);
  491.   dc.InvertRgn(updateRgn &= rect);
  492. }
  493.  
  494. void
  495. TDumpView::CmEditUndo()
  496. {
  497.   TRect rect;
  498.   TDumpData* edit;
  499.  
  500.   UpdateMode = 0;
  501.   if (!Changes)
  502.     return;
  503.   int index = GetIndex(Changes->Addr);
  504.   DeleteString(index);
  505.   memcpy(Changes->New, Changes->Old, Changes->Count);
  506.   FormatLine(index, Changes);
  507.   SetSelIndex(index);
  508.   edit = Changes;
  509.   Changes = Changes->Next;
  510.   delete edit;
  511.   GetItemRect(index, rect);
  512.   InvalidateRect(rect);
  513. }
  514.  
  515. void
  516. TDumpView::CmEditItem()
  517. {
  518.   int line = GetSelIndex();
  519.   if (UpdateMode > 0) {
  520.     if (line == EditLine)
  521.       return;
  522.     EndEditLine();
  523.   }
  524.   NewEditLine(line, 0);
  525. }
  526.  
  527. IMPLEMENT_STREAMABLE2(TDumpView, TListBox, TView);
  528.  
  529. void*
  530. TDumpView::Streamer::Read(ipstream& is, uint32 /*version*/) const
  531. {
  532.   ReadBaseObject((TListBox*)GetObject(), is);
  533.   ReadBaseObject((TView*)GetObject(), is);
  534.   is >> GetObject()->Origin;
  535.   GetObject()->Init();
  536.   return GetObject();
  537. }
  538.  
  539. void
  540. TDumpView::Streamer::Write(opstream &os) const
  541. {
  542.   WriteBaseObject((TListBox*)GetObject(), os);
  543.   WriteBaseObject((TView*)GetObject(), os);
  544.   os << GetObject()->Origin;
  545. }
  546.  
  547. DEFINE_DOC_TEMPLATE_CLASS(TFileDocument, TDumpView, DumpTemplate);
  548. DumpTemplate dumpTpl("DumpView, Binary files", "*.obj;*.res", 0, 0,
  549.                      dtAutoDelete | dtUpdateDir);
  550.