shellundo.c

Go to the documentation of this file.
00001 
00002 /*  $Id: shellundo.c 355 2005-01-11 22:48:55Z andreradke $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #include "memory.h"
00032 #include "shell.h"
00033 #include "shellmenu.h" /*7.0fc1 PBS*/
00034 #include "shellundo.h"
00035 
00036 
00037 #define noaction 0
00038 
00039 
00040 
00041 static boolean flmultipleundo = false;
00042 
00043 hdlundostack shellundostack = nil;
00044 
00045 hdlundostack shellredostack = nil;
00046 
00047 
00048 
00049 
00050 static boolean initstack (short basesize, short elemsize, hdlstack *hstack) {
00051 
00052     /*
00053     generic handle-based stack initialization
00054     */
00055 
00056     register ptrstack ps;
00057 
00058     if (!newhandle ((long) basesize, (Handle *) hstack))
00059         return (false);
00060 
00061     ps = **hstack;
00062 
00063     ps->topstack = 0;
00064     
00065     ps->basesize = basesize;
00066     
00067     ps->elemsize = elemsize;
00068     
00069     return (true);
00070     } /*initstack*/
00071 
00072 
00073 static boolean pushstack (hdlstack hstack, ptrvoid pelem) {
00074 
00075     /*
00076     push a new element, pelem, onto the top of the handle-based 
00077     stack hstack
00078     */
00079 
00080     if (!enlargehandle ((Handle) hstack, (long) (**hstack).elemsize, pelem))
00081         return (false);
00082 
00083     ++(**hstack).topstack;
00084 
00085     return (true);
00086     } /*pushstack*/
00087 
00088 
00089 static boolean popstack (hdlstack hstack, ptrvoid pelem) {
00090 
00091     /*
00092     pop the top element off of the handle-based stack hstack, copying
00093     into pelem
00094     */
00095 
00096     register long elemsize = (**hstack).elemsize;
00097     long newsize;
00098 
00099     if (!(**hstack).topstack) /*check for empty stack*/
00100         return (false);
00101 
00102     newsize = gethandlesize ((Handle) hstack) - (long) elemsize;
00103 
00104     moveleft (* (char **) hstack + newsize, pelem, elemsize);
00105 
00106     sethandlesize ((Handle) hstack, newsize); /*should never fail; going smaller*/
00107 
00108     --(**hstack).topstack;
00109 
00110     return (true);
00111     } /*popstack*/
00112 
00113 
00114 static void swapundostacks (void) {
00115 
00116     /*
00117     redo is often identical to undo, but sometimes operates on the 
00118     opposite stacks.  swapping stacks avoids having to duplicate a lot 
00119     of code, or having to pass the current stack as a parameter everywhere
00120     
00121     12/11/90 dmb: must change fields in windowinfo too, in case undo 
00122     routines cause globals to be pushed and popped
00123     */
00124     
00125     register hdlwindowinfo hw = shellwindowinfo;
00126     hdlundostack htempstack = shellundostack;
00127     
00128     shellundostack = shellredostack;
00129     
00130     shellredostack = htempstack;
00131     
00132     /*keep true globals in sync*/
00133     
00134     (**hw).hundostack = (Handle) shellundostack;
00135     
00136     (**hw).hredostack = (Handle) shellredostack;
00137     } /*swapundostacks*/
00138 
00139 
00140 static boolean pushstep (undocallback pundo, Handle hundo, boolean flaction) {
00141 
00142     /*
00143     push a new step, defined by an undo routine and its data, onto 
00144     the undo stack.  any number of steps can accumulate to undo a 
00145     single action.  if no action is pending, just toss the undo by 
00146     calling the undo routine with flundo false
00147     */
00148     
00149     tyundorecord step;
00150     
00151     if (!shellundostack || (**shellundostack).ixaction == noaction) {
00152         
00153         (*pundo) (hundo, false);
00154         
00155         return (true);
00156         }
00157     
00158 //  assert ((**shellwindowinfo).configresnum <= idpictconfig);
00159     
00160     step.undoroutine = pundo;
00161     
00162     step.hundodata = hundo;
00163     
00164     step.flactionstep = flaction;
00165     
00166     return (pushstack ((hdlstack) shellundostack, &step));
00167     } /*pushstep*/
00168 
00169 
00170 boolean pushundostep (undocallback pundo, Handle hundo) {
00171 
00172     /*
00173     push a new step, defined by an undo routine and its data, onto 
00174     the undo stack.  any number of steps can accumulate to undo a 
00175     single action.  if no action is pending, just toss the undo by 
00176     calling the undo routine with flundo false
00177     */
00178     
00179     return (pushstep (pundo, hundo, false));
00180     } /*pushundostep*/
00181 
00182 
00183 static boolean pushactionstep (short ixaction, long globaldata) {
00184     
00185     return (pushstep ((undocallback) ((long) ixaction), (Handle) globaldata, true));
00186     } /*pushactionstep*/
00187 
00188 
00189 static boolean popundostep (tyundorecord *pstep) {
00190     
00191     /*
00192     pop the next step off of the undo stack.  this is usually done only 
00193     within the undo code (in this file), but may be called from a 
00194     higher level under certain circumstances.
00195     */
00196     
00197     return (popstack ((hdlstack) shellundostack, pstep));
00198     } /*popundostep*/
00199 
00200 
00201 static boolean pushaction (short ixaction, long globaldata) {
00202 
00203     /*
00204     start recording undos for a new action.  ixaction is a non-zero index 
00205     into a stringlist of undoable actions, used to build the menu item.
00206     
00207     to mark the juncture between the previous action steps (if any), the 
00208     index of the previous action is pushed onto the stack as a psuedo-step.
00209     */
00210     
00211     register hdlundostack hstack = shellundostack;
00212     register short ixlastaction = (**hstack).ixaction;
00213     
00214     if (!hstack)
00215         return (false);
00216     
00217     /* if previous action exists, try pushing it */
00218     
00219     if (ixlastaction != noaction  &&  !pushactionstep (ixlastaction, (**hstack).globaldata))
00220         return (false);
00221     
00222     /* set the new action */
00223     
00224     (**hstack).globaldata = globaldata;
00225     
00226     (**hstack).ixaction = ixaction;
00227     
00228     return (true);
00229     } /*pushaction*/
00230 
00231 
00232 static void killactions (void) {
00233 
00234     /*
00235     release all pending undo steps, for all actions.
00236     
00237     7/9/91 dmb: need to set up globals, but only if an undo step is actually 
00238     tossed
00239     */
00240     
00241     register hdlundostack hstack = shellundostack;
00242     register long globaldata = (**hstack).globaldata;
00243     tyundorecord step;
00244     
00245     while (popundostep (&step)) { /*pop stack until empty; ignore action records*/
00246         
00247         if (step.flactionstep)
00248             globaldata = (long) step.hundodata;
00249         
00250         else {
00251             
00252             shellsetundoglobals (globaldata, false); /*set up environment*/
00253             
00254             (*step.undoroutine) (step.hundodata, false); /*ignore errors*/
00255             }
00256         }
00257     
00258     (**hstack).ixaction = noaction;
00259     } /*killactions*/
00260 
00261 
00262 boolean pushundoaction (short ixaction) {
00263 
00264     /*
00265     start recording undos for a new action.  ixaction is a non-zero index 
00266     into a stringlist of undoable actions, used to build the menu item.
00267     
00268     any pending redo must be killed; since we're making a new change, we're 
00269     creating a new future than cannot be comingled with the old future that 
00270     was undone
00271 
00272     for single-level undo, this routine also kills any existing undo.  
00273     for multiple-level undo, subsequent undos are added to the same undo stack.
00274 
00275     7.0fc1 PBS: adjust the Undo menu item.
00276     */
00277     
00278     long globaldata;
00279     boolean res;
00280     
00281     if (shellundostack == nil)
00282         return (false);
00283     
00284     if (!flmultipleundo)
00285         killactions ();
00286     
00287     swapundostacks (); /*to redo*/
00288     
00289     killactions ();
00290     
00291     swapundostacks (); /*restore*/
00292     
00293     if ((ixaction == noaction) || !shellgetundoglobals (&globaldata))
00294         globaldata = 0L;
00295     
00296     /*return (pushaction (ixaction, globaldata));*/
00297 
00298     res = pushaction (ixaction, globaldata);
00299 
00300     shelladjustundo (); /*7.0fc1: adjust the Undo menu item.*/
00301 
00302     return (res);
00303     } /*pushundoaction*/
00304 
00305 
00306 boolean popundoaction (void) {
00307 
00308     /*
00309     remove the topmost action's steps from the undo stack, releasing the 
00310     undo by calling the undo routines with flundo false.
00311     
00312     7/9/91 dmb: need to set up globals, but only if an undo step is actually 
00313     tossed
00314     */
00315     
00316     register hdlundostack hstack = shellundostack;
00317     tyundorecord step;
00318     register short ixaction;
00319     register long globaldata;
00320     
00321     ixaction = noaction;
00322     
00323     globaldata = 0L;
00324     
00325     while (popundostep (&step)) { /*pop stack until empty; ignore action records*/
00326     
00327         if (step.flactionstep) { /*new action record; finished with this undo*/
00328             
00329             ixaction = (short) ((long) step.undoroutine);
00330             
00331             globaldata = (long) step.hundodata;
00332             
00333             break;
00334             }
00335         
00336         shellsetundoglobals ((**hstack).globaldata, false); /*set up environment*/
00337         
00338         (*step.undoroutine) (step.hundodata, false); /*ignore errors*/
00339         }
00340     
00341     (**hstack).ixaction = ixaction; /*update current action*/
00342     
00343     (**hstack).globaldata = globaldata;
00344     
00345     return (true);
00346     } /*popundoaction*/
00347 
00348 
00349 boolean undolastaction (boolean flbuildredo) {
00350     
00351     register hdlundostack hstack = shellundostack;
00352     register short ixaction;
00353     register long globaldata;
00354     tyundorecord step;
00355     
00356     ixaction = (**hstack).ixaction;
00357     
00358     if (ixaction == noaction)
00359         return (false); /*nothing to undo*/
00360     
00361     globaldata = (**hstack).globaldata;
00362     
00363     swapundostacks ();
00364     
00365     if (flbuildredo)
00366         pushaction (ixaction, globaldata);
00367     else
00368         pushaction (noaction, 0L);
00369     
00370     swapundostacks ();
00371     
00372     shellsetundoglobals (globaldata, true); /*set up environment, as required*/
00373     
00374     ixaction = noaction; /*default if new action isn't found*/
00375     
00376     globaldata = 0L;
00377     
00378     while (popundostep (&step)) { /*pop stack until empty or action record is found*/
00379     
00380         if (step.flactionstep) { /*new action record; finished with this undo*/
00381             
00382             ixaction = (short) ((long) step.undoroutine);
00383             
00384             globaldata = (long) step.hundodata;
00385             
00386             break;
00387             }
00388         
00389         swapundostacks ();
00390         
00391         (*step.undoroutine) (step.hundodata, true); /*xxx error checking here*/
00392         
00393         swapundostacks ();  
00394         }
00395     
00396     (**hstack).ixaction = ixaction; /*update current action*/
00397     
00398     (**hstack).globaldata = globaldata; /*update current action*/
00399     
00400     return (true); /*xxx*/
00401     } /*undolastaction*/
00402 
00403 
00404 boolean redolastaction (boolean flbuildundo) {
00405 
00406     swapundostacks ();
00407 
00408     undolastaction (flbuildundo);
00409 
00410     swapundostacks ();
00411     
00412     return (true);
00413     } /*redolastaction*/
00414 
00415 
00416 boolean getundoaction (short *ixaction) {
00417 
00418     *ixaction = (**shellundostack).ixaction;
00419     
00420     return (*ixaction != noaction);
00421     } /*getundoaction*/
00422 
00423 
00424 boolean getredoaction (short *ixaction) {
00425 
00426     *ixaction = (**shellredostack).ixaction;
00427     
00428     return (*ixaction != noaction);
00429     } /*getredoaction*/
00430 
00431 
00432 void killundo (void) {
00433 
00434     /*
00435     release all pending undo and redo steps, for all actions.
00436     */
00437     
00438     killactions (); /*kill undo*/
00439     
00440     swapundostacks ();
00441     
00442     killactions (); /*kill redo*/
00443     
00444     swapundostacks ();
00445     } /*killundo*/
00446 
00447 
00448 boolean newundostack (hdlundostack *hstack) {
00449 
00450     if (!initstack (sizeof (tyundostack), sizeof (tyundorecord), (hdlstack *) hstack))
00451         return (false);
00452     
00453     (***hstack).ixaction = noaction;
00454     
00455     return (true);
00456     } /*newundostack*/
00457 
00458 
00459 boolean disposeundostack (hdlundostack hstack) {
00460     
00461     #ifdef fldebug
00462     
00463     if (hstack != nil)
00464         assert ((**hstack).ixaction == noaction);
00465     
00466     #endif
00467     
00468     disposehandle ((Handle) hstack);
00469     
00470     return (true);
00471     } /*disposeundostack*/
00472 
00473 
00474 void initundo (void) {
00475     
00476     /*
00477     newundostack (&shellundostack);
00478     
00479     newundostack (&shellredostack);
00480     */
00481     } /*initundo*/
00482 
00483 

Generated on Wed May 31 18:20:01 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6