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

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.11  $
  6. //
  7. // Implementation of class TListView
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_LISTVIEW_H)
  12. # include <owl/listview.h>
  13. #endif
  14. #if !defined(OWL_INPUTDIA_H)
  15. # include <owl/inputdia.h>
  16. #endif
  17. #include <owl/listview.rh>
  18. #include <owl/docview.rh>
  19. #include <owl/edit.rh>
  20. #include <stdio.h>
  21.  
  22. OWL_DIAGINFO;
  23. DIAG_DECLARE_GROUP(OwlDocView);        // General Doc/View diagnostic group
  24.  
  25. #if !defined(SECTION) || SECTION == 1
  26.  
  27. const char VirtualLastLineStr[] = "---";  // Last virtual line appended to list
  28.  
  29. DEFINE_RESPONSE_TABLE1(TListView, TListBox)
  30.   EV_COMMAND(CM_EDITUNDO,   CmEditUndo),
  31.   EV_COMMAND(CM_EDITCUT,    CmEditCut),
  32.   EV_COMMAND(CM_EDITCOPY,   CmEditCopy),
  33.   EV_COMMAND(CM_EDITPASTE,  CmEditPaste),
  34.   EV_COMMAND(CM_EDITCLEAR,  CmEditClear),
  35.   EV_COMMAND(CM_EDITDELETE, CmEditDelete),
  36.   EV_COMMAND(CM_EDITADD,    CmEditAdd),
  37.   EV_COMMAND(CM_EDITEDIT,   CmEditItem),
  38.   EV_WM_GETDLGCODE,
  39.   EV_NOTIFY_AT_CHILD(LBN_DBLCLK, CmEditItem),
  40.   EV_NOTIFY_AT_CHILD(LBN_SELCHANGE, CmSelChange),
  41.   EV_VN_DOCCLOSED,
  42.   EV_VN_ISWINDOW,
  43.   EV_VN_ISDIRTY,
  44.   EV_VN_COMMIT,
  45.   EV_VN_REVERT,
  46. END_RESPONSE_TABLE;
  47.  
  48. //
  49. //
  50. //
  51. TListView::TListView(TDocument& doc, TWindow* parent)
  52. :
  53.   TView(doc),
  54.   TListBox(parent, GetNextViewId(), 0,0,0,0),
  55.   Origin(0),
  56.   MaxWidth(0),
  57.   DirtyFlag(false)
  58. {
  59.   Attr.Style &= ~(LBS_SORT);
  60.   Attr.Style |= (WS_HSCROLL | LBS_NOINTEGRALHEIGHT);
  61.   Attr.AccelTable = IDA_LISTVIEW;
  62.   if (::FindResource(*GetModule(), TResId(IDM_LISTVIEW), RT_MENU))
  63.     SetViewMenu(new TMenuDescr(IDM_LISTVIEW, 0,1,0,0,0,1, GetModule()));
  64. }
  65.  
  66. //
  67. // Add a string into the view.
  68. // Return the index at which the string is added.
  69. //
  70. int
  71. TListView::AddString(const char far* str)
  72. {
  73.   long style = GetWindowLong(GWL_STYLE);
  74.   if (!(style & LBS_SORT)) {
  75.     int itemsInListBox = GetCount();
  76.     if (itemsInListBox > 0) {
  77.       // before the end of list marker
  78.       return InsertString(str, itemsInListBox-1);
  79.     }
  80.   }
  81.   return TListBox::AddString(str);
  82. }
  83.  
  84. //
  85. //
  86. //
  87. void
  88. TListView::SetExtent(const char far* str)
  89. {
  90.   int len = strlen(str);
  91.   if (len == 0)
  92.     return;
  93.  
  94.   TClientDC  clientDC(*this);
  95.   TSize extent = clientDC.GetTextExtent(str, len);
  96.   extent.cx += 2; // room for focus rectangle
  97.  
  98.   if (extent.cx > MaxWidth)
  99.     SetHorizontalExtent(MaxWidth = extent.cx);
  100. }
  101.  
  102. //
  103. //
  104. //
  105. bool
  106. TListView::VnDocClosed(int omode)
  107. {
  108.   if (DirtyFlag == 2 || !(omode & ofWrite))  // make sure someone else's write
  109.     return false;
  110.   int top = GetTopIndex();
  111.   int sel = GetSelIndex();
  112.   LoadData(top, sel);
  113.   return true;
  114. }
  115.  
  116. //
  117. //
  118. //
  119. bool
  120. TListView::LoadData(int top, int sel)
  121. {
  122.   CmEditClear();    // Clear list & remove virtual last line temporarily
  123.   DeleteString(0);
  124.  
  125.   long style = GetWindowLong(GWL_STYLE);
  126.   if (!(style & LBS_SORT))
  127.     TListBox::AddString(VirtualLastLineStr);     // Append virtual last line
  128.  
  129.   DirtyFlag = false;
  130.  
  131.   bool status;
  132.   istream* inStream;
  133.   if ((inStream = Doc->InStream(ios::in)) == 0) {
  134.     Doc->PostError(IDS_UNABLEOPEN, MB_OK);
  135.     return false;
  136.   }
  137.   for (;;) {
  138.     char buf[100+1];
  139.     inStream->getline(buf, sizeof(buf)-1);
  140.     if (!inStream->gcount() && !inStream->good()) {
  141.       status = ToBool(inStream->eof());
  142.       break;
  143.     }
  144.     AddString(buf);
  145.     SetExtent(buf);
  146.   }
  147.   SetTopIndex(top);
  148.   SetSelIndex(sel);
  149.   delete inStream;   // close file in case process switch
  150.   if (!status)
  151.     Doc->PostError(IDS_READERROR, MB_OK);
  152.   return status;
  153. }
  154.  
  155. //
  156. //
  157. //
  158. bool
  159. TListView::Create()
  160. {
  161.   TRY {
  162.     TListBox::Create();   // throws exception TWindow::TXWindow
  163.   }
  164.   CATCH( (TXOwl& x) {
  165.     Doc->PostError(IDS_NOMEMORYFORVIEW, MB_OK);
  166.     return true;   // cannot return false - throws another exception
  167.   })
  168.   if (Doc->GetDocPath() == 0) {
  169.     CmEditClear();         // perform any clearing initialization
  170.     return true;           // new file, no data to display
  171.   }
  172.   if (!LoadData(0, 0))
  173.     NotOK();
  174.   return true;
  175. }
  176.  
  177. //
  178. //
  179. //
  180. bool
  181. TListView::VnCommit(bool force)
  182. {
  183.   if (!force && !DirtyFlag)
  184.     return true;
  185.  
  186.   ostream* outStream = Doc->OutStream(ios::out);
  187.   if (outStream == 0) {
  188.     Doc->PostError(IDS_UNABLEOPEN, MB_OK);
  189.     return false;
  190.   }
  191.   outStream->seekp(Origin);
  192.   int count = GetCount();
  193.   for (int index = 0; index < count-1; index++) {  // don't write last virtual line
  194.     int len = GetStringLen(index);
  195.     char* buf = new char[len+1];
  196.     GetString(buf, index);
  197.     *outStream << buf << '\n';
  198.     delete buf;
  199.   }
  200.   DirtyFlag = 2;           // to detect our own close notification
  201.  
  202.   bool status = ToBool(outStream->good());
  203.   delete outStream;
  204.   DirtyFlag = false;
  205.   if (!status)
  206.     Doc->PostError(IDS_WRITEERROR, MB_OK);
  207.  
  208.   return status;
  209. }
  210.  
  211. //
  212. //
  213. //
  214. bool
  215. TListView::VnRevert(bool clear)
  216. {
  217.   if (!clear && Doc->GetDocPath() != 0)
  218.     return LoadData(0,0);
  219.   CmEditClear();
  220.   DirtyFlag = false;
  221.   return true;
  222. }
  223.  
  224. //
  225. //
  226. //
  227. uint
  228. TListView::EvGetDlgCode(MSG far*)
  229. {
  230.   uint retVal = (uint)DefaultProcessing();
  231.   retVal |= DLGC_WANTCHARS;
  232.   return retVal;
  233. }
  234.  
  235. //
  236. //
  237. //
  238. void
  239. TListView::CmEditUndo()
  240. {
  241.   MessageBox("Feature not implemented", "Undo", MB_OK);
  242. }
  243.  
  244. //
  245. //
  246. //
  247. void
  248. TListView::CmEditCut()
  249. {
  250.   CmEditCopy();
  251.   CmEditDelete();
  252. }
  253.  
  254. //
  255. //
  256. //
  257. void
  258. TListView::CmEditCopy()
  259. {
  260.   int index = GetSelIndex();
  261.   int count = GetCount();
  262.   if (count <= 1 || index >= count)
  263.     return;
  264.  
  265.   TClipboard cb(*this);
  266.   if (cb.EmptyClipboard()) {
  267.     int len = GetStringLen(index);
  268.     HANDLE cbhdl = ::GlobalAlloc(GHND,len+0+1);
  269.     char far* buf = (char far*)::GlobalLock(cbhdl);
  270.     GetString(buf, index);
  271.     ::GlobalUnlock(cbhdl);
  272.     cb.SetClipboardData(CF_TEXT, cbhdl);
  273.   }
  274. }
  275.  
  276. //
  277. //
  278. //
  279. void
  280. TListView::CmEditPaste()
  281. {
  282.   int index = GetSelIndex();
  283.   if (index < 0)
  284.     index = 0;
  285.  
  286.   TClipboard cb(*this);
  287.   if (!cb)
  288.     return;   // clipboard open by another program
  289.  
  290.   HANDLE cbhdl = cb.GetClipboardData(CF_TEXT);
  291.   if (cbhdl) {
  292.     char far* text = (char far*)::GlobalLock(cbhdl);
  293.     InsertString(text, index);
  294.     SetSelIndex(index+1);
  295.     DirtyFlag = true;
  296.     ::GlobalUnlock(cbhdl);
  297.   }
  298. }
  299.  
  300. //
  301. //
  302. //
  303. void
  304. TListView::CmEditDelete()
  305. {
  306.   int count = GetCount();
  307.   int index = GetSelIndex();
  308.   if (count <= 1 || index >= count-1)
  309.     return;
  310.  
  311.   DeleteString(index);
  312.   SetSelIndex(index);
  313.   DirtyFlag = true;
  314. }
  315.  
  316. //
  317. //
  318. //
  319. void
  320. TListView::CmEditClear()
  321. {
  322.   int count = GetCount();
  323.   if (count == 1)
  324.     return;
  325.   if (count) {
  326.     ClearList();
  327.     DirtyFlag = true;
  328.     SetHorizontalExtent(MaxWidth = 0);
  329.   }
  330.   long style = GetWindowLong(GWL_STYLE);
  331.   if (!(style & LBS_SORT))
  332.     TListBox::AddString(VirtualLastLineStr);
  333. }
  334.  
  335. static int linePrompt(TWindow* parent, int index, UINT id,
  336.                       char far* buf, int buflen)
  337. {
  338.   char msg[41];
  339.   sprintf(msg, parent->GetModule()->LoadString(IDS_LISTNUM).c_str(), index);
  340.   return TInputDialog(parent, msg,
  341.                       parent->GetModule()->LoadString(id).c_str(),
  342.                       buf, buflen).Execute();
  343. }
  344.  
  345. //
  346. //
  347. //
  348. void
  349. TListView::CmEditAdd()
  350. {
  351.   char inputText[101];
  352.   *inputText = 0;
  353.  
  354.   int index = GetSelIndex();
  355.   if (index < 0)
  356.     index = 0;
  357.  
  358.   if (linePrompt(this,index+1,CM_EDITADD,inputText,sizeof(inputText)) == IDOK) {
  359.     InsertString(inputText, index);
  360.     SetSelIndex(index+1);
  361.     SetExtent(inputText);
  362.     DirtyFlag = true;
  363.   }
  364. }
  365.  
  366. //
  367. //
  368. //
  369. void
  370. TListView::CmEditItem()
  371. {
  372.   int index = GetSelIndex();
  373.   int count = GetCount();
  374.  
  375.   if (index == count-1) {
  376.     CmEditAdd();
  377.     return;
  378.   }
  379.  
  380.   if (index < 0 || index >= count-1)
  381.     return;
  382.  
  383.   char inputText[101];
  384.   GetSelString(inputText, sizeof(inputText)-1);
  385.  
  386.   if (linePrompt(this,index+1,CM_EDITEDIT,inputText,sizeof(inputText))==IDOK) {
  387.     DeleteString(index);
  388.     InsertString(inputText, index);
  389.     SetExtent(inputText);
  390.     SetSelIndex(index);
  391.     DirtyFlag = true;
  392.   }
  393. }
  394.  
  395. //
  396. // To prevent interpreting as unprocessed accelerator
  397. //
  398. void
  399. TListView::CmSelChange()
  400. {
  401. }
  402.  
  403. #endif
  404. #if !defined(SECTION) || SECTION == 2
  405.  
  406. IMPLEMENT_STREAMABLE2(TListView, TListBox, TView);
  407.  
  408. #if !defined(BI_NO_OBJ_STREAMING)
  409.  
  410. //
  411. //
  412. //
  413. void*
  414. TListView::Streamer::Read(ipstream& is, uint32 /*version*/) const
  415. {
  416.   ReadBaseObject((TListBox*)GetObject(), is);
  417.   ReadBaseObject((TView*)GetObject(), is);
  418.   is >> GetObject()->Origin;
  419.   return GetObject();
  420. }
  421.  
  422. //
  423. //
  424. //
  425. void
  426. TListView::Streamer::Write(opstream &os) const
  427. {
  428.   WriteBaseObject((TListBox*)GetObject(), os);
  429.   WriteBaseObject((TView*)GetObject(), os);
  430.   os << GetObject()->Origin;
  431. }
  432.  
  433. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  434.  
  435. #endif
  436.