home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 2.ddi / TVDEMOS.ZIP / LISTDLG.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  16.7 KB  |  586 lines

  1. /*-------------------------------------------------------*/
  2. /*                                                       */
  3. /*   Turbo Vision 1.0                                    */
  4. /*   Turbo Vision Forms Demo                             */
  5. /*   Copyright (c) 1991 by Borland International         */
  6. /*                                                       */
  7. /*   Listdlg.cpp: Support source file for TVFORMS demo   */
  8. /*-------------------------------------------------------*/
  9.  
  10. #define Uses_TRect
  11. #define Uses_TSortedListBox
  12. #define Uses_TDialog
  13. #define Uses_MsgBox
  14. #define Uses_TProgram
  15. #define Uses_TScrollBar
  16. #define Uses_TButton
  17. #define Uses_TResourceFile
  18. #define Uses_TEvent
  19. #define Uses_TApplication
  20. #define Uses_TKeys
  21. #define Uses_TDeskTop
  22. #define Uses_TLabel
  23. #define Uses_fpstream
  24. #include <tv.h>
  25. __link( RResourceCollection )
  26. __link( RDialog )
  27. __link( RScrollBar )
  28.  
  29. #if !defined( __LISTDLG_H )
  30. #include "Listdlg.h"
  31. #endif  // __LISTDLG_H
  32.  
  33. #if !defined( __FORMCMDS_H )
  34. #include "Formcmds.h"
  35. #endif  // __FORMCMDS_H
  36.  
  37. #if !defined( __FORMS_H )
  38. #include "Forms.h"
  39. #endif  // __FORMS_H
  40.  
  41. #if !defined( __DATACOLL_H )
  42. #include "Datacoll.h"
  43. #endif  // __DATACOLL_H
  44.  
  45. #if !defined( __STDLIB_H )
  46. #include <stdlib.h>
  47. #endif  // __STDLIB_H
  48.  
  49. #if !defined( __STDIO_H )
  50. #include <stdio.h>
  51. #endif  // __STDIO_H
  52.  
  53. #if !defined( __STRING_H )
  54. #include <string.h>
  55. #endif  // __STRING_H
  56.  
  57. #if !defined( __DIR_H )
  58. #include <dir.h>
  59. #endif  // __DIR_H
  60.  
  61. Boolean fileExists( char *name )
  62. {
  63.     struct ffblk sr;
  64.     int ccode;
  65.  
  66.     ccode = findfirst(name, &sr, 0);
  67.     if (!ccode)
  68.         return True;
  69.     else
  70.         return False;
  71. }
  72.  
  73. // TListKeyBox
  74.  
  75. TListKeyBox::TListKeyBox(const TRect& bounds, ushort aNumCols,
  76.                   TScrollBar *aScrollBar):
  77.      TSortedListBox(bounds, aNumCols, aScrollBar)
  78. {
  79. }
  80.  
  81. void TListKeyBox::getText( char *dest, short item, short maxLen )
  82. {
  83.  
  84.     switch (((TDataCollection *)list())->keyType)
  85.         {
  86.         case stringKey:
  87.             TSortedListBox::getText(dest, item, maxLen);
  88.             break;
  89.         case longIntKey:
  90.             ltoa(*((long *)((TDataCollection *)list()->keyOf((TDataCollection *)list()->at(item)))), dest, 10);
  91.             break;
  92.         }
  93. }
  94.  
  95. // TListDialog
  96.  
  97. TListDialog::TListDialog( char *rezName, char *title) :
  98.              TDialog( TRect( 2, 2, 32, 15 ), title),
  99.          TWindowInit(&TListDialog::initFrame)
  100. {
  101.      const
  102.          buttonCt = 4,
  103.          listX = 2,
  104.          listY = 3,
  105.          formWd = 30,
  106.          formHt = 13,
  107.          defaultListWd = 12,
  108.          listHt = buttonCt * 2,
  109.          buttonWd = 12,
  110.          buttonY = listY;
  111.      TScrollBar *sb;
  112.      int y;
  113.      TForm *f;
  114.      ushort listWd;
  115.      ushort buttonX;
  116.  
  117.      modified = False;
  118.      fileName = newStr(rezName);
  119.      // Read data off resource stream
  120.      if (openDataFile(fileName, formDataFile, ios::in) == True)
  121.          {
  122.          // Get horizontal size of key field
  123.          f = (TForm *)formDataFile->get("FormDialog");
  124.          if (f == NULL)
  125.              {
  126.              messageBox("Error accessing file data.", mfError | mfOKButton);
  127.              return;
  128.              }
  129.  
  130.              // Base listbox width on key width. Grow entire dialog if required
  131.          if (f->keyWidth > defaultListWd)
  132.              {
  133.              listWd = f->keyWidth;
  134.              growTo(formWd + listWd - defaultListWd, formHt);
  135.              }
  136.          else
  137.              listWd = defaultListWd;
  138.  
  139.          // Move to upper right corner of desktop
  140.          TRect r (TProgram::deskTop->getExtent());   // Desktop coordinates
  141.          moveTo(r.b.x - size.x, 1);
  142.  
  143.          //delete f;
  144.  
  145.          // Read data collection into memory
  146.          dataCollection = (TDataCollection *)formDataFile->get("FormData");
  147.          if (dataCollection != NULL)
  148.              {
  149.              // Loaded successfully: build ListDialog dialog
  150.  
  151.              // Scrollbar
  152.              sb = new TScrollBar( TRect(listX + listWd, listY,
  153.                       listX + listWd + 1, listY + listHt));
  154.              insert(sb);
  155.  
  156.              // List box
  157.              list = new TListKeyBox( TRect(listX, listY, listX + listWd,
  158.                         listY + listHt), 1, sb);
  159.              list->newList(dataCollection);
  160.              insert(list);
  161.  
  162.              // Label
  163.              insert(new TLabel ( TRect(listX, listY - 1,
  164.                         listX + 10, listY), "~K~eys", list));
  165.  
  166.              // Buttons
  167.              buttonX = listX + listWd + 2;
  168.              y = buttonY;
  169.  
  170.              insert(new TButton (TRect(buttonX, y, buttonX + buttonWd,
  171.                         y + 2), "~E~dit", cmFormEdit, bfDefault));
  172.  
  173.              y += 2;
  174.  
  175.              insert(new TButton (TRect(buttonX, y, buttonX + buttonWd,
  176.                         y + 2), "~N~ew", cmFormNew, bfNormal));
  177.  
  178.              y += 2;
  179.              insert(new TButton (TRect(buttonX, y, buttonX + buttonWd,
  180.                         y + 2), "~D~elete", cmFormDel, bfNormal));
  181.  
  182.              y += 2;
  183.  
  184.              insert(new TButton (TRect(buttonX, y, buttonX + buttonWd,
  185.                         y + 2), "~S~ave", cmListSave, bfNormal));
  186.  
  187.              selectNext(False);      // Select first field
  188.              isValid = True;
  189.              }
  190.          }
  191. }
  192.  
  193. TListDialog::~TListDialog(void)
  194. {
  195.  
  196.     if (formDataFile != NULL)
  197.         destroy(formDataFile);
  198.     if (fileName != NULL)
  199.         delete fileName;
  200. }
  201.  
  202. void TListDialog::close(void)
  203. {
  204.     if (valid(cmClose))
  205.         {
  206.         // Stop desktop video update in case there are scores of attached forms 
  207.         TProgram::deskTop->lock();
  208.         message(TProgram::deskTop, evBroadcast, cmCloseForm, this);
  209.         TProgram::deskTop->unlock();
  210.         destroy(this);
  211.         }
  212. }
  213.  
  214. TForm *TListDialog::editingForm()
  215. {
  216.     // Return pointer to the form that is editing the current selection
  217.  
  218.     return (TForm *)message(TProgram::deskTop, evBroadcast, cmEditingForm,
  219.                             dataCollection->at(list->focused));
  220. }
  221.  
  222. void TListDialog::formOpen(Boolean newForm)
  223. {
  224.     TForm *f;
  225.  
  226.     if (!newForm)
  227.         {
  228.         // Empty collection?
  229.         if (dataCollection->getCount() == 0)
  230.             return;
  231.  
  232.         // If selection is being edited, then bring its form to top
  233.         f = editingForm();
  234.         if (f != NULL)
  235.             {
  236.             f->select();
  237.             return;
  238.             }
  239.         }
  240.  
  241.     // Selection is not being edited: open new form from the resource file
  242.     f = (TForm *) formDataFile->get("FormDialog");
  243.     if (f == NULL)
  244.         messageBox("Error opening form.", mfError | mfOKButton);
  245.     else
  246.         {
  247.         f->listDialog = this;                // Form points back to List
  248.         if (newForm)
  249.             f->prevData = NULL;               // Adding new form
  250.         else
  251.             {
  252.             // Edit data from collection
  253.             f->prevData = dataCollection->at(list->focused);
  254.             f->setData(f->prevData);
  255.             }
  256.         if (TApplication::application->validView(f) != NULL)
  257.             {
  258.             stackOnPrev(f);
  259.             TProgram::deskTop->insert(f);      // Insert & select
  260.             }
  261.         }
  262. }
  263.  
  264. void TListDialog::deleteSelection()
  265. {
  266.     TForm *f;
  267.  
  268.     // Empty collection?
  269.     if (dataCollection->getCount() == 0)
  270.         return;
  271.  
  272.     // Don't allow delete of data already being edited
  273.     f = editingForm();
  274.     if (f != NULL)
  275.         {
  276.         f->select();
  277.         messageBox("Data is already being edited. Close form before deleting.",
  278.                      mfWarning | mfOKButton);
  279.         return;
  280.         }
  281.  
  282.     // Confirm delete 
  283.     if (messageBox("Are you sure you want to delete this item?",
  284.                     mfWarning | mfYesNoCancel) == cmYes)
  285.         {
  286.         dataCollection->atFree(list->focused);
  287.         list->setRange(dataCollection->getCount());
  288.         list->drawView();
  289.         modified = True;
  290.         }
  291. }
  292.  
  293. void TListDialog::handleEvent(TEvent& event)
  294. {
  295.     if ( (event.what == evKeyDown) && (event.keyDown.keyCode == kbEsc) )
  296.          {
  297.          event.what = event.message.command;
  298.          event.message.command = cmClose;
  299.          }
  300.  
  301.     TDialog::handleEvent(event);
  302.  
  303.     switch (event.what)
  304.         {
  305.         case evCommand:
  306.             switch (event.message.command)
  307.                 {
  308.                 case cmFormEdit:
  309.                     formOpen(False);
  310.                     break;
  311.                 case cmFormNew: 
  312.                     formOpen(True);
  313.                     break;    
  314.                 case cmFormDel: 
  315.                     deleteSelection();
  316.                     break;   
  317.                 case cmListSave: 
  318.                     if (modified)
  319.                         saveList();
  320.                      break;
  321.                 default: 
  322.                     return;
  323.                 }
  324.             clearEvent(event);
  325.             break;
  326.         case evKeyDown:
  327.             switch (event.keyDown.keyCode)
  328.                 { 
  329.                 case kbIns: 
  330.                     formOpen(True);
  331.                     break;
  332.                 default: 
  333.                     return;
  334.                 }
  335.             clearEvent(event);
  336.             break;
  337.         case evBroadcast:
  338.             switch (event.message.command)
  339.                 {  // Respond to broadcast from TSortedListBox 
  340.                 case cmListItemSelected: 
  341.                     formOpen(False);
  342.                     break;
  343.  
  344.                 // Keep file from being edited simultaneously by 2 lists
  345.                 case cmEditingFile:
  346.                     if (strcmp(fileName, (char *)event.message.infoPtr) == 0)
  347.                         clearEvent(event);
  348.                     break;
  349.  
  350.                 // Respond to search for topmost list dialog
  351.                 case cmTopList:
  352.                     clearEvent(event);
  353.                     break;
  354.                 }
  355.             break;
  356.         }
  357. }
  358.  
  359. Boolean TListDialog::openDataFile( char *name,
  360.             TResourceFile *&dataFile, int mode)
  361. {
  362.     fpstream* s;
  363.  
  364.     s = new fpstream(name, mode);
  365.     dataFile = new TResourceFile(s);
  366.     if (!s->good())
  367.         {
  368.         destroy(dataFile);
  369.         dataFile = NULL;
  370.         return False;
  371.         }
  372.     else
  373.         return True;
  374. }
  375.  
  376. Boolean TListDialog::saveList()
  377. {
  378.     TResourceFile *newDataFile;
  379.     TForm *form;
  380.     char drive[MAXDRIVE];
  381.     char d[MAXDIR];
  382.     char n[MAXFILE];
  383.     char e[MAXEXT];
  384.     char bufStr[MAXPATH];
  385.     int ccode;
  386.  
  387.     // Empty collection? Unedited?
  388.     if ( (dataCollection->getCount() == 0) || (!modified) )
  389.         {
  390.         return True;
  391.         }
  392.  
  393.     //saveList = False;
  394.     // Read form definition out of original form file
  395.     form = (TForm *)formDataFile->get("FormDialog");
  396.     if (form == NULL)
  397.         messageBox("Cannot find original file. Data not saved.",
  398.              mfError | mfOKButton);
  399.     else
  400.         {
  401.         // Create new data file
  402.         fnsplit(fileName, drive, d, n, e);
  403.         sprintf(bufStr,"%s%s%s.$$$", drive, d, n);
  404.         if (openDataFile(bufStr, newDataFile, ios::out) == False)
  405.             messageBox("Cannot create file. Data not saved.",
  406.                               mfError | mfOKButton);
  407.         else
  408.             {
  409.             // Create new from form and collection in memory
  410.             newDataFile->put(form, "FormDialog");
  411.             newDataFile->put(dataCollection, "FormData");
  412.             newDataFile->flush();
  413.             destroy(newDataFile);
  414.  
  415.             // Close original file, rename to .BAK
  416.             destroy (formDataFile);
  417.             formDataFile = NULL;
  418.             sprintf(bufStr, "%s%s%s.BAK", drive, d, n);
  419.             if (fileExists(bufStr))
  420.                 ::remove(bufStr);
  421.             ccode = rename(fileName, bufStr);
  422.             // Error trying to erase old .BAK or rename original to .BAK? 
  423.             if (ccode)
  424.                 {
  425.                 messageBox("Cannot create .BAK file. Data not saved.",
  426.                      mfError | mfOKButton);
  427.  
  428.                 //Try to re-open original. New data will still be in memory
  429.                 if (openDataFile(fileName, formDataFile, ios::in) == False)
  430.                     {
  431.                     messageBox("Cannot re-open original file.",
  432.                         mfError | mfOKButton);
  433.                     destroy(this);        // Cannot proceed. Free data and close window }
  434.                     }
  435.                 }
  436.             else
  437.                 {
  438.                 // Rename temp file to original file and re-open 
  439.                 sprintf(bufStr,"%s%s%s.$$$", drive, d, n);
  440.                 rename(bufStr, fileName);
  441.                 openDataFile(fileName, formDataFile, ios::in);
  442.  
  443.                 modified = False;
  444.                 destroy(form);
  445.                 return True;
  446.                 }
  447.             }
  448.             destroy(form);
  449.         }
  450.     return False;
  451. }
  452.  
  453. Boolean TListDialog::saveForm(TDialog *f)
  454. {
  455.     ccIndex i;
  456.     void *p;
  457.  
  458.     // Validate data before updating collection
  459.     if (!f->valid(cmFormSave))
  460.       return False;
  461.  
  462.     // Extract data from form. Don't use safety pool.
  463.     p = new char[dataCollection->itemSize];
  464.     if (p == NULL)
  465.         {
  466.         TApplication::application->outOfMemory();
  467.         return False;
  468.         }
  469.  
  470.     f->getData(p);
  471.     // If no duplicates, make sure not attempting to add duplicate key
  472.     if ( (!(dataCollection->duplicates) && dataCollection->search(dataCollection->keyOf(p), i)) )
  473.         if ( (((TForm*)f)->prevData == NULL) || (((TForm *)f)->prevData != dataCollection->at(i)) )
  474.             {
  475.             delete(p);
  476.             messageBox("Duplicate keys are not allowed in this database."
  477.                        "  Delete duplicate record before saving this form.",
  478.                         mfError | mfOKButton);
  479.             return False;
  480.             }
  481.  
  482.     // Free previous data?
  483.     if (((TForm *)f)->prevData != NULL)
  484.         dataCollection->remove(((TForm*)f)->prevData);
  485.  
  486.     // TDataCollection.Insert may fail because it doesn't use
  487.     //  the safety pool. Check status field after insert and cleanup
  488.     //  if necessary.
  489.  
  490.     dataCollection->insert(p);
  491.     if (dataCollection->status != 0)
  492.         {
  493.         delete(p);
  494.         TApplication::application->outOfMemory();
  495.         return False;
  496.         }
  497.  
  498.     // Success: store off original data pointer
  499.     ((TForm *)f)->prevData = p;
  500.  
  501.     // Redraw list
  502.     list->setRange(dataCollection->getCount());
  503.     list->drawView();
  504.  
  505.     modified = True;
  506.     return True;
  507. }
  508.  
  509. void TListDialog::stackOnPrev(TDialog *f)
  510. {
  511.     TForm *topForm;
  512.  
  513.     // Stack on top topmost form or on top list if first form
  514.     topForm = (TForm *)message(owner, evBroadcast, cmTopForm, this);
  515.     if (topForm != NULL)
  516.     // Stack on top previous topmost form
  517.         f->moveTo(topForm->origin.x + 1, topForm->origin.y + 1);
  518.     else
  519.         {
  520.         // Stack right or left of ListDialog
  521.         if (origin.x > f->size.x)
  522.             f->moveTo(0, origin.y);
  523.         else
  524.             f->moveTo(origin.x + size.x + 1, origin.y);
  525.         }
  526.  
  527.     // Visible on desktop? Make sure at least half of form is visible
  528.     TRect r = owner->getExtent();                      // Desktop coordinates
  529.     if (f->origin.x + size.x / 2 > r.b.x) 
  530.         f->moveTo(0, 1);
  531.     if (f->origin.y + size.y / 2 > r.b.y)
  532.         f->moveTo(f->origin.x, 1);
  533. }
  534.  
  535. Boolean TListDialog::valid(ushort command)
  536. {
  537.     Boolean ok;
  538.     ushort reply;
  539.  
  540.     ok = True;
  541.     switch (command)
  542.         {
  543.         case cmValid:
  544.             ok = isValid;
  545.             if (!ok)
  546.                 messageBox("Error opening file (%s).",
  547.                             mfError | mfOKButton);
  548.             break;
  549.  
  550.         case cmQuit:
  551.         case cmClose:
  552.  
  553.             // Any forms open that cannot close?
  554.             if (message(TProgram::deskTop, evBroadcast, cmCanCloseForm, this) == NULL)
  555.                 ok = True;
  556.             else
  557.                 ok = False;
  558.  
  559.             // Any data modified?
  560.             if (ok && modified)
  561.                 {
  562.                 select();
  563.                 reply = messageBox("Database has been modified. Save? ",
  564.                                     mfYesNoCancel);
  565.                 switch (reply)
  566.                     {
  567.                     case cmYes:
  568.                         ok = saveList();
  569.                         break;
  570.                     case cmNo:
  571.                         modified = False;       // abandon changes
  572.                         break;
  573.                     default:
  574.                         ok = False;             // cancel close request
  575.                         break;
  576.                     }
  577.                 }
  578.             break;
  579.         }
  580.     if (ok)
  581.         return TDialog::valid(command);
  582.     else
  583.         return False;
  584. }
  585.  
  586.