opstructure.c

Go to the documentation of this file.
00001 
00002 /*  $Id: opstructure.c 1260 2006-04-13 06:13:10Z sethdill $    */
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 "quickdraw.h"
00032 #include "memory.h"
00033 #include "strings.h"
00034 #include "scrap.h"
00035 #include "cursor.h"
00036 #include "kb.h"
00037 #include "ops.h"
00038 #include "search.h"
00039 #include "shellundo.h"
00040 #include "shell.rsrc.h"
00041 #include "op.h"
00042 #include "opinternal.h"
00043 #include "oplineheight.h"
00044 #include "lang.h" // for flscriptrunning
00045 #include "tablestructure.h" /*7.0b6 PBS: for opCursorMoved callback*/
00046 #include "process.h" /*7.0b8 PBS: check to see if we're debugging*/
00047 
00048 
00049 
00050 typedef struct tycopyinfo {
00051     
00052     hdlheadrecord hnode;
00053     
00054     short level;
00055     } tycopyinfo, *ptrcopyinfo;
00056 
00057 
00058 static hdlscreenmap hundomap; /*temporary screen map shared by opbefore/afterundo*/
00059 
00060 
00061 
00062 typedef struct tydepositinfo {
00063 
00064     hdlheadrecord hpre, hdeposit;
00065     
00066     tydirection dir;
00067     } tydepositinfo, *ptrdepositinfo, **hdldepositinfo;
00068 
00069 
00070 void opstartinternalchange (void) {
00071     
00072     /*
00073     5.1.3 dmb: flag is now a byte, make nestable
00074     */
00075     
00076     if (outlinedata)
00077         (**outlinedata).flinternalchange++;
00078     } /*opstartinternalchange*/
00079 
00080 
00081 void opendinternalchange (void) {
00082     
00083     if (outlinedata)
00084         (**outlinedata).flinternalchange--;
00085     } /*opendinternalchange*/
00086 
00087 
00088 boolean opinternalchange (void) {
00089     
00090     /*
00091     5.0d11 dmb: flinternalchange is now outline-specific
00092     */
00093     
00094     return (outlinedata && (**outlinedata).flinternalchange);
00095     } /*opendinternalchange*/
00096 
00097 
00098 boolean opnodechanged (hdlheadrecord hnode) {
00099     
00100     /*
00101     5.0a24 dmb: I don't know why we should have to do something as
00102     display intensive as invalidate a node every time it's "changed",
00103     something that happens all over the place during structure 
00104     changes. Maybe clay basket needed it, but as far as I can tell
00105     it's totally unnecessary, and clearly there's a performance hit.
00106     
00107     most importantly, this caused a bug in scrollrect under NT, where
00108     the invalidated area fouled up its basic operation
00109     */
00110 
00111     /*
00112     opnodecallback cb = (**outlinedata).nodechangedcallback;
00113     
00114     if (cb != nil) { // we can get called before the top level has been able to init this, workaround problem
00115         
00116         opinvalnode (hnode);
00117         
00118         return ((*cb) (hnode));
00119         }
00120     */
00121     
00122     (**hnode).hpixels = (**hnode).vpixels = opdirtymeasurevalue;
00123     
00124     return (true);
00125     } /*opnodechanged*/
00126 
00127 
00128 void opsetline1 (hdlheadrecord hline1) {
00129     
00130     register hdloutlinerecord ho = outlinedata;
00131     
00132     (**ho).hline1 = hline1;
00133     
00134     (**ho).line1linesabove = 0;
00135     } /*opsetline1*/
00136 
00137 
00138 static boolean opundounmark (hdlheadrecord hnode, boolean flundo) {
00139     
00140     /*
00141     8/28/92 dmb: the undo process must clear all marks in case the user has 
00142     made a new selection since the original change. this routine is used to 
00143     ensure that the original selection is restored
00144     */
00145     
00146     if (flundo) {
00147         
00148         if (!(**hnode).flmarked) {
00149             
00150             (**hnode).flmarked = true;
00151             
00152             (**outlinedata).ctmarked++;
00153             }
00154         
00155         oppushundo (&opundounmark, hnode);
00156         }
00157     
00158     return (true);
00159     } /*opundounmark*/
00160 
00161 
00162 boolean oppushunmarkundo (hdlheadrecord hnode) {
00163     
00164     /*
00165     8/28/92 dmb: setup undo to maintain selection for reorg operation.
00166     
00167     this undo should be pushed while hnode is still in the outline; 
00168     not between an unlink and a deposit
00169     */
00170     
00171     if ((**hnode).flmarked)
00172         oppushundo (&opundounmark, hnode);
00173     
00174     return (true);
00175     } /*oppushunmarkundo*/
00176 
00177 
00178 static boolean opundodeposit (hdlheadrecord hnode, boolean flundo) {
00179 
00180     if (flundo) {
00181         
00182         opunlink (hnode);
00183         
00184         if ((**hnode).flmarked)
00185             (**outlinedata).ctmarked--;
00186         }
00187     
00188     return (true);
00189     } /*opundodeposit*/
00190 
00191 
00192 static boolean oppushdepositundo (hdlheadrecord hnode) {
00193     
00194     return (oppushundo (&opundodeposit, hnode));
00195     } /*oppushdepositundo*/
00196 
00197 
00198 static boolean opdeletelinecallback (hdlheadrecord hnode) {
00199 
00200     if (!outlinedata || opinternalchange ())
00201         return (false);
00202     
00203     return ((*(**outlinedata).deletelinecallback) (hnode));
00204     } /*opdeletelinecallback*/
00205 
00206 
00207 static boolean opinsertlinecallback (hdlheadrecord hnode) {
00208     
00209     if (!outlinedata || opinternalchange ())
00210         return (false);
00211     
00212     return ((*(**outlinedata).insertlinecallback) (hnode));
00213     } /*opinsertlinecallback*/
00214 
00215 
00216 static void opchoosesafenodes (hdlheadrecord hdangerous, hdlheadrecord hsafe) {
00217 
00218     register hdloutlinerecord ho = outlinedata;
00219     
00220     if (hdangerous == (**ho).hline1) /*unlinking first line in display*/
00221         opsetline1 (hsafe);
00222         
00223     if (hdangerous == (**ho).hbarcursor) /*unlinking the bar cursor line, pretty good*/
00224         (**ho).hbarcursor = hsafe;
00225         
00226     if (hdangerous == (**ho).hsummit) /*unlinking the summit, awesome*/
00227         (**ho).hsummit = hsafe;
00228     } /*opchoosesafenodes*/
00229 
00230 
00231 boolean oppushundo (opundocallback pundo, hdlheadrecord hnode) {
00232     
00233     /*
00234     2/19/91 dmb: this used to be a macro to simply cast hnode as a Handle.  
00235     now, all outline undo goes through here, and we short circuit when 
00236     appropriate.
00237     */
00238     
00239     #if !fljustpacking
00240     
00241         if (outlinedata == nil) /*PBS 7.0b49: this can happen when getting OSA code, which doesn't require set global*/
00242             return (false);
00243 
00244         if (opinternalchange () || !(**outlinedata).flbuildundo) {
00245             
00246             (*pundo) (hnode, false);
00247             
00248             return (true);
00249             }
00250         else
00251             return (pushundostep ((undocallback) pundo, (Handle) hnode));
00252         
00253     #endif
00254     } /*oppushundo*/
00255 
00256 
00257 static boolean opundounlink (hdldepositinfo hdepositinfo, boolean flundo) {
00258     
00259     /*
00260     1/24/91 dmb: when undoing, we need to determine whether or not we need 
00261     reset levels.
00262     */
00263     
00264     if (flundo) {
00265         
00266         register hdldepositinfo hdi = hdepositinfo;
00267         register hdlheadrecord hdeposit = (**hdi).hdeposit;
00268         register short level = (**hdeposit).headlevel;
00269         
00270         opdeposit ((**hdi).hpre, (**hdi).dir, (**hdi).hdeposit);
00271         
00272         if ((**hdeposit).headlevel != level)
00273             opresetlevels (hdeposit);
00274         
00275         if ((**hdeposit).flmarked) {
00276             
00277             opexpandto (hdeposit);
00278             
00279             (**outlinedata).ctmarked++;
00280             }
00281         }
00282     
00283     disposehandle ((Handle) hdepositinfo);
00284     
00285     return (true);
00286     } /*opundounlink*/
00287 
00288 
00289 void opunlink (hdlheadrecord hnode) {
00290     
00291     /*
00292     point all elements of the structure around the indicated node, and 
00293     set his "outbound" pointers (ie everything but his right pointer)  
00294     to point at himself.
00295 
00296     6/20/90 dmb: callback to deleteline
00297     6/27/90 dmb: added undo
00298     */
00299     
00300     register hdlheadrecord h = hnode;
00301     register hdlheadrecord hdown = (**h).headlinkdown;
00302     register hdlheadrecord hup = (**h).headlinkup;
00303     register hdlheadrecord hleft = (**h).headlinkleft;
00304     tydepositinfo depositinfo;
00305     Handle hundo;
00306     
00307     if (h == nil) /*defensive driving*/
00308         return;
00309     
00310     opnodechanged (h);
00311     
00312     opnodechanged (hup); 
00313     
00314     opnodechanged (hdown);
00315     
00316     opdeletelinecallback (h);
00317 
00318     depositinfo.hdeposit = h;
00319     
00320     if (hup == h) { /*unlinking first guy at this level*/
00321 
00322         if (hleft == h) { /*has no parent -- undo by depositing up from downlink*/
00323         
00324             depositinfo.hpre = hdown;
00325             
00326             depositinfo.dir = up;
00327             
00328             assert (hdown != h);
00329             }
00330         else { /*has a parent -- undo by depositing right from leftlink*/
00331         
00332             depositinfo.hpre = hleft;
00333 
00334             depositinfo.dir = right;
00335             }
00336 
00337         if (hdown == h) { /*only child*/
00338 
00339             opchoosesafenodes (h, hleft);
00340 
00341             (**hleft).headlinkright = hleft; /*eliminate parent's child list*/
00342             
00343             goto L1;
00344             }
00345 
00346         opchoosesafenodes (h, hdown);
00347 
00348         if (hleft != h) /*has a parent*/
00349             (**hleft).headlinkright = hdown;
00350         
00351         (**hdown).headlinkup = hdown; /*he's now the 1st kid*/
00352         
00353         goto L1;
00354         }
00355 
00356     /*has a sibling above -- undo by depositing down from uplink*/
00357 
00358     depositinfo.hpre = hup;
00359 
00360     depositinfo.dir = down;
00361 
00362     opchoosesafenodes (h, hup);
00363 
00364     if (hdown == h) { /*last guy in his list*/
00365     
00366         (**hup).headlinkdown = hup; /*he's now the last kid*/
00367 
00368         goto L1;
00369         }
00370 
00371     (**hup).headlinkdown = hdown; /*point around me*/
00372     
00373     (**hdown).headlinkup = hup;
00374     
00375     L1: /*goto here to exit*/
00376     
00377     if (newfilledhandle ((ptrchar) &depositinfo, longsizeof (tydepositinfo), &hundo))
00378         oppushundo ((opundocallback) &opundounlink, (hdlheadrecord) hundo);
00379 
00380     (**h).headlinkup = (**h).headlinkdown = (**h).headlinkleft = h;
00381     } /*opunlink*/
00382 
00383 
00384 static void opdepositdown (hdlheadrecord hpre, hdlheadrecord hdeposit) {
00385     
00386     /*
00387     deposit the indicated node down from hpre.
00388     
00389     modified 11/9/88 to support multiple level-0 nodes DW.
00390     
00391     11/10/88 handles moving the first summit down, updates 
00392     (**outlinedata).hsummit.
00393     
00394     12/23/88 more efficient code, use registers better.
00395 
00396     6/20/90 dmb: callback to insertline
00397     
00398     12/29/91 dmb: make sure flexpanded is consistent with hpre
00399     */
00400     
00401     register hdlheadrecord hp = hpre;
00402     register hdlheadrecord hd = hdeposit;
00403     register short headlevel = (**hp).headlevel;
00404     
00405     opnodechanged (hp);
00406     
00407     if (headlevel == 0)
00408         (**hd).headlinkleft = hd; /*points back at himself*/
00409     else
00410         (**hd).headlinkleft = (**hp).headlinkleft; /*inherits parent from pre*/
00411     
00412     (**hd).headlevel = headlevel; /*inherits level from pre*/
00413     
00414     (**hd).flexpanded = (**hp).flexpanded; /*must be consistent*/
00415     
00416     if ((**hp).headlinkdown == hp) /*inserting as the last in the list*/
00417     
00418         (**hd).headlinkdown = hd; /*point back at himself*/
00419         
00420     else { /*inserting in the middle of the list*/
00421         
00422         register hdlheadrecord x = (**hp).headlinkdown;
00423         
00424         (**hd).headlinkdown = x;
00425         
00426         (**x).headlinkup = hd;
00427         
00428         opnodechanged (x);
00429         }
00430     
00431     (**hd).headlinkup = hp;
00432     
00433     (**hp).headlinkdown = hd;
00434 
00435     opinsertlinecallback (hd);
00436     
00437     #if !fljustpacking
00438     
00439         oppushdepositundo (hd);
00440     
00441     #endif
00442     
00443     opnodechanged ((**hd).headlinkleft); /*the parent's list changed*/
00444     
00445     opnodechanged ((**hd).headlinkdown); /*the next guy's prev pointer changed*/
00446     } /*opdepositdown*/
00447 
00448 
00449 static void opdepositright (hdlheadrecord hparent, hdlheadrecord hdeposit) {
00450 
00451     /*
00452     6/20/90 dmb: callback to insertline
00453     
00454     12/29/91 dmb: make sure flexpanded is consistent with sibling
00455     
00456     8/28/92 dmb: if only child of non-expanded parent, clear expanded bit
00457     */
00458 
00459     register hdlheadrecord hp = hparent;
00460     register hdlheadrecord hd = hdeposit;
00461     register hdlheadrecord hr = (**hp).headlinkright;
00462     
00463     opnodechanged (hp);
00464     
00465     (**hp).fldirty = true;
00466     
00467     (**hd).headlevel = (**hp).headlevel + 1;
00468     
00469     (**hd).headlinkleft = hp;
00470     
00471     (**hd).headlinkup = hd; /*points at himself*/
00472     
00473     if (hr == hp) { /*first kid*/
00474         
00475         (**hd).headlinkdown = hd; /*points at himself*/
00476         
00477         (**hp).fldirty = true;
00478         
00479         if (!(**hp).flexpanded)
00480             (**hd).flexpanded = false; /*must be consistent*/
00481         }
00482     else {
00483         (**hd).headlinkdown = hr;
00484         
00485         (**hr).headlinkup = hd;
00486         
00487         (**hd).flexpanded = (**hr).flexpanded; /*must be consistent*/
00488         
00489         opnodechanged (hr); /*the former first kid*/
00490         }
00491     
00492     (**hp).headlinkright = hd;
00493     
00494     opinsertlinecallback (hd);
00495     
00496     #if !fljustpacking
00497     
00498         oppushdepositundo (hd);
00499         
00500     #endif
00501     } /*opdepositright*/
00502 
00503 
00504 static void opdepositup (hdlheadrecord hpre, hdlheadrecord hdeposit) {
00505     
00506     /*
00507     deposit the indicated node up from hpre.  special case considerations if
00508     we're moving at the very topmost level of the structure.
00509 
00510     6/20/90 dmb: callback to insertline
00511     
00512     12/29/91 dmb: make sure flexpanded is always set
00513     */
00514     
00515     register hdlheadrecord hp = hpre;
00516     register hdlheadrecord hd = hdeposit;
00517     register hdlheadrecord hleft;
00518     register hdloutlinerecord ho = outlinedata;
00519     
00520     opnodechanged (hp);
00521             
00522     if (!opfirstinlist (hp)) { /*simple in every case*/
00523     
00524         opdepositdown ((**hp).headlinkup, hd);
00525         
00526         return;
00527         }
00528     
00529     hleft = (**hp).headlinkleft;
00530     
00531     if (hleft != hp) { /*pre has a parent*/
00532     
00533         opdepositright (hleft, hd); /*insert to right of pre's parent*/
00534         }
00535         
00536     else { /*insert as the new 0-level summit*/
00537         
00538         (**hd).headlevel = 0;
00539         
00540         (**hd).headlinkup = hd; 
00541         
00542         (**hd).headlinkdown = hp;
00543         
00544         (**hd).flexpanded = true; /*summits are always expanded*/
00545         
00546         (**hp).headlinkup = hd;
00547         
00548         if (hp == (**ho).hsummit) /*becomes the new summit*/
00549             (**ho).hsummit = hd;
00550         
00551         opinsertlinecallback (hd);
00552         
00553         #if !fljustpacking
00554         
00555             oppushdepositundo (hd);
00556         
00557         #endif
00558         }
00559         
00560     if (hp == (**ho).hline1) /*becomes the new first line*/
00561         opsetline1 (hd);
00562     } /*opdepositup*/
00563 
00564 
00565 boolean opdeposit (hdlheadrecord hpre, tydirection dir, hdlheadrecord hdeposit) {
00566     
00567     switch (dir) {
00568     
00569         case down:
00570             opdepositdown (hpre, hdeposit);
00571             
00572             break;
00573             
00574         case right:
00575             opdepositright (hpre, hdeposit);
00576             
00577             break;
00578             
00579         case up:
00580             opdepositup (hpre, hdeposit);
00581             
00582             break;
00583             
00584         case sorted:
00585             #if false 
00587                 opsorteddeposit (hpre, right, hdeposit);
00588             
00589             #endif
00590             
00591             break;
00592         
00593         default:
00594             return (false); /*invalid direction for deposit*/
00595         } /*switch*/
00596     
00597     return (true);
00598     } /*opdeposit*/
00599 
00600 
00601 boolean opmoveto (hdlheadrecord hnode) {
00602     
00603     /*
00604     move the structure cursor to the indicated node.
00605     
00606     the flcursorneedsdisplay flag lets an external user insist that no matter
00607     what the cursor line must be displayed.
00608     
00609     returns true if it had to scroll vertically to make the cursor visible.
00610     
00611     automatically adjust the horizontal scrollbar to make the new cursor line
00612     fully visible horizontally (if possible).
00613     
00614     5/4/93 dmb: don't need to docursor if we just visiscrolled
00615     */
00616     
00617     register hdloutlinerecord ho = outlinedata;
00618     register hdlheadrecord h = hnode;
00619     long hscroll, vscroll;
00620     register boolean flvisiscroll;
00621     
00622     if (((**ho).hbarcursor == hnode) && (!(**ho).flcursorneedsdisplay))
00623         return (false);
00624     
00625     opdirtyview ();
00626     
00627     (**ho).flcursorneedsdisplay = false; /*must be reset every time*/
00628     
00629     opunloadeditbuffer ();
00630     
00631     if ((**ho).flbarcursoron) /*un-highlight the old bar cursor line*/
00632         opdocursor (false); 
00633     
00634     (**ho).hbarcursor = h;
00635     
00636     flvisiscroll = opneedvisiscroll (h, &hscroll, &vscroll, false);
00637     
00638     if (flvisiscroll)
00639         opdovisiscroll (hscroll, vscroll);
00640     
00641     oploadeditbuffer ();
00642     
00643     if (!(/*dmb 11/11/96 - flvisiscroll ||*/ (**ho).fltextmode)) /*if in text mode, drawing already happened*/
00644         opdocursor (true);
00645     
00646     opschedulevisi (); /*may need horizontal scroll, once idle*/
00647     
00648     if (!debuggingcurrentprocess () && opdisplayenabled ()) /*7.0b8: don't run callbacks if debugging*/
00649     
00650         langopruncallbackscripts (idopcursormovedscript); /*7.0b6 PBS: call callback when cursor moves*/
00651     
00652     return (flvisiscroll);
00653     } /*opmoveto*/
00654     
00655     
00656 #if false
00657 
00658 static boolean oldopjumpto (hdlheadrecord hnode) {
00659     
00660     /*
00661     a special way to move the cursor when you know it's going a long 
00662     distance. no point erasing the old cursor. no point trying to scroll
00663     or erase the display. everything is going to be updated. do it all
00664     in one shot for nice staging.
00665     */
00666     
00667     long hscroll, vscroll;
00668     
00669     opinvaldisplay (); /*everything will get redrawn*/
00670     
00671     (**outlinedata).hbarcursor = hnode;
00672     
00673     if (opneedvisiscroll (hnode, &hscroll, &vscroll, false)) {
00674     
00675         opvertscrollrecord (&vscroll); 
00676 
00677         /*ophorizscrollrecord (&vscroll);*/
00678         }
00679     } /*oldopjumpto*/
00680 
00681 #endif
00682     
00683     
00684 boolean opjumpto (hdlheadrecord hnode) {
00685     
00686     /*
00687     dmb 11/8/96: keep it simple here, let opdisplay take care of all the updating
00688     */
00689     
00690     hdlheadrecord oldbarcursor = (**outlinedata).hbarcursor;
00691     
00692     (**outlinedata).hbarcursor = hnode;
00693     
00694     opjumpdisplayto (oldbarcursor, hnode);
00695     
00696     return (true);
00697     } /*opjumpto*/
00698 
00699 
00700 boolean opflatfind (boolean flfromtop, boolean flwrap) {
00701     
00702     /*
00703     search for the search string, bumping our way flatdown as we go and
00704     wrapping around to the top when we reach the last node.
00705     
00706     return true if the search was successful, with the outline cursor on the
00707     node.
00708     
00709     8/21/90 DW: add flwrap parameter -- if false the search stops at the last
00710     node, doesn't wrap around to the first summit.
00711     
00712     7/15/91 dmb: never return true when doing a replace all; keep going 
00713     until we fail
00714     
00715     9/12/91 dmb: fixed replace all logic bugs.
00716     
00717     4/26/96 dmb: never automatically bump; it not in text mode, search from 
00718     beginning of current headline
00719     */
00720     
00721     register hdloutlinerecord ho = outlinedata;
00722     register hdlheadrecord nomad;
00723     register hdlheadrecord orignomad;
00724     register hdlheadrecord nextnomad;
00725     register short ix;
00726     Handle hstring;
00727     long startsel, endsel;
00728     boolean flbump;
00729     long ixfind = 0, lenfind;
00730     
00731     flbump = !flscriptrunning;  // 4/26/96 dmb: was true
00732     
00733     if (flfromtop) {
00734         
00735         nomad = (**ho).hsummit;
00736         
00737         flbump = false;
00738         }
00739     else {
00740         
00741         nomad = (**ho).hbarcursor;
00742         
00743         if (opeditingtext (nomad)) {
00744             
00745             opeditgetselection (&startsel, &endsel);
00746             
00747             ixfind = max (startsel, endsel);
00748             
00749             opwriteeditbuffer (); /*make sure we search the current text*/
00750             
00751             flbump = false;
00752             }
00753         }
00754     
00755     orignomad = nomad;
00756     
00757     while (true) {      
00758         
00759         if (!flbump)
00760             flbump = true; /*set for next time*/
00761         
00762         else {
00763             nextnomad = opbumpflatdown (nomad, false);
00764             
00765             if (nextnomad == nomad) { /*no way flatdown, maybe wrap around to top*/
00766                 
00767                 if (!flwrap)
00768                     return (false);
00769                 
00770                 nextnomad = (**ho).hsummit;
00771                 }
00772             
00773             if (nextnomad == orignomad) /*back where we started, search failed*/
00774                 return (false);
00775             
00776             nomad = nextnomad; /*advance to next node flatdown with wrap*/
00777             
00778             ixfind = 0;
00779             }
00780         
00781         rollbeachball ();
00782     
00783         hstring = (**nomad).headstring;
00784         
00785         if (handlesearch (hstring, &ixfind, &lenfind)) { /*found match, stop searching*/
00786             
00787             if (keyboardescape ()) /*use didn't want this to happen*/
00788                 return (false);
00789             
00790             opexpandto (nomad);
00791             
00792             opsettextmode (true);
00793             
00794             ix = ixfind;
00795             
00796             opeditsetselection (ix, ix + lenfind);
00797             
00798             if (!searchparams.flreplaceall) { /*we're done*/
00799                 
00800                 opschedulevisi (); /*make sure new selection is visible*/
00801                 
00802                 return (true);
00803                 }
00804             
00805              /*do replacement while we have control*/
00806             
00807             if (oprestoreeditbuffer ()) {
00808                 
00809                 opeditinsert (searchparams.bsreplace);
00810                 
00811                 opwriteeditbuffer ();
00812                 }
00813             else {
00814                 
00815                 if (!copyhandle (hstring, &hstring))
00816                     return (false);
00817                 
00818                 if (!mungehandle (hstring, ix, lenfind,
00819                             stringbaseaddress (searchparams.bsreplace),
00820                             stringlength (searchparams.bsreplace)))
00821                     return (false);
00822                 
00823                 opsetheadtext (nomad, hstring);
00824                 }
00825             
00826             ++searchparams.ctreplaced;
00827             
00828             flbump = false;
00829             
00830             ixfind += stringlength (searchparams.bsreplace);
00831             
00832             continue; /*next iteration of loop*/
00833             }
00834         
00835         if ((*(opnodecallback)(**ho).searchrefconcallback) (nomad)) {
00836             
00837             if (!searchparams.flreplaceall)
00838                 return (true);
00839             }
00840         } /*while*/
00841     } /*opflatfind*/
00842 
00843 
00844 boolean opgetsafenode (hdlheadrecord *hnode) {
00845     
00846     /*
00847     look for a new place to put the node.  first try going up, then down.
00848     then left.  right isn't an option since we're assuming that the line that
00849     the node is on is about to be unlinked from the structure and therefore
00850     it isn't a "safe" place.
00851     */
00852     
00853     register hdlheadrecord hdangerous = *hnode;
00854     register hdlheadrecord h;
00855     
00856     h = (**hdangerous).headlinkup;
00857     
00858     if (h != hdangerous) /*found a safe place*/
00859         goto L1;
00860         
00861     h = (**hdangerous).headlinkdown;
00862     
00863     if (h != hdangerous) /*found a safe place*/
00864         goto L1;
00865         
00866     h = (**hdangerous).headlinkleft;
00867     
00868     if (h != hdangerous) /*found a safe place*/
00869         goto L1;
00870         
00871     return (false); /*couldn't move down, up or left*/
00872     
00873     L1:
00874     
00875     *hnode = h;
00876     
00877     return (true);
00878     } /*opgetsafenode*/
00879 
00880 
00881 static boolean opchecksafenode (hdlheadrecord hdelete, hdlheadrecord *hsafe) {
00882     
00883     /*
00884     check to see if hsafe or any subelement is the first line in the
00885     display.  if so, change the first line to something nearby.
00886     
00887     return true if hsafe needed to be moved.
00888     */
00889     
00890     while (true) {
00891         
00892         if (*hsafe == hdelete) { /*danger*/
00893             
00894             return (opgetsafenode (hsafe)); /*should always be true*/
00895             }
00896         
00897         if (!opchaseleft (hsafe)) /*safe*/
00898             return (false);
00899         }
00900     } /*opchecksafenode*/
00901 
00902 
00903 static boolean opcheckline1 (hdlheadrecord hdelete) {
00904     
00905     /*
00906     check to see if hdelete or any subelement is the first line in the
00907     display.  if so, change the first line to something nearby.
00908     */
00909     
00910     hdlheadrecord hline1 = (**outlinedata).hline1;
00911     
00912     if (opchecksafenode (hdelete, &hline1))
00913         opsetline1 (hline1);
00914     
00915     return (true);
00916     } /*opcheckline1*/
00917 
00918 
00919 static boolean opsafebarcursor (hdlheadrecord hdelete) {
00920     
00921     /*
00922     look for a new place to put the bar cursor.  first try going up, then down.
00923     then left.  right isn't an option since we're assuming that the line that
00924     the bar cursor is on is about to be unlinked from the structure.
00925     */
00926     
00927     hdlheadrecord hcursor = (**outlinedata).hbarcursor;
00928     
00929     if (opchecksafenode (hdelete, &hcursor))
00930         (**outlinedata).hbarcursor = hcursor;
00931     
00932     return (true);
00933     } /*opsafebarcursor*/
00934 
00935 
00936 boolean opmovecursor (hdlheadrecord hpre, tydirection dirmove, long units, hdlheadrecord *hnew) {
00937     
00938     /*
00939     return with *hnew pointing to the node in the indicated
00940     direction from hpre.
00941     
00942     if there was no way to move in the indicated direction, 
00943     return false.
00944     */
00945     
00946     register tydirection dir = dirmove;
00947     register hdlheadrecord h = hpre;
00948     register hdlheadrecord horig;
00949     register boolean flmoved = false;
00950     register long ct = units;
00951     
00952     while (--ct >= 0) {
00953         
00954         horig = h;
00955         
00956         switch (dir) {
00957         
00958             case right: {
00959                 
00960                 register hdlheadrecord hright = (**h).headlinkright;
00961                 
00962                 if ((**hright).flexpanded) /*only move into expanded nodes*/
00963                     h = hright;
00964                     
00965                 break;
00966                 }
00967                 
00968             case left:
00969                 h = (**h).headlinkleft;
00970                 
00971                 break;
00972                 
00973             case up:
00974                 h = (**h).headlinkup;
00975                 
00976                 break;
00977                 
00978             case down:
00979                 h = (**h).headlinkdown;
00980                 
00981                 break;
00982                 
00983             case flatup:
00984                 h = opbumpflatup (h, true);
00985                 
00986                 break;
00987                 
00988             case flatdown:
00989                 h = opgetnextexpanded (h);
00990                 
00991                 break;
00992             
00993             default:
00994                 /* nothing to do */
00995                 break;
00996                 
00997             } /*switch*/
00998             
00999         if (h == horig) /*didn't move, break out of loop*/
01000             goto L1;
01001             
01002         flmoved = true;
01003         } /*for*/
01004     
01005     L1:
01006     
01007     *hnew = h; /*return new position for caller*/
01008         
01009     return (flmoved);
01010     } /*opmovecursor*/
01011     
01012 
01013 boolean opcopyrefconroutine (hdlheadrecord hsource, hdlheadrecord hdest) {
01014     
01015     /*
01016     the default version of the callback that copies the refcon handle linked
01017     into the original node and links the copy into the destination.
01018     */
01019     
01020     Handle hrefcon = (**hsource).hrefcon;
01021     Handle hcopy;
01022     
01023     (**hdest).hrefcon = nil; /*default*/
01024         
01025     if (hrefcon == nil) /*very easy to copy a nil refcon*/
01026         return (true);
01027 
01028     if (!copyhandle (hrefcon, &hcopy)) 
01029         return (false);
01030         
01031     (**hdest).hrefcon = hcopy;
01032     
01033     return (true);
01034     } /*opcopyrefconroutine*/
01035     
01036 
01037 static hdlheadrecord opcopyheadrecord (hdlheadrecord horig) {
01038     
01039     register hdlheadrecord hcopy;
01040     hdlheadrecord hnewnode;
01041     Handle hstring;
01042     
01043     if (!copyhandle ((**horig).headstring, &hstring))
01044         return (false);
01045     
01046     if (!opnewheadrecord (hstring, &hnewnode)) 
01047         return (nil);
01048     
01049     hcopy = hnewnode; /*copy into register*/
01050     
01051     (**hcopy).headlevel = (**horig).headlevel; /*inherits level*/
01052     
01053     (**hcopy).flexpanded = (**horig).flexpanded; /*inherits expanded state*/
01054     
01055     (**hcopy).flcomment = (**horig).flcomment; 
01056 
01057     (**hcopy).fldynamic = (**horig).fldynamic; /*7.0b30 PBS: copy fldynamic flag*/
01058     
01059     (**hcopy).appbit0 = (**horig).appbit0; /*7/30/93 DW: for forking in Clay Basket*/
01060     
01061     (**hcopy).appbit1 = (**horig).appbit1; 
01062     
01063     (**hcopy).appbit2 = (**horig).appbit2; 
01064     
01065     (**hcopy).appbit3 = (**horig).appbit3; 
01066     
01067     (**hcopy).appbit4 = (**horig).appbit4; 
01068     
01069     (**hcopy).appbit5 = (**horig).appbit5; 
01070     
01071     (**hcopy).appbit6 = (**horig).appbit6; 
01072     
01073     (**hcopy).appbit7 = (**horig).appbit7; 
01074     
01075     if ((**horig).hrefcon != nil) { /*the original has a refcon handle attached*/
01076         
01077         boolean fl;
01078         hdloutlinerecord x = outlinedata; /*we preserve x, y and z*/
01079         
01080         fl = (*(**outlinedata).copyrefconcallback) (horig, hcopy);
01081         
01082         opsetoutline (x); /*restore to original*/
01083         
01084         if (!fl) {
01085         
01086             opreleasenode (hcopy, false); /*dispose of the partial copy*/
01087             
01088             return (nil);
01089             }
01090         }
01091     
01092     return (hcopy);
01093     } /*opcopyheadrecord*/
01094     
01095 
01096 static boolean opmoveoutlineup (void) {
01097     
01098     register hdlheadrecord hcursor = (**outlinedata).hbarcursor;
01099     register hdlheadrecord hpre = (**hcursor).headlinkup;
01100     
01101     if (hpre == hcursor) /*he's the first in the list*/
01102         return (false);
01103     
01104     opunlink (hcursor);
01105     
01106     opdepositup (hpre, hcursor);
01107     
01108     return (true);
01109     } /*opmoveoutlineup*/
01110     
01111     
01112 static boolean opmoveoutlinedown (void) {
01113     
01114     /*
01115     in this operation we must preserve the cursor, in case there are 
01116     multiple moves involved.  the unlink operation keeps the barcursor
01117     pointing at a valid headline.
01118     */
01119     
01120     register hdloutlinerecord ho = outlinedata;
01121     register hdlheadrecord hcursor = (**ho).hbarcursor;
01122     register hdlheadrecord hpre = (**hcursor).headlinkdown;
01123     
01124     if (hpre == hcursor) /*he's the last guy in the list*/
01125         return (false);
01126     
01127     opunlink (hcursor);
01128     
01129     opdepositdown (hpre, hcursor);
01130     
01131     (**ho).hbarcursor = hcursor; /*restore...*/
01132     
01133     return (true);
01134     } /*opmoveoutlinedown*/
01135     
01136 
01137 static boolean opmoveoutlineleft (void) {
01138     
01139     register hdloutlinerecord ho = outlinedata;
01140     register hdlheadrecord hcursor = (**ho).hbarcursor;
01141     register hdlheadrecord hpre = (**hcursor).headlinkleft;
01142     
01143     if (hpre == hcursor) /*trying to move a summit to the left*/
01144         return (false);
01145     
01146     opunlink (hcursor);
01147     
01148     opdepositdown (hpre, hcursor);
01149     
01150     (**hpre).fldirty = true;
01151     
01152     opresetlevels (hcursor);
01153     
01154     (**hcursor).fldirty = true;
01155     
01156     return (true);
01157     } /*opmoveoutlineleft*/
01158     
01159     
01160 static boolean opmoveoutlineright (void) {
01161     
01162     register hdloutlinerecord ho = outlinedata;
01163     register hdlheadrecord hcursor = (**ho).hbarcursor;
01164     register hdlheadrecord hpre = (**hcursor).headlinkup;
01165     
01166     if (hpre == hcursor) /*he's the first guy at his level, can't move right*/
01167         return (false);
01168         
01169     opexpand (hpre, 1, false); /*make any subheads visible*/
01170     
01171     opunlink (hcursor);
01172     
01173     if (opnosubheads (hpre))
01174         opdepositright (hpre, hcursor);
01175     else
01176         opdepositdown (opgetlastsubhead (hpre), hcursor);
01177         
01178     opresetlevels (hcursor);
01179     
01180     return (true);
01181     } /*opmoveoutlineright*/
01182 
01183 
01184 static boolean opbeforeundo (hdlheadrecord hnode, boolean flundo) {
01185     
01186     if (flundo) {
01187         
01188         opclearallmarks ();
01189         
01190         opexpandto (hnode);
01191         
01192         opmoveto (hnode);
01193         
01194         opbeforestrucchange (&hundomap, false);
01195 
01196         opdisabledisplay (); //5.0b18
01197         }
01198     
01199     return (true);
01200     } /*opbeforeundo*/
01201 
01202 
01203 static boolean opafterundo (hdlheadrecord hnode, boolean flundo) {
01204 
01205     if (flundo) {
01206         
01207         opexpandto (hnode);
01208         
01209         opmoveto (hnode);
01210         
01211         if (opanymarked ())
01212             opsettextmode (false);
01213         
01214         openabledisplay ();
01215         
01216         opafterstrucchange (hundomap, false);
01217         }
01218     
01219     return (true);
01220     } /*opafterundo*/
01221 
01222 
01223 boolean opbeforestrucchange (hdlscreenmap *hmap, boolean flsaveeditbuffer) {
01224     
01225     /*
01226     this is what you do before restructuring the outline.
01227     */
01228     
01229     opnewscreenmap (hmap); /*nil if it failed*/
01230     
01231     if (flsaveeditbuffer)
01232         opsaveeditbuffer ();
01233     else
01234         opunloadeditbuffer ();
01235     
01236     oppushundo (&opafterundo, (**outlinedata).hbarcursor);
01237     
01238     return (true);
01239     } /*opbeforestrucchange*/
01240 
01241 
01242 boolean opafterstrucchange (hdlscreenmap hmap, boolean flvisisubs) {
01243     
01244     /*
01245     this is what you do after restructuring the outline.
01246     
01247     9.1b3 AR: Check currentprocess before even considering whether
01248     to run the opCursorMoved callbacks. This fixes a crashing bug that
01249     would occur if we tried to run the callbacks while removing the
01250     current thread's entry from the system.compiler.threads table
01251     since at that point all the infrastructure for running scripts
01252     has already been disposed.
01253     */
01254 
01255     register hdloutlinerecord ho = outlinedata;
01256     
01257     opsetctexpanded (ho); /*don't bother maintaining this, we re-compute*/
01258     
01259     opsetscrollpositiontoline1 ();
01260     
01261     opresetscrollbars (); /*show changes in scroll bars, update data structures*/
01262     
01263     opinvalscreenmap (hmap); /*only inval those lines that changed*/
01264     
01265     opupdatenow (); /*provide immediate feedback*/
01266     
01267     if ((**ho).textinfo.flvalid)
01268         oprestoreeditbuffer ();
01269     else
01270         oploadeditbuffer ();
01271     
01272     if (flvisisubs)
01273         opvisisubheads ((**ho).hbarcursor);
01274     else
01275         opvisinode ((**ho).hbarcursor, true);
01276     
01277     opdirtyoutline ();
01278     
01279     if (currentprocess != nil               /* 9.1b3 AR */
01280             && !debuggingcurrentprocess ()  /*7.0b8: don't run callbacks if debugging*/
01281             && opdisplayenabled ()) {
01282              
01283         langopruncallbackscripts (idopcursormovedscript); /*7.0b6 PBS: call callback when cursor moves*/
01284         }
01285         
01286     return (oppushundo (&opbeforeundo, (**ho).hbarcursor));
01287     } /*opafterstrucchange*/
01288 
01289 
01290 boolean opsortlevel (hdlheadrecord hnode) {
01291     
01292     /*
01293     sort the nodes at the same level as the indicated node.
01294     
01295     9/1/92 dmb: roll the beachball cursor
01296     */
01297     
01298     hdlheadrecord houter, hinner;
01299     hdlheadrecord h;
01300     bigstring bslowest;
01301     hdlheadrecord hlowest;
01302     bigstring bs;
01303     long ct, i;
01304     hdlscreenmap hmap;
01305     
01306     if (opanymarked ())
01307         return (false);
01308     
01309     pushundoaction (undosortstring);
01310     
01311     opbeforestrucchange (&hmap, false);
01312     
01313     houter = oprepeatedbump (up, longinfinity, hnode, true);
01314     
01315     ct = opcountatlevel (houter);
01316     
01317     initbeachball (right);
01318     
01319     for (i = 0; i < ct; i++) {
01320         
01321         hlowest = houter;
01322         
01323         opgetsortstring (hlowest, bslowest);
01324         
01325         hinner = (**houter).headlinkdown;
01326         
01327         if (hinner == houter) /*the list is sorted*/
01328             break;
01329         
01330         while (true) {
01331             
01332             rollbeachball ();
01333             
01334             opnodechanged (hinner); /*make sure all lines get refreshed*/
01335             
01336             (**hinner).fldirty = true;
01337             
01338             opgetsortstring (hinner, bs);
01339             
01340             if (stringlessthan (bs, bslowest)) {
01341             
01342                 hlowest = hinner;
01343                 
01344                 copystring (bs, bslowest);
01345                 }
01346                 
01347             h = (**hinner).headlinkdown;
01348             
01349             if (h == hinner) /*finished scanning for lowest*/
01350                 break;
01351                 
01352             hinner = h; /*advance to next node*/
01353             } /*while*/
01354         
01355         if (hlowest != houter) {
01356         
01357             opunlink (hlowest);
01358 
01359             opdepositup (houter, hlowest);
01360 
01361             houter = hlowest;
01362             }
01363 
01364         houter = (**houter).headlinkdown;
01365         } /*while*/
01366     
01367     opafterstrucchange (hmap, false);
01368     
01369     return (true);
01370     } /*opsortlevel*/
01371 
01372 
01373 /*
01374 static boolean opdefaultcanmove (hdlheadrecord hnode, tydirection dir) {
01375     
01376     register hdlheadrecord h = hnode;
01377     boolean fl;
01378     
01379     switch (dir) {
01380         
01381         case up:
01382         case right:
01383             fl = (**h).headlinkup != h;
01384             
01385             break;
01386         
01387         case down:
01388             fl = (**h).headlinkdown != h;
01389             
01390             break;
01391             
01392         case left:
01393             fl = (**h).headlinkleft != h;
01394             
01395             break;
01396         
01397         default:
01398             fl = false;
01399         }
01400     
01401     return (fl);
01402     } /%opdefaultcanmove%/
01403 */
01404 
01405 
01406 typedef struct tymoveinfo {
01407     
01408     hdlheadrecord hpre;
01409     
01410     tydirection dir;
01411     } tymoveinfo;
01412 
01413 
01414 static boolean opvalidatecanmove (hdlheadrecord hnode, ptrvoid refcon) {
01415     
01416     /*
01417     5.0a18 dmb: added moveinfo parameter, so we can test move against
01418     correct parent when there's a multiple selection
01419     */
01420     
01421     hdloutlinerecord ho = outlinedata;
01422     tymoveinfo *moveinfo = (tymoveinfo *) refcon;
01423     hdlheadrecord hpre = (*moveinfo).hpre;
01424     tydirection dir = (*moveinfo).dir;
01425     
01426     if (hpre == nil) { // we're first, we need to set hpre, dir
01427     
01428         switch (dir) {
01429             
01430             case up:
01431             case right:
01432                 hpre = (**hnode).headlinkup;
01433                 
01434                 break;
01435             
01436             case down:
01437                 hpre = (**hnode).headlinkdown;
01438                 
01439                 break;
01440                 
01441             case left:
01442                 hpre = (**hnode).headlinkleft;
01443                 
01444                 dir = down;
01445                 
01446                 break;
01447             
01448             default:
01449                 return (false);
01450             }
01451         
01452         (*moveinfo).hpre = hpre;
01453         
01454         (*moveinfo).dir = dir;
01455         }
01456     
01457     return ((*(**ho).validatedragcallback) (hnode, hpre, dir));
01458     } /*opvalidatecanmove*/
01459 
01460 
01461 static boolean opmoveoutlinevisit (hdlheadrecord hnode, ptrvoid dir) {
01462     
01463     boolean fl;
01464     
01465     (**outlinedata).hbarcursor = hnode; /*will be restored by caller later*/
01466     
01467     oppushunmarkundo (hnode);
01468     
01469     switch ((tydirection) dir) {
01470         
01471         case up:
01472             fl = opmoveoutlineup ();
01473             
01474             break;
01475         
01476         case down:
01477             fl = opmoveoutlinedown ();
01478             
01479             break;
01480             
01481         case left:
01482             fl = opmoveoutlineleft ();
01483             
01484             break;
01485             
01486         case right:                 
01487             fl = opmoveoutlineright ();
01488             
01489             break;
01490         
01491         default:
01492             fl = false;
01493         }
01494     
01495     return (fl);
01496     } /*opmoveoutlinevisit*/
01497 
01498         
01499 boolean opreorgcursor (tydirection dir, long units) {
01500     
01501     /*
01502     reorganize the structure so that the cursor line is moved in the 
01503     indicated direction, the indicated number of times.
01504     
01505     return false if the move couldn't be done.
01506     
01507     supported directions are up, down, left and right.
01508     
01509     if it's a one level structure, return false if direction is left
01510     or right.
01511     
01512     1/24/91 dmb: must restore hcursor every time through loop
01513     */
01514     
01515     register hdloutlinerecord ho = outlinedata;
01516     register long i;
01517     register boolean fl;
01518     register boolean flmovedsomething = false;
01519     hdlscreenmap hmap;
01520     hdlheadrecord horigcursor = (**ho).hbarcursor;
01521     tydirection visitdir;
01522     tymoveinfo moveinfo;
01523     
01524     pushundoaction (undomovestring);
01525     
01526     opbeforestrucchange (&hmap, true);
01527     
01528     if ((dir == up) || (dir == right))
01529         visitdir = down;
01530     else
01531         visitdir = up;
01532     
01533     for (i = 1; i <= units; i++) {
01534         
01535         moveinfo.hpre = nil;
01536         moveinfo.dir = dir;
01537         
01538         fl = opvisitmarked (visitdir, &opvalidatecanmove, &moveinfo);
01539         
01540         if (fl)
01541             fl = opvisitmarked (visitdir, &opmoveoutlinevisit, (ptrvoid) dir);
01542         
01543         if (!fl)
01544             break;
01545         
01546         (**ho).hbarcursor = horigcursor; /*unlink changed it*/
01547         
01548         flmovedsomething = true;
01549         } /*for*/
01550     
01551     if (!flmovedsomething) {
01552         
01553         popundoaction ();
01554         
01555         oprestoreeditbuffer ();
01556         
01557         disposehandle ((Handle) hmap);
01558         
01559         return (false);
01560         }
01561     
01562     opafterstrucchange (hmap, true);
01563     
01564     return (true);
01565     } /*opreorgcursor*/
01566     
01567 
01568 static boolean opvalidatemovevisit (hdlheadrecord hnode, tymoveinfo *moveinfo) {
01569     
01570     /*
01571     5.0b15 dmb: this is confusing. the validatedrag callback makes sure that 
01572     the destination can accept a drag. We need only test a single source 
01573     headline for this test.
01574 
01575     the validatepastecallback looks for conflicts between the source nodes 
01576     and the dest. all source nodes must be tested, which it does automatcially
01577     */
01578 
01579     if (!(*(**outlinedata).validatedragcallback) (hnode, (*moveinfo).hpre, (*moveinfo).dir))
01580         return (false);
01581 
01582     return ((*(**outlinedata).validatepastecallback) (hnode, (*moveinfo).hpre, (*moveinfo).dir));
01583     } /*opvalidatemovevisit*/
01584 
01585 
01586 boolean oppromote (void) {
01587     
01588     /*
01589     move all the subheads of the bar cursor node out one level.
01590     
01591     5.0a25 dmb: use ophassubheads, not opnosubheads, to count dynamics
01592 
01593     5.0b13 dmb: added validation
01594     */
01595     
01596     register hdloutlinerecord ho = outlinedata;
01597     register hdlheadrecord hcursor = (**ho).hbarcursor;
01598     register hdlheadrecord nomad, nextnomad;
01599     hdlscreenmap hmap;
01600     boolean fl = false;
01601     
01602     if (!ophassubheads (hcursor)) /*nothing to promote*/
01603         return (false);
01604     
01605     if (opanymarked ())
01606         return (false);
01607     
01608     pushundoaction (undopromotestring);
01609 
01610     opbeforestrucchange (&hmap, true);
01611     
01612     opnodechanged (hcursor); 
01613     
01614     (**hcursor).fldirty = true; /*leader icon will change*/
01615     
01616     opexpand (hcursor, 1, false); /*make sure subheads are visible*/
01617     
01618     /*validate the move first*/ {
01619         tymoveinfo moveinfo;
01620         
01621         moveinfo.hpre = hcursor;
01622         moveinfo.dir = down;
01623         
01624         if (!opvalidatemovevisit ((**hcursor).headlinkright, &moveinfo)) //this visits list
01625             goto exit;
01626         }
01627 
01628     nomad = opgetlastsubhead (hcursor); /*start at the end of the list*/
01629     
01630     while (true) {
01631         
01632         nextnomad = (**nomad).headlinkup;
01633         
01634         (**ho).hbarcursor = nomad; /*play a li'l trick*/
01635         
01636         opmoveoutlineleft ();
01637         
01638         (**ho).hbarcursor = hcursor; /*restore*/
01639         
01640         if (nextnomad == nomad) { /*we're outa here*/
01641             
01642             fl = true;
01643 
01644             break;
01645             }
01646             
01647         nomad = nextnomad;
01648         } /*while*/
01649     
01650     exit: {
01651 
01652         opafterstrucchange (hmap, true); /*update the display, set dirty bits*/
01653 
01654         return (fl);
01655         }
01656     } /*oppromote*/
01657     
01658     
01659 boolean opdemote (void) {
01660     
01661     /*
01662     borrow Doug Baron's idea of demoting -- thanks Doug!  we move all the heads
01663     at the bar cursor's level, that are down from the bc, at the end of the
01664     bar cursor's list of subs.
01665 
01666     5.0b13 dmb: added validation
01667     */
01668     
01669     register hdloutlinerecord ho = outlinedata;
01670     register hdlheadrecord hcursor = (**ho).hbarcursor;
01671     register hdlheadrecord nomad;
01672     register boolean flmovedsomething = false;
01673     hdlscreenmap hmap;
01674     
01675     if (opanymarked ())
01676         return (false);
01677     
01678     if (oplastinlist (hcursor)) //nothing to do
01679         return (false);
01680 
01681     pushundoaction (undodemotestring);
01682     
01683     opbeforestrucchange (&hmap, true);
01684     
01685     opexpand (hcursor, 1, false); /*make sure subheads are visible*/
01686     
01687     /*validate the move first*/ {
01688         tymoveinfo moveinfo;
01689 
01690         moveinfo.hpre = hcursor;
01691         moveinfo.dir = right;
01692 
01693         if (!opvalidatemovevisit ((**hcursor).headlinkdown, &moveinfo)) //this visits list
01694             goto exit;
01695         }
01696 
01697     while (true) {
01698         
01699         nomad = (**hcursor).headlinkdown;
01700         
01701         if (nomad == hcursor) /*no more items down from the cursor*/
01702             break;
01703         
01704         (**ho).hbarcursor = nomad; /*play a li'l trick*/
01705         
01706         opmoveoutlineright ();
01707         
01708         (**ho).hbarcursor = hcursor; /*restore*/
01709         
01710         opnodechanged (hcursor); /*leader icon may change*/
01711         
01712         (**hcursor).fldirty = true;
01713         
01714         flmovedsomething = true;
01715         } /*while*/
01716 
01717     exit: {
01718         
01719         opafterstrucchange (hmap, true);
01720             
01721         return (flmovedsomething);
01722         }
01723     } /*opdemote*/
01724 
01725 
01726 static boolean opdeletesubvisit (hdlheadrecord hnode, ptrvoid refcon) {
01727     
01728     /*
01729     5.0.1 dmb: new routline betweeen opdeletesubs and opreleasenode,
01730     to avoid breaking the display
01731 
01732     5.0.2 dmb: perfect place to fix the next bug: maintain ctexpanded
01733     in case we're tossing expanded nodes
01734     */
01735 
01736     hdlheadrecord hsafe = (hdlheadrecord) refcon;
01737     hdloutlinerecord ho = outlinedata;
01738 
01739     if ((**ho).hbarcursor == hnode)
01740         (**ho).hbarcursor = hsafe;
01741     
01742     if ((**ho).hline1 == hnode)
01743         opsetline1 (hsafe);
01744     
01745     if ((**hnode).flexpanded)
01746         (**ho).ctexpanded -= opgetnodelinecount (hnode);
01747     
01748     return (opreleasevisit (hnode, (ptrvoid) true));
01749     } /*opdeletesubvisit*/
01750 
01751 
01752 boolean opdeletesubs (hdlheadrecord hnode) {
01753     
01754     /*
01755     5.0a25 dmb: use ophassubheads, not opnosubheads, to count dynamics
01756     
01757     7.0b23: Tables are dynamic. If a node is collapsed,
01758     headlinkright doesn't point to the first child, it points to itself.
01759     So call the preexpand callback to make sure headlinkright is correct.
01760     If it's not a table, it's a harmless call.
01761     */
01762     
01763     register hdlheadrecord h = hnode;
01764     hdlscreenmap hmap;
01765     
01766     if (opanymarked ())
01767         return (false);
01768     
01769     if (!ophassubheads (h)) /*nothing to delete*/
01770         return (true);
01771     
01772     pushundoaction (undodeletionstring);
01773 
01774     opbeforestrucchange (&hmap, true);
01775     
01776     opnodechanged (h); /*leader icon will change*/
01777     
01778     if (!(*(**outlinedata).preexpandcallback) (hnode, 1, true)) /*PBS 7.0b23: fixes crashing bug in tables, harmless elsewhere.*/
01779         return (false);
01780     
01781     (**h).fldirty = true;
01782     
01783     opsiblingvisiter ((**h).headlinkright, true, &opdeletesubvisit, (ptrvoid) h);
01784     
01785     (**h).headlinkright = h; /*children list is now empty*/
01786     
01787     opafterstrucchange (hmap, false);
01788     
01789     return (true); 
01790     } /*opdeletesubs*/
01791     
01792 
01793 static boolean opcopyvisit (hdlheadrecord hnode, ptrvoid refcon) {
01794     
01795     ptrcopyinfo copyinfo = (ptrcopyinfo) refcon;
01796     register hdlheadrecord hcopy;
01797     register hdlheadrecord htarget;
01798     register short level, lastlevel;
01799     register tydirection dir;
01800     
01801     hcopy = opcopyheadrecord (hnode);
01802     
01803     if (hcopy == nil) /*kill the recursion*/
01804         return (false);
01805         
01806     level = (**hnode).headlevel;
01807     
01808     lastlevel = (*copyinfo).level;
01809     
01810     htarget = (*copyinfo).hnode;
01811     
01812     if (level > lastlevel) 
01813         dir = right;
01814         
01815     else {
01816         htarget = oprepeatedbump (left, lastlevel - level, htarget, true);
01817         
01818         dir = down;
01819         }
01820     
01821     opstartinternalchange ();
01822 
01823     opdeposit (htarget, dir, hcopy);
01824 
01825     opendinternalchange ();
01826 
01827     (*copyinfo).level = level;
01828     
01829     (*copyinfo).hnode = hcopy;
01830     
01831     return (true);
01832     } /*opcopyvisit*/
01833     
01834     
01835 hdlheadrecord opcopyoutline (hdlheadrecord horig) {
01836     
01837     register hdlheadrecord hcopy;
01838     tycopyinfo copyinfo;
01839     
01840     hcopy = opcopyheadrecord (horig);
01841     
01842     if (hcopy == nil)
01843         return (nil);
01844 
01845     copyinfo.hnode = hcopy;
01846     
01847     copyinfo.level = (**hcopy).headlevel;
01848     
01849     if (oprecursivelyvisit (horig, infinity, &opcopyvisit, &copyinfo))  
01850         return (hcopy);
01851     
01852     opdisposestructure (hcopy, true); /*release what we've allocated so far*/
01853     
01854     return (nil); /*indicate failure*/
01855     } /*opcopyoutline*/
01856     
01857     
01858 boolean opcopysiblings (hdlheadrecord horig, hdlheadrecord *hcopy) {
01859     
01860     /*
01861     copy horig and all his siblings and return the copy in hcopy.
01862     
01863     5.0.2b15 dmb: make sure each new copy has expanded bit set, and no
01864     expanded subheads. also, must set headlevel of first copy to zero like 
01865     we do in opcopymarkedvisit; we used to assume that horig was a true summit
01866     
01867     5.0.2b16 dmb: leave the subhead expansion alone, and only set expanded bit
01868     if levels are changing.
01869     */
01870     
01871     register hdlheadrecord hlastcopy = nil;
01872     register hdlheadrecord h;
01873     boolean fllevelschanging = (**horig).headlevel != 0;
01874     
01875     *hcopy = nil; /*default value*/
01876     
01877     while (true) { /*copy horig and each of its siblings*/
01878     
01879         h = opcopyoutline (horig);
01880         
01881         if (h == nil) { /*memory allocation failure*/
01882             
01883             opdisposestructure (*hcopy, false);
01884             
01885             *hcopy = nil; /*further indication of error*/
01886             
01887             return (false);
01888             }
01889         
01890         if (fllevelschanging)
01891             (**h).flexpanded = true;
01892         
01893         if (*hcopy == nil) /*set returned handle*/
01894             *hcopy = h;
01895         
01896         if (hlastcopy == nil) // first one copied
01897             (**h).headlevel = 0;
01898         
01899         else {
01900         
01901             opstartinternalchange ();
01902 
01903             opdepositdown (hlastcopy, h);
01904 
01905             opendinternalchange ();
01906             }
01907         
01908         if (fllevelschanging)
01909             opresetlevels (h);
01910         
01911         hlastcopy = h; /*remember for next iteration*/
01912         
01913         if (!opnavigate (down, &horig)) /*finished copying the siblings*/
01914             return (true);
01915         } /*while*/
01916     } /*opcopysiblings*/
01917     
01918     
01919 boolean opcopyoutlinerecord (hdloutlinerecord horig, hdloutlinerecord *hcopy) {
01920     
01921     /*
01922     12/1/92 dmb: clear tophoist & hbuffer in copy. (avoids menueditor crash)
01923     
01924     5.0.2b12 dmb: set outlinedata to horig during copy, to get its callbacks.
01925     
01926     5.1.5b9 dmb: preserve barcursor, hline1
01927     */
01928     
01929     register hdloutlinerecord ho;
01930     hdlheadrecord hnewsummit;
01931     Handle hnew;
01932     long lnumline1, lnumcursor;
01933     //hdloutlinerecord hsave = outlinedata;
01934     boolean fl;
01935     
01936     if (!copyhandle ((Handle) horig, &hnew))
01937         return (false);
01938     
01939     ho = *hcopy = (hdloutlinerecord) hnew; /*copy into register*/
01940     
01941     oppushoutline (horig); //opsetoutline (horig);
01942     
01943     fl = opcopysiblings ((**horig).hsummit, &hnewsummit);
01944     
01945     opgetnodeline ((**horig).hbarcursor, &lnumcursor);
01946     
01947     opgetnodeline ((**horig).hline1, &lnumline1);
01948     
01949     oppopoutline (); //opsetoutline (hsave);
01950     
01951     if (!fl) {
01952         
01953         disposehandle ((Handle) ho);
01954         
01955         return (false);
01956         }
01957     
01958     (**ho).hsummit = nil; /*we don't own it*/
01959     
01960     opsetsummit (ho, hnewsummit);
01961     
01962     (**ho).tophoist = 0; /*if there were hoists, they're gone! should be fixed some day*/
01963     
01964     (**ho).hbuffer = nil; /*if horig was in edit mode, this doesn't belong to us*/
01965     
01966     (**ho).hbarcursor = oprepeatedbump (flatdown, lnumcursor, hnewsummit, true);
01967     
01968     (**ho).hline1 = oprepeatedbump (flatdown, lnumline1, hnewsummit, true);
01969     
01970     return (true);
01971     } /*opcopyoutlinerecord*/
01972 
01973 
01974 static boolean opclearmarkvisit (hdlheadrecord hnode, ptrvoid refcon) {
01975 #pragma unused (refcon)
01976 
01977     register hdlheadrecord h = hnode;
01978     
01979     if ((**h).flmarked) {
01980         
01981         // 5.0a25 dmb: opscreenmap handles marked changes now
01982         // (**h).fldirty = true; /*only dirty if it was previously marked*/
01983         
01984         (**h).flmarked = false;
01985         
01986         --(**outlinedata).ctmarked;
01987         }
01988     
01989     return (true);
01990     } /*opclearmarkvisit*/
01991 
01992 
01993 void opclearallmarks (void) {
01994     
01995     hdloutlinerecord ho = outlinedata;
01996     hdlscreenmap hmap;
01997     
01998     if (!opanymarked ()) { /*must check barcursor*/
01999         
02000         opsetmark ((**ho).hbarcursor, false);
02001         
02002         return;
02003         }
02004     
02005     if (!opgetmark ((**ho).hbarcursor)) /*odd case -- cursor wasn't in selection*/
02006         (**ho).flcursorneedsdisplay = true;
02007     
02008     opnewscreenmap (&hmap); /*9/11/91 dmb*/
02009     
02010     opsiblingvisiter ((**ho).hsummit, false, &opclearmarkvisit, nil);
02011     
02012     opinvalscreenmap (hmap); /*inval all the dirty lines*/
02013     
02014     //assert ((**ho).ctmarked == 0); /*really should already be zero*/
02015     
02016     (**ho).ctmarked = 0; /*make sure*/
02017     } /*opclearallmarks*/
02018 
02019 
02020 void opclearmarks (hdlheadrecord hnode) {
02021     
02022     oprecursivelyvisit (hnode, infinity, &opclearmarkvisit, nil);
02023     } /*opclearmarks*/
02024     
02025     
02026 boolean opgetmark (hdlheadrecord hnode) {
02027     
02028     return ((**hnode).flmarked);
02029     } /*opgetmark*/
02030     
02031     
02032 void opsetmark (hdlheadrecord hnode, boolean fl) {
02033     
02034     register hdlheadrecord h = hnode;
02035     register hdlheadrecord hleft;
02036     register boolean flmarked = (**h).flmarked;
02037     
02038     if (fl == flmarked) /*no change*/
02039         return;
02040     
02041     (**h).flmarked = fl;
02042     
02043     // 5.0a25 dmb: opscreenmap handles marked changes now
02044     // (**h).fldirty = true;
02045     
02046     if (!fl)  { /*turning off the marked bit is much easier*/
02047         
02048         (**outlinedata).ctmarked--;
02049         
02050         return;
02051         }
02052     
02053     (**outlinedata).ctmarked++;
02054     
02055     opclearmarks (h); /*make sure nothing subordinated is marked*/
02056     
02057     while (true) { /*clear marks on all ancestors of marked node*/
02058         
02059         hleft = (**h).headlinkleft;
02060         
02061         if (hleft == h) /*we're at the summit*/
02062             return;
02063             
02064         h = hleft; 
02065         
02066         opclearmarkvisit (h, nil);
02067         } /*while*/
02068     } /*opsetmark*/
02069 
02070 
02071 static boolean opsetbarcursorvisit (hdlheadrecord hnode, ptrvoid refcon) {
02072 #pragma unused (refcon)
02073 
02074     (**outlinedata).hbarcursor = hnode; /*move barcursor here*/
02075     
02076     return (false); /*this is the only marked node*/
02077     } /*opsetbarcursorvisit*/
02078 
02079 
02080 #if 0
02081 
02082 static boolean debugmarkedvisit (hdlheadrecord hnode, long *intforrecursion) {
02083     
02084     if ((**hnode).flmarked)
02085         ++*intforrecursion;
02086     
02087     return (true);
02088     } /*debugmarkedvisit*/
02089 
02090 #endif
02091 
02092 boolean opanymarked (void) {
02093     
02094     /*
02095     normalize the selection, and return true if anything is marked, false otherwise.
02096     */
02097     
02098     register hdloutlinerecord ho = outlinedata;
02099     
02100     switch ((**ho).ctmarked) {
02101         
02102         case 0:
02103             return (false);
02104         
02105         case 1:
02106             if (!opgetmark ((**ho).hbarcursor))
02107                 opvisitmarked (down, &opsetbarcursorvisit, nil); /*move cursor to marked headline*/
02108             
02109             return (false);
02110         
02111         default:
02112             return (true);
02113         }
02114     } /*opanymarked*/
02115 
02116 
02117 static hdlheadrecord hfirstscrap, hlastscrap; /*for copying marked structures*/
02118     
02119 
02120 static boolean opcopymarkedvisit (hdlheadrecord hnode, ptrvoid refcon) {
02121 #pragma unused (refcon)
02122 
02123     /*
02124     10/3/92 dmb: set levels so that all copies are summits
02125     */
02126     
02127     register hdlheadrecord hcopy;
02128     
02129     hcopy = opcopyoutline (hnode);
02130     
02131     if (hcopy == nil) /*allocation error, stop the traversal*/
02132         return (false);
02133         
02134     if (hfirstscrap == nil) {
02135     
02136         hfirstscrap = hcopy;
02137         
02138         hlastscrap = hcopy;
02139         
02140         (**hcopy).headlevel = 0;
02141         }
02142     else {
02143         
02144         opstartinternalchange ();
02145         
02146         opdepositdown (hlastscrap, hcopy);
02147         
02148         opendinternalchange ();
02149         
02150         hlastscrap = hcopy;
02151         }
02152     
02153     opresetlevels (hcopy);
02154     
02155     return (true);
02156     } /*opcopymarkedvisit*/
02157     
02158 
02159 static boolean
02160 optrytextcommand (
02161         boolean (*editroutine) (void),
02162         boolean flneedselection,
02163         boolean flchanging)
02164 {
02165 #pragma unused (flchanging)
02166 
02167     register hdloutlinerecord ho = outlinedata;
02168     long startsel, endsel;
02169 
02170     if (!(**ho).fltextmode)
02171         return (false);
02172     
02173     if (flneedselection) {
02174         
02175         opeditgetselection (&startsel, &endsel);
02176         
02177         if (startsel == endsel)
02178             return (false);
02179         }
02180     
02181     (*editroutine) ();
02182     
02183     return (true);
02184     } /*optrytextcommand*/
02185 
02186 
02187 boolean opcopy (void) {
02188 
02189     /*
02190     5.1.3 dmb: better error handling
02191     */
02192     
02193     register hdloutlinerecord ho = outlinedata;
02194     
02195     if (optrytextcommand (opeditcopy, true, false))
02196         return (true);
02197     
02198     if (!((**ho).validatecopycallback) (STR_copy))
02199         return (false);
02200     
02201     opwriteeditbuffer (); /*if a headline is being edited, update text handle*/
02202     
02203     if (!opanymarked ()) { /*just copy the bar cursor structure*/
02204     
02205         return (opsetscrap (opcopyoutline ((**ho).hbarcursor)));
02206         }
02207     
02208     hfirstscrap = hlastscrap = nil; /*nothing has been copied yet*/
02209     
02210     if (!opvisitmarked (nodirection, &opcopymarkedvisit, nil)) {
02211         
02212         opdisposestructure (hfirstscrap, false);
02213         
02214         return (false);
02215         }
02216     
02217     return (opsetscrap (hfirstscrap));
02218     } /*opcopy*/
02219 
02220 
02221 static void opdisposenode (hdlheadrecord hnode) {
02222 
02223     opdisposestructure (hnode, true);
02224     } /*opdisposenode*/
02225 
02226 
02227 static boolean opundodelete (hdlheadrecord hnode, boolean flundo); /*forward*/
02228 
02229 static boolean opredodelete (hdlheadrecord hnode, boolean flundo) {
02230 
02231     if (flundo)
02232         oppushundo (&opundodelete, hnode);
02233 
02234     return (true);
02235     } /*opredodelete*/
02236 
02237 
02238 static boolean opundodelete (hdlheadrecord hnode, boolean flundo) {
02239     
02240     if (flundo) {
02241         
02242         (**hnode).flmarked = true; /*just make sure it's marked; it's notin the outline now*/
02243         
02244         oppushundo (&opredodelete, hnode);
02245         }
02246     else
02247         opdisposenode (hnode);
02248     
02249     return (true);
02250     } /*opundodelete*/
02251 
02252 
02253 boolean opdepositnewheadline (hdlheadrecord hpre, tydirection dir, Handle hstring, hdlheadrecord *hnew) {
02254 
02255     /*
02256     6.0a1 dmb: handle-based version of opaddheadline, which now calls us
02257     */
02258     
02259     if (!opnewheadrecord (hstring, hnew))
02260         return (false);
02261     
02262     #if !fljustpacking
02263     
02264         oppushundo (&opredodelete, *hnew);
02265         
02266     #endif
02267     
02268     return (opdeposit (hpre, dir, *hnew));
02269     } /*opdepositnewheadline*/
02270 
02271 
02272 boolean opaddheadline (hdlheadrecord hpre, tydirection dir, bigstring bshead, hdlheadrecord *hnew) {
02273 
02274     Handle hstring;
02275     
02276     if (!newtexthandle (bshead, &hstring))
02277         return (false);
02278     
02279     return (opdepositnewheadline (hpre, dir, hstring, hnew));
02280     } /*opaddheadline*/
02281 
02282 
02283 static boolean opundonewsummit (hdlheadrecord hnode, boolean flundo) {
02284     
02285     if (flundo) {
02286         
02287         register hdloutlinerecord ho = outlinedata;
02288         hdlheadrecord hdelete = (**ho).hsummit;
02289         
02290         /* restore original summit */
02291         
02292         (**ho).hsummit = hnode;
02293         
02294         (**ho).hbarcursor = hnode;
02295         
02296         (**ho).hline1 = hnode;
02297         
02298         assert ((**ho).ctmarked == 0);
02299         
02300         if ((**hnode).flmarked)
02301             (**ho).ctmarked = 1;
02302         
02303         /* prepare reciprocal undo for what was the "new" summit */
02304         
02305         oppushundo (&opundonewsummit, hdelete);
02306         }
02307     
02308     return (true);
02309     } /*opundonewsummit*/
02310 
02311 
02312 boolean opdeletenode (hdlheadrecord hnode) {
02313     
02314     /*
02315     5.0a25 dmb: don't assume that hnode itself is expanded
02316 
02317     5.0b7 dmb: create new summit before calling deletelinecallback
02318     */
02319 
02320     register hdloutlinerecord ho = outlinedata;
02321     register hdlheadrecord hdelete = hnode;
02322     register hdlheadrecord hsummit;
02323     
02324     hsummit = (**ho).hsummit;
02325     
02326     if (hdelete == hsummit) { /*deleting the first summit*/
02327         
02328         register hdlheadrecord hdown = (**hsummit).headlinkdown;
02329         
02330         if (hdown == hsummit) /*deleting the only summit*/
02331             hdown = nil;
02332         
02333         (**ho).hsummit = hdown;
02334         
02335         opsetline1 (hdown);
02336         
02337         (**ho).hbarcursor = hdown;
02338         }
02339         
02340     else { /*deleting something other than the first summit*/
02341         
02342         if (!opsafebarcursor (hdelete)) { /*couldn't move up, down, or left*/
02343             
02344             popundoaction ();
02345             
02346             return (false);
02347             }
02348         }
02349     
02350     /*the cursor has been moved out of harm's way, perform the delete*/
02351     
02352     if ((**ho).hsummit == nil) { /*we deleted the only summit, make a new blank one*/
02353         
02354         opnewsummit (); /*make a new, blank summit, xxx -- add pre-flighting*/
02355         
02356         opdeletelinecallback (hdelete);
02357         
02358         opinsertlinecallback ((**ho).hsummit);
02359         
02360         oppushundo (&opredodelete, (**ho).hsummit);
02361         
02362         oppushundo (&opundonewsummit, hdelete);
02363         
02364         (**ho).ctexpanded = 1;
02365         
02366         (**ho).ctmarked = 0;
02367         }
02368     else {
02369         opcheckline1 (hdelete);
02370         
02371         opunlink (hdelete);
02372         
02373         if (opsubheadsexpanded (hdelete)) /*got rid of the deleted line(s)*/
02374             opsetctexpanded (ho);
02375         else if ((**hdelete).flexpanded)
02376             (**ho).ctexpanded -= opgetnodelinecount (hdelete);
02377         
02378         opsetscrollpositiontoline1 ();
02379         
02380         if ((**hdelete).flmarked)
02381             (**ho).ctmarked --;
02382         
02383         opnodechanged ((**ho).hbarcursor); 
02384         
02385         (**(**ho).hbarcursor).fldirty = true; /*be sure cursor gets displayed*/
02386         }
02387     
02388     oppushundo (&opundodelete, hdelete);
02389     
02390     return (true);
02391     } /*opdeletenode*/
02392 
02393 
02394 static boolean opdeletenodevisit (hdlheadrecord hnode, ptrvoid refcon) {
02395 #pragma unused (refcon)
02396 
02397     return (opdeletenode (hnode));
02398     } /*opdeletenodevisit*/
02399 
02400 
02401 boolean opdelete (void) {
02402     
02403     /*
02404     delete the barcursor outline
02405     
02406     9/11/91 dmb: handle scrollbars when barcursor has expanded subheads
02407     
02408     2/12/92 dmb: must call delete/insert callbacks when replacing the 
02409     summit.  (failure to do so used to cause menubar crash.)
02410     */
02411     
02412     hdlscreenmap hmap;
02413     
02414     opbeforestrucchange (&hmap, false);
02415     
02416     if (!opvisitmarked (down, &opdeletenodevisit, nil)) { /*an error occurred; try to unwind*/
02417         
02418         disposehandle ((Handle) hmap); /*checks for nil*/
02419         
02420         popundoaction ();
02421 
02422         return (false);
02423         }
02424     
02425     opafterstrucchange (hmap, false);
02426     
02427     return (true);
02428     } /*opdelete*/
02429 
02430 
02431 boolean opclear (void) {
02432         
02433     if (optrytextcommand (opeditclear, true, true))
02434         return (true);
02435     
02436     pushundoaction (undoclearstring);
02437     
02438     return (opdelete ());
02439     } /*opclear*/
02440     
02441     
02442 void opdeleteline (void) {
02443     
02444     /*
02445     support for the deleteline verb.
02446     */
02447         
02448     pushundoaction (undoclearstring);
02449     
02450     opdelete ();
02451     } /*opdeleteline*/
02452 
02453 
02454 boolean opcut (void) {
02455 
02456     if (optrytextcommand (opeditcut, true, true))
02457         return (true);
02458     
02459     pushundoaction (undocutstring);
02460     
02461     if (!opcopy ())
02462         return (false);
02463     
02464     return (opdelete ());
02465     } /*opcut*/
02466 
02467 
02468 #if 0
02469 
02470 static boolean opundopaste (hdlheadrecord hnode, boolean flundo) {
02471 
02472     if (flundo) {
02473     
02474         opmoveto (hnode);
02475 
02476         opdelete ();
02477         }
02478 
02479     return (true);
02480     } /*opundopaste*/
02481 
02482 #endif
02483 
02484 
02485 boolean isoutlinetext (Handle htext) {
02486     
02487     /*
02488     return true if the text represents a multiple headline 
02489     outline, false if it is just flat text
02490     
02491     2.1b9 dmb: broke out this snippet so it can be shared
02492 
02493     6.0a1 dmb: fat headlines can be > lenbigstring
02494     */
02495     
02496     bigstring bsreturn;
02497 
02498     setstringwithchar (chreturn, bsreturn);
02499 
02500     return (textpatternmatch ((byte *) (*htext), gethandlesize (htext), bsreturn, false) >= 0);
02501     
02502     /*
02503     bigstring bs;
02504     
02505     if (gethandlesize (htext) > lenbigstring) //too big for a single head
02506         return (true);
02507     
02508     texthandletostring (htext, bs);
02509         
02510     return (stringfindchar (chreturn, bs));
02511     */
02512     } /*isoutlinetext*/
02513 
02514 
02515 boolean isoutlinescrap (void) {
02516     
02517     /*
02518     return true if the scrap should be pasted as an outline even when 
02519     in text mode
02520     
02521     12/31/96 dmb: removed check for scrap being > 0x400 bytes. simple 
02522     wptext scraps can be that large.
02523     */
02524     
02525     boolean fltempscrap;
02526     tyscraptype scraptype;
02527     Handle hscrap;
02528     boolean floutline;
02529     
02530     if (!shellgetscrap (&hscrap, &scraptype)) /*try to get the scrap, ignoring type*/
02531         return (false);
02532     
02533     switch (scraptype) {
02534         
02535         case opscraptype: /*specifically an OP scrap*/
02536         case scriptscraptype:
02537         case menuscraptype:
02538         case hashscraptype:
02539             return (true);
02540         
02541         default:
02542         //  if (gethandlesize (hscrap) > 0x0400) /*too big for a headline*/
02543         //      return (true);
02544             
02545             if (!shellconvertscrap (textscraptype, &hscrap, &fltempscrap)) /*try converting to text*/
02546                 return (false);
02547             
02548             floutline = isoutlinetext (hscrap);
02549             
02550             if (fltempscrap)
02551                 disposehandle (hscrap);
02552             
02553             return (floutline);
02554         }
02555     } /*isoutlinescrap*/
02556 
02557 
02558 static boolean equalheadstrings (hdlheadrecord h1, hdlheadrecord h2) {
02559     
02560     bigstring s1, s2;
02561     
02562     opgetheadstring (h1, s1);
02563     
02564     opgetheadstring (h2, s2);
02565     
02566     return (equalstrings (s1, s2));
02567     } /*equalheadstrings*/
02568 
02569 
02570 boolean oppaste (void) {
02571     
02572     /*
02573     1/30/91 dmb: fixed heap bug; was passing &hmap to opafterstrucchange
02574     
02575     5.0a5 dmb: when pasting a temp scrap, must unlink each node that we don't copy
02576     */
02577     
02578     register hdloutlinerecord ho = outlinedata;
02579     register hdlheadrecord hcursor = (**ho).hbarcursor;
02580     register hdlheadrecord hcopy, hfirstcopy, hlastcopy;
02581     hdlheadrecord nomad, nextnomad;
02582     hdlheadrecord houtlinescrap;
02583     hdlscreenmap hmap;
02584     boolean fltempscrap;
02585     boolean flmarkcopies = false;
02586     
02587     opclearallmarks ();
02588     
02589     if (isoutlinescrap ()) /*pasting outlines exits text mode*/
02590         opsettextmode (false);
02591     
02592     if (optrytextcommand (opeditpaste, false, true)) /*if text mode, handle & exit*/
02593         return (true);
02594     
02595     pushundoaction (undopastestring);
02596     
02597     if (!opgetscrap (&houtlinescrap, &fltempscrap))
02598         return (false);
02599         
02600     if (!((**ho).validatepastecallback) (houtlinescrap, hcursor, down))
02601         return (false);
02602     
02603     hcursor = (**outlinedata).hbarcursor; /*the validate routine could delete the bar cursor*/
02604     
02605     opbeforestrucchange (&hmap, false);
02606     
02607     opnodechanged (hcursor);
02608     
02609     (**hcursor).fldirty = true;
02610     
02611     nomad = houtlinescrap;
02612     
02613     hlastcopy = hcursor; /*where we deposit the next pasted structure*/
02614     
02615     hfirstcopy = nil; /*indicate nothing has been pasted yet*/
02616     
02617     while (true) { /*copy each of the summits on the scrap*/
02618     
02619         nextnomad = (**nomad).headlinkdown;
02620         
02621         if (fltempscrap) {
02622             
02623             hcopy = nomad; /*rather than disposing temp afterwards, use it directly*/
02624             
02625             if (nextnomad != nomad) { // must disconnect since we're not making a copy
02626                 
02627                 (**nomad).headlinkdown = nomad;
02628                 
02629                 (**nextnomad).headlinkup = nextnomad;
02630                 }
02631             }
02632         else
02633             hcopy = opcopyoutline (nomad);
02634         
02635         oppushundo (&opredodelete, hcopy);
02636         
02637         if (hfirstcopy == nil) { /*first time*/
02638             
02639             hfirstcopy = hcopy;
02640             
02641             flmarkcopies = (nextnomad != nomad) && (nextnomad != nil); /*more to come*/
02642             }
02643         
02644         if (hcopy == nil) { /*memory error*/
02645             
02646             if (hfirstcopy == nil) { /*nothing to paste*/
02647                 
02648                 disposehandle ((Handle) hmap);
02649                 
02650                 popundoaction ();
02651                 
02652                 return (true);
02653                 }
02654                 
02655             goto L1; /*paste what we have so far*/
02656             }
02657             
02658         opdepositdown (hlastcopy, hcopy);
02659         
02660         hlastcopy = hcopy;
02661         
02662         opresetlevels (hcopy);
02663         
02664         if (flmarkcopies)
02665             opsetmark (hcopy, true);
02666         
02667         else {
02668             if (!equalheadstrings (hcopy, nomad)) {
02669                 
02670                 (**ho).flcursorneedsdisplay = true; /*make sure opmoveto does something*/
02671                 
02672                 (**ho).fltextmode = true;
02673                 
02674                 (**hcopy).flmarked = false; /*clear flag*/
02675                 
02676                 opeditsetselection (0, infinity);
02677                 }
02678             }
02679         
02680         opfastcollapse (hcopy); /*turn off expanded bits of submaterial*/
02681         
02682         (**hcopy).flexpanded = true;
02683         
02684         if ((nomad == nextnomad) || (nextnomad == nil)) /*copied the last guy on scrap*/
02685             goto L1;
02686             
02687         nomad = nextnomad; /*advance to next guy on scrap*/
02688         } /*while*/
02689     
02690     L1:
02691     
02692     opsetctexpanded (ho); /*don't bother maintaining this, we re-compute*/
02693     
02694     (**ho).hbarcursor = hlastcopy;
02695     
02696     (*(**ho).postpastecallback) (hfirstcopy);
02697     
02698     opafterstrucchange (hmap, false);
02699     
02700     if (!opnodevisible (hfirstcopy)) {
02701         
02702         opvisinode (hfirstcopy, false);
02703         
02704         opvisinode (hlastcopy, false);
02705         }
02706     
02707     return (true);
02708     } /*oppaste*/
02709 
02710 
02711 boolean opinsertheadline (Handle hstring, tydirection dir, boolean flcomment) {
02712     
02713     /*
02714     8/11/92 dmb: make sure display is enabled before drawing
02715     */
02716     
02717     register hdloutlinerecord ho = outlinedata;
02718     register hdlheadrecord hcursor = (**ho).hbarcursor;
02719     hdlheadrecord hnewcursor;
02720     
02721     opunloadeditbuffer ();
02722     
02723     pushundoaction (undotypingstring);
02724     
02725     oppushundo (&opafterundo, hcursor);
02726     
02727     opdocursor (false); /*un-highlight the old bar cursor line*/
02728     
02729     if (!opdepositnewheadline (hcursor, dir, hstring, &hnewcursor)) {
02730         
02731         opdocursor (true); /*un-highlight the old bar cursor line*/
02732     
02733         popundoaction ();
02734         
02735         return (false);
02736         }
02737     
02738     oppushundo (&opbeforeundo, hnewcursor);
02739     
02740     opdirtyoutline ();
02741     
02742     hcursor = hnewcursor; /*copy into register*/
02743     
02744     (**hcursor).flcomment = bitboolean (flcomment);
02745     
02746     (**ho).hbarcursor = hcursor;
02747     
02748     opexpandupdate (hcursor);
02749     
02750     if (opdisplayenabled ())
02751         opvisibarcursor ();
02752     
02753     oploadeditbuffer ();
02754     
02755     opeditselectall (); // 5.0d18 dmb: in case text was added by callback
02756     
02757     return (true);
02758     } /*opinsertheadline*/
02759     
02760 
02761 boolean opinsertstructure (hdlheadrecord hnode, tydirection dir) {
02762     
02763     /*
02764     12/13/91 dmb: created from oppaste to service insert verb.
02765     */
02766     
02767     register hdloutlinerecord ho = outlinedata;
02768     register hdlheadrecord hcursor = (**ho).hbarcursor;
02769     hdlheadrecord nomad, nextnomad;
02770     hdlscreenmap hmap;
02771     
02772     opsettextmode (false);
02773     
02774     pushundoaction (undotypingstring);
02775     
02776     opbeforestrucchange (&hmap, false);
02777     
02778     opnodechanged (hcursor);
02779     
02780     (**hcursor).fldirty = true;
02781     
02782     nomad = hnode;
02783     
02784     while (true) { /*copy each of the summits on the scrap*/
02785         
02786         nextnomad = (**nomad).headlinkdown;
02787         
02788         oppushundo (&opredodelete, nomad);
02789         
02790         opdeposit (hcursor, dir, nomad);
02791         
02792         dir = down;
02793         
02794         hcursor = nomad;
02795         
02796         opresetlevels (hcursor);
02797         
02798         (**hcursor).flexpanded = true;
02799         
02800         if ((nomad == nextnomad) || (nextnomad == nil)) /*deposited the last guy*/
02801             break;
02802         
02803         nomad = nextnomad; /*advance to next guy on scrap*/
02804         } /*while*/
02805     
02806     // 6.0a14 dmb: done by afterstructchangenow -- opsetctexpanded (ho);
02807     
02808     (**ho).hbarcursor = hnode;
02809     
02810     opafterstrucchange (hmap, false);
02811     
02812     if (!opnodevisible (hcursor)) {
02813         
02814         opvisinode (hcursor, false);
02815         
02816         opvisinode (hnode, true);
02817         }
02818     
02819     return (true);
02820     } /*opinsertstructure*/
02821 
02822 
02823 boolean opsettmpbitvisit (hdlheadrecord hnode, ptrvoid flset) {
02824     
02825     (**hnode).tmpbit = (boolean) ((long) flset);
02826     
02827     return (true);
02828     } /*opsettmpbitvisit*/
02829 
02830 
02831 boolean opcleartmpbits (void) {
02832     
02833     return (opsiblingvisiter ((**outlinedata).hsummit, true, &opsettmpbitvisit, (ptrvoid) false));
02834     } /*opcleartmpbits*/
02835 
02836 
02837 
02838 

Generated on Wed May 31 18:19:57 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6