home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / desklib / sources / DeskLib / !DLSources / Libraries / Save / c / Save
Encoding:
Text File  |  1995-07-08  |  15.4 KB  |  499 lines

  1. /*
  2.     ####             #    #     # #
  3.     #   #            #    #       #          The FreeWare C library for
  4.     #   #  ##   ###  #  # #     # ###             RISC OS machines
  5.     #   # #  # #     # #  #     # #  #   ___________________________________
  6.     #   # ####  ###  ##   #     # #  #
  7.     #   # #        # # #  #     # #  #    Please refer to the accompanying
  8.     ####   ### ####  #  # ##### # ###    documentation for conditions of use
  9.     ________________________________________________________________________
  10.  
  11.     File:    Save.Save.c
  12.     Author:  Copyright © 1994 Julian Smith and Jason Howat
  13.     Version: 1.02 (18 Jun 1994)
  14.     Purpose: Automated handling of save-as window
  15.     Mods:    13-Jun-1994 - JPS - Added support for filetypes
  16.              18-Jun-1994 - JDH - Changed sense of value returned by
  17.                   save_filesaver to be in line with rest of DeskLib.
  18.                   save_filsaver uses filename instead of stream.  Tidied code
  19.                   to use core routines and proper DeskLib conventions.  Added
  20.                   Save__KeyHandler to check for RETURN key in text icon.  For
  21.                   a RETURN key or OK click, added check that filename isn't
  22.                   just a leafname.  Changed Save__DragIconClickHandler to use
  23.                   Icon_StartSolidDrag.  Changed several routines to make
  24.                   messages in their own blocks -- they used to corrupt
  25.                   event_lastevent.  In Save__MessageHandler the initial
  26.                   reference check excludes unacknowledged messages that were
  27.                   returned.
  28. */
  29.  
  30. #include "DeskLib:Event.h"
  31. #include "DeskLib:WimpSWIs.h"
  32. #include "DeskLib:Icon.h"
  33. #include "DeskLib:Keycodes.h"
  34. #include "DeskLib:Error.h"
  35. #include "DeskLib:Save.h"
  36. #include "DeskLib:Str.h"
  37. #include "Desklib:File.h"
  38.  
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include <stdlib.h>
  42.  
  43.  
  44. void Save_SetFiletype(save_saveblock *saveblock, int filetype)
  45. {
  46.   saveblock->filetype = filetype;
  47.   Icon_FileIcon(saveblock->window, saveblock->dragsprite, filetype);
  48. }
  49.  
  50.  
  51.  
  52. static void Save__CleanIconText(window_handle window, icon_handle icon)
  53. /* used to clean up writable-icon text - these seem to be
  54.  * terminated by '\n', which is no use to <string.h> functions.
  55.  */
  56. {
  57.   icon_block iconblock;
  58.  
  59.   Wimp_GetIconState(window, icon, &iconblock);
  60.   Str_MakeASCIIZ(iconblock.data.indirecttext.buffer,
  61.                  iconblock.data.indirecttext.bufflen-1);
  62. }
  63.  
  64.  
  65. static void Save__ResetSaveBlock(save_saveblock *saveblock)
  66. {
  67.   saveblock->ram_progress               = 0;
  68.   saveblock->last_message_ref           = -1;
  69.   saveblock->flags.data.we_are_dragging = FALSE;
  70. }
  71.  
  72.  
  73. static BOOL Save__SaveDataToFilename(char *filename, save_saveblock *saveblock)
  74. {
  75.   BOOL save_ok;
  76.  
  77.   save_ok = saveblock->filesaver(filename, saveblock->ref);
  78.  
  79.   if(save_ok)
  80.     File_SetType(filename, saveblock->filetype);
  81.   else
  82.     saveblock->resulthandler(save_FILESAVERFAILED, saveblock);
  83.  
  84.   return save_ok;
  85. }
  86.  
  87.  
  88. static void Save__CloseMenuOrSaveWindow(save_saveblock *saveblock)
  89.   /* A save has been completed with 'Select'.
  90.    * If we were part of a menu, close menu.
  91.    * If we were a save window, close this window.
  92.    * If none of the above, our window contains other things, (it might be the
  93.    *   main document window with a 'Quick save' icon), so do nothing.
  94.    * The Event_ handlers will be released by Save_CloseHandler and
  95.    * Save_MenusDeletedHandler, so we don't release them here.
  96.    */
  97. {
  98.   if(saveblock->flags.data.is_menu)
  99.     Wimp_CreateMenu((menu_block *)-1, 0, 0);  /* close menu */
  100.  
  101.   if(saveblock->flags.data.is_save_window)
  102.     Wimp_CloseWindow(saveblock->window);      /* close window */
  103. }
  104.  
  105.  
  106. static BOOL Save__OKIconHandler(event_pollblock *event, void *ref)
  107. {
  108.   icon_block     iconblock;
  109.   save_saveblock *saveblock = (save_saveblock *)ref;
  110.   char           *filename;
  111.  
  112.   Wimp_GetIconState(saveblock->window, saveblock->filenameicon, &iconblock);
  113.   filename = iconblock.data.indirecttext.buffer;
  114.  
  115.   if(LeafName(filename) != filename)    /* not just a leafname in icon */
  116.   {
  117.     Save__SaveDataToFilename(iconblock.data.indirecttext.buffer, saveblock);
  118.     Save__ResetSaveBlock(saveblock);
  119.  
  120.     if((event->type == event_CLICK && event->data.mouse.button.data.select) ||
  121.         event->type == event_KEY)
  122.       Save__CloseMenuOrSaveWindow(saveblock);
  123.   }
  124.   else
  125.     Error_Report(0, "To save, drag the icon to a directory display");
  126.  
  127.   return TRUE;
  128. }
  129.  
  130.  
  131. static BOOL Save__KeyHandler(event_pollblock *event, void *ref)
  132. {
  133.   if(event->data.key.code == keycode_RETURN)
  134.     return Save__OKIconHandler(event, ref);
  135.  
  136.   return FALSE;
  137. }
  138.  
  139.  
  140. static BOOL Save__CancelIconHandler(event_pollblock *event, void *ref)
  141. {
  142.   UNUSED_ARG(event);
  143.  
  144.   Save__CloseMenuOrSaveWindow((save_saveblock *)ref);
  145.   return TRUE;
  146. }
  147.  
  148.  
  149. static BOOL Save__DragIconClickHandler(event_pollblock *event, void *ref)
  150. {
  151.   save_saveblock *saveblock = (save_saveblock *)ref;
  152.  
  153.   if(!event->data.mouse.button.data.dragselect &&
  154.      !event->data.mouse.button.data.dragadjust)
  155.     return FALSE;
  156.  
  157.   saveblock->flags.data.quit_after_save =
  158.                                       event->data.mouse.button.data.dragselect;
  159.  
  160.   saveblock->flags.data.we_are_dragging = TRUE;
  161.  
  162.   Icon_StartSolidDrag(saveblock->window, saveblock->dragsprite);
  163.  
  164.   return TRUE;
  165. }
  166.  
  167.  
  168. static BOOL Save__UserDragHandler(event_pollblock *event, void *ref)
  169. {
  170.   save_saveblock *saveblock = (save_saveblock *)ref;
  171.   mouse_block    ptr;
  172.   message_block  msg;
  173.  
  174.   UNUSED_ARG(event);
  175.  
  176.   /* Is the drag nothing to do with the save drag-icon? */
  177.   if(!saveblock->flags.data.we_are_dragging)
  178.     return FALSE;
  179.  
  180.   saveblock->flags.data.we_are_dragging = FALSE;
  181.  
  182.   Wimp_GetPointerInfo(&ptr);
  183.  
  184.   msg.header.size            = 80;
  185.   msg.header.yourref         = 0;
  186.   msg.header.action          = message_DATASAVE;
  187.   msg.data.datasave.window   = ptr.window;
  188.   msg.data.datasave.icon     = ptr.icon;
  189.   msg.data.datasave.pos      = ptr.pos;
  190.   msg.data.datasave.estsize  = saveblock->estimatedsize;
  191.   msg.data.datasave.filetype = saveblock->filetype;
  192.  
  193.   strcpy(msg.data.datasave.leafname,
  194.          LeafName(Icon_GetTextPtr(saveblock->window, saveblock->filenameicon)));
  195.  
  196.   Wimp_SendMessage(event_SENDWANTACK, &msg, ptr.window, ptr.icon);
  197.  
  198.   saveblock->last_message_ref = msg.header.myref;
  199.  
  200.   return TRUE;
  201. }
  202.  
  203.  
  204. static BOOL Save__MenusDeletedOrWindowClosedHandler(event_pollblock *event,
  205.                                                     void *ref)
  206. {
  207.   save_saveblock *saveblock = (save_saveblock *)ref;
  208.  
  209.   /* Don't release handlers when menu/window is closed */
  210.   if(!saveblock->flags.data.release_after)
  211.     return FALSE;
  212.  
  213.   if((event->type == event_SEND && saveblock->flags.data.is_menu &&
  214.       event->data.message.header.action == message_MENUSDELETED) ||
  215.      (event->type == event_CLOSE  && saveblock->flags.data.is_save_window))
  216.   {
  217.     Save_ReleaseSaveHandlers(ref);
  218.     free(saveblock);
  219.   }
  220.  
  221.   return FALSE;
  222. }
  223.  
  224.  
  225. static BOOL Save__MessageHandler(event_pollblock *event, void *ref)
  226. {
  227.   save_saveblock *saveblock = (save_saveblock *)ref;
  228.   message_block  *msg = &event->data.message;
  229.  
  230.   if(event->type != event_ACK &&
  231.      msg->header.yourref != saveblock->last_message_ref)
  232.     return FALSE;
  233.   /* we are only interested in replies to our previous messages...
  234.      or unacknowledged messages */
  235.  
  236.   if(msg->header.action == message_DATASAVE)
  237.   {
  238.     /* User has dragged onto useless part of the desktop...
  239.      * This could be our original message_SENDWANTACK being sent to us
  240.      * because the sprite was dragged onto one of *our task's* windows,
  241.      * or a message_ACK sent to us by the WIMP because nobody responded
  242.      * to our original message.
  243.      */
  244.  
  245.     return FALSE;  /*  the app might want to deal with this
  246.                     *  message to save into itself.
  247.                     */
  248.   }
  249.  
  250.   if(msg->header.action == message_DATASAVEACK)
  251.   {
  252.     BOOL save_ok;
  253.  
  254.     save_ok = Save__SaveDataToFilename(msg->data.datasaveack.filename,
  255.                                        saveblock);
  256.     if(save_ok)
  257.     {
  258.       message_block reply;
  259.  
  260.       memcpy(&reply, msg, sizeof(message_block));
  261.  
  262.       reply.header.action = message_DATALOAD;
  263.       reply.data.dataload.size = 49;
  264.       reply.header.yourref = reply.header.myref;
  265.  
  266.       Wimp_SendMessage(event_SENDWANTACK, &reply, reply.header.sender, 0);
  267.  
  268.       saveblock->last_message_ref = reply.header.myref;
  269.     }
  270.     else
  271.       Save__ResetSaveBlock(saveblock);
  272.  
  273.     return TRUE;
  274.   }
  275.  
  276.   if(msg->header.action == message_RAMFETCH)
  277.   {
  278.     /* If we ignore message_RAMFETCH, the receiving task should
  279.      * try again using a transfer through <Wimp$Scrap>.
  280.      */
  281.     int           byteswritten;
  282.     BOOL          last_ramtransfer;
  283.     message_block reply;
  284.  
  285.     if(saveblock->ramsaver == NULL)
  286.       return TRUE;
  287.  
  288.     byteswritten = (saveblock->ramsaver)(event_taskhandle, saveblock->ref,
  289.                                          msg->header.sender,
  290.                                          msg->data.ramfetch.buffer,
  291.                                          msg->data.ramfetch.buffsize,
  292.                                          saveblock->ram_progress);
  293.  
  294.     last_ramtransfer = byteswritten < msg->data.ramfetch.buffsize;
  295.     saveblock->ram_progress += byteswritten;
  296.  
  297.     if(byteswritten < 0)
  298.     {
  299.       (saveblock->resulthandler)(save_RAMSAVERFAILED, saveblock);
  300.       Save__ResetSaveBlock(saveblock);
  301.       return TRUE;
  302.     }
  303.  
  304.     memcpy(&reply, msg, sizeof(message_block));
  305.     reply.header.yourref = reply.header.myref;
  306.     reply.header.action  = message_RAMTRANSMIT;
  307.     reply.data.ramtransmit.byteswritten = byteswritten;
  308.  
  309.     Wimp_SendMessage((last_ramtransfer) ? event_SEND : event_SENDWANTACK,
  310.                      &reply, reply.header.sender, 0);
  311.  
  312.     saveblock->last_message_ref = reply.header.myref;
  313.  
  314.     if(last_ramtransfer)
  315.     {
  316.       Save__ResetSaveBlock(saveblock);
  317.       if(saveblock->flags.data.quit_after_save)
  318.         Save__CloseMenuOrSaveWindow(saveblock);
  319.  
  320.       (saveblock->resulthandler)(save_SAVEOK, saveblock->ref);
  321.     }
  322.  
  323.     return TRUE;
  324.   }
  325.  
  326.   if(msg->header.action == message_RAMTRANSMIT)
  327.   {
  328.     /* This is our message being returned to us by the Wimp  */
  329.     Save__ResetSaveBlock(saveblock);
  330.     (saveblock->resulthandler)(save_RECEIVERFAILED, saveblock->ref);
  331.     return TRUE;
  332.   }
  333.  
  334.   if(msg->header.action == message_DATALOADACK)
  335.   {
  336.     /* everything OK  */
  337.     Save__ResetSaveBlock(saveblock);
  338.     if(saveblock->flags.data.quit_after_save)
  339.       Save__CloseMenuOrSaveWindow(saveblock);
  340.  
  341.     (saveblock->resulthandler)(save_SAVEOK, saveblock->ref);
  342.     return TRUE;
  343.   }
  344.  
  345.   if(msg->header.action == message_DATALOAD)
  346.   {
  347.     /* This is our message being returned to us by the Wimp  */
  348.     Error_Report(0, "Received DATALOAD back - scrap file not loaded...");
  349.     Save__ResetSaveBlock(saveblock);
  350.  
  351.     (saveblock->resulthandler)(save_RECEIVERFAILED, saveblock->ref);
  352.     return TRUE;
  353.   }
  354.  
  355.   return FALSE;
  356. }
  357.  
  358.  
  359. static void Save__DefaultResultHandler(save_result result, void *ref)
  360. {
  361.   UNUSED_ARG(ref);
  362.  
  363.   switch(result)
  364.   {
  365.     case save_RECEIVERFAILED:
  366.       Error_Report(0, "Receiver failed to load scrap file");
  367.       break;
  368.  
  369.     case save_FILESAVERFAILED:
  370.       Error_Report(0, "Filer-saver failed");
  371.       break;
  372.  
  373.     case save_RAMSAVERFAILED:
  374.       Error_Report(0, "RAM-saver failed");
  375.       break;
  376.   }
  377. }
  378.  
  379.  
  380. typedef BOOL (*save_eventclaimorreleasefn)(event_type    eventtype,
  381.                                            window_handle window,
  382.                                            icon_handle   icon,
  383.                                            event_handler handler,
  384.                                            void          *reference);
  385.   /* This just defines a function pointer which can point
  386.    * to the two functions Event_Claim and Event_Release.
  387.    */
  388.  
  389.  
  390. static void Save__EventClaimOrRelease(save_saveblock *saveblock,
  391.                                       save_eventclaimorreleasefn fn)
  392. {
  393.   if(saveblock->dragsprite >= 0)
  394.   {
  395.     (fn)(event_CLICK, saveblock->window, saveblock->dragsprite,
  396.          Save__DragIconClickHandler, saveblock);
  397.  
  398.     (fn)(event_USERDRAG, event_ANY, event_ANY,
  399.          Save__UserDragHandler, saveblock);
  400.   }
  401.  
  402.   if(saveblock->okbutton >= 0)
  403.     (fn)(event_CLICK, saveblock->window, saveblock->okbutton,
  404.          Save__OKIconHandler, saveblock);
  405.  
  406.   if(saveblock->cancelbutton >= 0)
  407.     (fn)(event_CLICK, saveblock->window, saveblock->cancelbutton,
  408.          Save__CancelIconHandler, saveblock);
  409.  
  410.   (fn)(event_KEY, saveblock->window, saveblock->filenameicon,
  411.        Save__KeyHandler, saveblock);
  412.  
  413.   (fn)(event_CLOSE, saveblock->window, event_ANY,
  414.        Save__MenusDeletedOrWindowClosedHandler, saveblock);
  415.  
  416.   (fn)(event_SEND, event_ANY, event_ANY,
  417.        Save__MenusDeletedOrWindowClosedHandler, saveblock);
  418.  
  419.   /* we always want to check whether to release the handlers
  420.    * when a menu has been closed because flags.data.is_menu
  421.    * may be changed after Save_InitSaveWindowHandler
  422.    */
  423.  
  424.   (fn)(event_SEND, event_ANY, event_ANY, Save__MessageHandler, saveblock);
  425.   (fn)(event_SENDWANTACK, event_ANY, event_ANY,
  426.        Save__MessageHandler, saveblock);
  427.   (fn)(event_ACK, event_ANY, event_ANY, Save__MessageHandler, saveblock);
  428. }
  429.  
  430.  
  431.  
  432. save_saveblock *Save_InitSaveWindowHandler(window_handle      window,
  433.                                            BOOL               is_menu,
  434.                                            BOOL               is_save_window,
  435.                                            BOOL               release_after,
  436.                                            icon_handle        dragsprite,
  437.                                            icon_handle        okbutton,
  438.                                            icon_handle        cancelbutton,
  439.                                            icon_handle        filenameicon,
  440.                                            save_filesaver     filesaver,
  441.                                            save_ramsaver      ramsaver,
  442.                                            save_resulthandler resulthandler,
  443.                                            size_t             estimatedsize,
  444.                                            int                filetype,
  445.                                            void               *ref)
  446. {
  447.   save_saveblock *saveblock;
  448.  
  449.   if(!filesaver)
  450.   {
  451.     /* Must have a file-saver  */
  452.     Error_Report(0, "Save_InitSaveWindowHandler called with NULL filesaver");
  453.     return NULL;
  454.   }
  455.  
  456.   saveblock = malloc(sizeof(save_saveblock));
  457.   if(!saveblock)
  458.   {
  459.     Error_OutOfMemory(FALSE, "save window");
  460.     return NULL;
  461.   }
  462.  
  463.   saveblock->window                    = window;
  464.   saveblock->flags.data.is_menu        = is_menu;
  465.   saveblock->flags.data.is_save_window = is_save_window;
  466.   saveblock->flags.data.release_after  = release_after;
  467.   saveblock->dragsprite                = dragsprite;
  468.   saveblock->okbutton                  = okbutton;
  469.   saveblock->cancelbutton              = cancelbutton;
  470.   saveblock->filenameicon              = filenameicon;
  471.   saveblock->filesaver                 = filesaver;
  472.   saveblock->ramsaver                  = ramsaver;
  473.   saveblock->resulthandler             = resulthandler;
  474.   saveblock->estimatedsize             = estimatedsize;
  475.   saveblock->ref                       = ref;
  476.  
  477.   Save_SetFiletype(saveblock, filetype);
  478.  
  479.   Save__ResetSaveBlock(saveblock);
  480.  
  481.   if(saveblock->resulthandler == NULL)
  482.     saveblock->resulthandler = Save__DefaultResultHandler;
  483.  
  484.   Save__CleanIconText(saveblock->window, saveblock->filenameicon);
  485.   /*  Make sure the terminator of the filename is '\0' - templates
  486.    *  seem to come with a '\n' as terminator.
  487.    */
  488.  
  489.   Save__EventClaimOrRelease(saveblock, Event_Claim);
  490.  
  491.   return saveblock;
  492. }
  493.  
  494.  
  495. void Save_ReleaseSaveHandlers(save_saveblock *saveblock)
  496. {
  497.   Save__EventClaimOrRelease(saveblock, Event_Release);
  498. }
  499.