opxml.c

Go to the documentation of this file.
00001 
00002 /*  $Id: opxml.c 1254 2006-04-12 20:27:14Z 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 /*
00029 opxml.c -- Implementation of op<->xml verbs. OPML is Outline Processor Markup Language.
00030 
00031 Spec: http://radio.userland.com/opmlspec.html
00032 
00033 7.0b21 PBS 09/00
00034 */
00035 
00036 #include "frontier.h"
00037 #include "standard.h"
00038 
00039 #include "op.h"
00040 #include "opinternal.h"
00041 #include "opxml.h"
00042 #include "tableinternal.h"
00043 #include "langxml.h"
00044 #include "strings.h"
00045 #include "lang.h"
00046 #include "langinternal.h"
00047 #include "tablestructure.h"
00048 #include "tableverbs.h"
00049 #include "ops.h"
00050 
00051 
00052 #define STR_quot            (BIGSTRING ("\x06" "&quot;"))
00053 #define STR_quot_replace    (BIGSTRING ("\x01" "\""))
00054 #define STR_lt              (BIGSTRING ("\x04" "&lt;"))
00055 #define STR_lt_replace      (BIGSTRING ("\x01" "<"))
00056 #define STR_gt              (BIGSTRING ("\x04" "&gt;")) 
00057 #define STR_gt_replace      (BIGSTRING ("\x01" ">"))
00058 #define STR_amp             (BIGSTRING ("\x05" "&amp;"))
00059 #define STR_amp_replace     (BIGSTRING ("\x01" "&"))
00060 #define STR_attstablename   (BIGSTRING ("\x05" "/atts"))
00061 #define STR_textitemname    (BIGSTRING ("\x04" "text"))
00062 #define STR_windowtop       (BIGSTRING ("\x09" "windowTop"))
00063 #define STR_windowleft      (BIGSTRING ("\x0a" "windowLeft"))
00064 #define STR_windowbottom    (BIGSTRING ("\x0c" "windowBottom"))
00065 #define STR_windowright     (BIGSTRING ("\x0b" "windowRight"))
00066 #define STR_title           (BIGSTRING ("\x05" "title"))
00067 #define STR_datecreated     (BIGSTRING ("\x0b" "dateCreated"))
00068 #define STR_datemodified    (BIGSTRING ("\x0c" "dateModified"))
00069 #define STR_ownername       (BIGSTRING ("\x09" "ownerName"))
00070 #define STR_owneremail      (BIGSTRING ("\x0a" "ownerEmail"))
00071 #define STR_expansionstate  (BIGSTRING ("\x0e" "expansionState"))
00072 #define STR_vertscrollstate (BIGSTRING ("\x0f" "vertScrollState"))
00073 #define STR_outlinedocument (BIGSTRING ("\x0f" "outlineDocument"))
00074 #define STR_opmldocument    (BIGSTRING ("\x04" "opml"))
00075 #define STR_head            (BIGSTRING ("\x04" "head"))
00076 #define STR_openhead        (BIGSTRING ("\x06" "<head>"))
00077 #define STR_closehead       (BIGSTRING ("\x07" "</head>"))
00078 #define STR_body            (BIGSTRING ("\x04" "body"))
00079 #define STR_xmlheader       (BIGSTRING ("\x2b" "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"))
00080 #define STR_docheader       (BIGSTRING ("\x14" "<opml version=\"1.1\">"))
00081 #define STR_closedoc        (BIGSTRING ("\x07" "</opml>"))
00082 #define STR_userprefs       (BIGSTRING ("\x0a" "user.prefs"))
00083 #define STR_name            (BIGSTRING ("\x04" "name"))
00084 #define STR_email           (BIGSTRING ("\x0b" "mailaddress"))
00085 #define STR_outlinetag      (BIGSTRING ("\x07" "outline"))
00086 #define STR_closeoutline    (BIGSTRING ("\x0a" "</outline>"))
00087 #define STR_openbody        (BIGSTRING ("\x06" "<body>"))
00088 #define STR_closebody       (BIGSTRING ("\x07" "</body>"))
00089 #define STR_openoutlinetext (BIGSTRING ("\x0f" "<outline text=\""))
00090 #define STR_space           (BIGSTRING ("\x01" " "))
00091 #define STR_equalsquotes    (BIGSTRING ("\x02" "=\""))
00092 #define STR_iscomment       (BIGSTRING ("\x09" "isComment"))
00093 #define STR_isbreakpoint    (BIGSTRING ("\x0c" "isBreakpoint"))
00094 #define STR_booleantrue     (BIGSTRING ("\x04" "true"))
00095 #define STR_xstruct         (BIGSTRING ("\x07" "xstruct"))
00096 
00097 #define STR_version         (BIGSTRING ("\x07" "version"))
00098 #define STR_cloud           (BIGSTRING ("\x05" "cloud"))
00099 #define STR_opencloud       (BIGSTRING ("\x06" "<cloud"))
00100 #define STR_domain          (BIGSTRING ("\x06" "domain"))
00101 #define STR_port            (BIGSTRING ("\x04" "port"))
00102 #define STR_path            (BIGSTRING ("\x04" "path"))
00103 #define STR_regProcedure    (BIGSTRING ("\x11" "registerProcedure"))
00104 #define STR_protocol        (BIGSTRING ("\x08" "protocol"))
00105 #define STR_legalprotocols  (BIGSTRING ("\x16" "xml-rpc|soap|http-post"))
00106 #define CH_legaldelim       ('|')
00107 
00108 #define STR_errornotopml    (BIGSTRING ("\x41" "Can't convert to an outline because this is not an OPML document."))
00109 
00110 #define STR_errornohead     (BIGSTRING ("\x42" "Can't convert to an outline because the <head> section is missing."))
00111 
00112 #define STR_errornobody     (BIGSTRING ("\x4b" "Can't convert to an outline because the <body> section is missing or empty."))
00113 
00114 #define STR_errornooutlines (BIGSTRING ("\x54" "Can't convert to an outline because the <body> section contains no outline elements."))
00115 
00116 
00117 
00118 /*Prototypes*/
00119 
00120 static boolean opxmltooutlinevisit (hdlhashtable ht, short ixlevel, bigstring bsname, boolean flfirstline);
00121 
00122 static boolean opxmlgetheadlinetextfromatts (hdlhashtable ht, Handle htext);
00123 
00124 static boolean opxmlsetwindowatts (hdlhashtable ht, hdloutlinerecord ho, hdlhashtable hto, bigstring bso, tyvaluerecord vo);
00125 
00126 static boolean opxmlsetwindowpositionandsize (hdlhashtable ht, hdlwindowinfo hinfo);
00127 
00128 static boolean opxmlfindtableitem (hdlhashtable ht, bigstring bsname, hdlhashtable *htfound);
00129 
00130 static boolean opxmlgetonelongvalue (hdlhashtable ht, bigstring bsname, long *v);
00131 
00132 //static boolean opxmlpushxmlheader (Handle htext, short indentlevel);
00133 
00134 static boolean opxmlencodetext (Handle htext);
00135 
00136 static boolean opxmlpushstringline (Handle htext, bigstring bs, short indentlevel);
00137 
00138 static boolean opxmlbuildhead (Handle htext, hdloutlinerecord ho, Handle hname, Handle hemail, short indentlevel, hdlwindowinfo hinfo, hdlhashtable hcloud);
00139 
00140 static boolean opxmlpushhandleline (Handle htext, Handle h, short indentlevel);
00141 
00142 static boolean opxmlgetwindowexpansionstate (hdloutlinerecord ho, Handle *hstate);
00143 
00144 static boolean opxmlbuildbody (hdloutlinerecord ho, Handle htext, short indentlevel);
00145 
00146 static boolean opxmlensureopenwindow (hdloutlinerecord ho, hdlhashtable hto, bigstring bso, tyvaluerecord vo, hdlwindowinfo *hinfo, boolean *flwasopen);
00147 
00148 static boolean opxmlpushindents (Handle htext, short indentlevel);
00149 
00150 static boolean opxmlheadexists (hdlhashtable ht);
00151 
00152 static boolean opxmlrecursivelyvisit (hdlheadrecord h, short lev, opvisitcallback visit, ptrvoid refcon);
00153 
00154 static boolean opxmlvisitnondynamicnodes (opvisitcallback visit, ptrvoid refcon);
00155 
00156 static boolean opxmlgetcloudatts (hdlhashtable hhead, hdlhashtable hcloudspec);
00157 
00158 static boolean opxmlpushoneattribute (Handle htext, bigstring bsname, Handle hvalue);
00159 
00160 static boolean opxmlgetattribute (hdlhashtable ht, bigstring bsname, tyvaluetype type, tyvaluerecord *val);
00161 
00162 
00163 /*Functions*/
00164 
00165 boolean opoutlinetoxml (hdloutlinerecord ho, Handle hname, Handle hemail, Handle *htext, 
00166                         hdlhashtable hto, bigstring bso, tyvaluerecord vo, hdlhashtable hcloud) {
00167     
00168     /*
00169     7.0b21 PBS: convert an outline to XML text.
00170     
00171     7.1b42 dmb: added hcloud parameter
00172 
00173     Note: it might be wise to use handlestreams at some point. Since I don't know how they work yet,
00174     I'm sticking with the tried-and-true.
00175     
00176     Caller is responsible for disposing htext.
00177     */
00178     
00179     short indentlevel = 0;
00180     hdlwindowinfo hinfo;
00181     boolean flwindowwasopen = false;
00182     boolean fl = false;
00183 
00184     if (!newemptyhandle (htext))
00185         goto exit;
00186     
00187     if (!opxmlpushstringline (*htext, STR_xmlheader, indentlevel)) /*Push <?xml...>*/
00188         goto exit;
00189     
00190     if (!opxmlpushstringline (*htext, STR_docheader, indentlevel)) /*Push <opml...>*/
00191         goto exit;
00192         
00193     indentlevel++;
00194     
00195     if (!opxmlensureopenwindow (ho, hto, bso, vo, &hinfo, &flwindowwasopen)) /*Make sure op window is open.*/
00196         goto exit;
00197 
00198     if (!opxmlbuildhead (*htext, ho, hname, hemail, indentlevel, hinfo, hcloud)) /*Build <head> section.*/
00199         goto exit;
00200     
00201     if (!opxmlbuildbody (ho, *htext, indentlevel)) /*Build <body> section.*/
00202         goto exit;
00203 
00204     if (!flwindowwasopen) /*Close window if necessary*/
00205         shellclosewindow ((**hinfo).macwindow);
00206     
00207     if (!opxmlpushstringline (*htext, STR_closedoc, indentlevel)) /*Push </opml>*/
00208         goto exit;
00209     
00210     fl = true; /*success*/
00211     
00212     exit:
00213     
00214     return (fl);
00215     } /*opoutlinetoxml*/
00216 
00217 
00218 boolean opxmltooutline (Handle htext, hdloutlinerecord ho, boolean flnewoutline, 
00219                         hdlhashtable hto, bigstring bso, tyvaluerecord vo, hdlhashtable hcloud) {
00220     
00221     /*
00222     7.0b21 PBS -- convert XML text to an outline.
00223 
00224 
00225 
00226     7.0b33 PBS: changes to conform to changing spec. Both <head> and <body> are required. <head> may be empty.
00227 
00228     7.1b42 dmb: added hcloud parameter
00229 
00230     <body> must contain one or more <outline> elements.
00231     */
00232     
00233     hdlhashtable ht, htfirst, htopmldocument, htbody, hthead;
00234     hdlhashnode hn;
00235     xmladdress xstruct;
00236     boolean flheadfound = false;
00237     boolean fl = false;
00238     boolean florigdisplayenabled = true;
00239     boolean flcanhavecloud = true;
00240     tyvaluerecord v, vvers;
00241     bigstring bsvers;
00242     
00243     /*New local table*/
00244     
00245     if (!newhashtable (&ht))
00246         goto exit1; 
00247     
00248     xstruct.ht = ht;
00249     
00250     copystring (STR_xstruct, xstruct.bs);
00251     
00252     /*Compile text into XML table*/
00253     
00254     if (!xmlcompile (htext, &xstruct))
00255         goto exit1;
00256         
00257     hn = (**xstruct.ht).hfirstsort; /*Get first item.*/
00258     
00259     if (!gethashnodetable (hn, &htfirst))
00260         goto exit2;
00261 
00262     /*Get <opml> item*/
00263     
00264     if (!opxmlfindtableitem (htfirst, STR_opmldocument, &htopmldocument)) { /*Find <opml> item*/
00265         
00266         if (!opxmlfindtableitem (htfirst, STR_outlinedocument, &htopmldocument)) { /*<outlineDocument> grandfathered in*/
00267             
00268             langerrormessage (STR_errornotopml);
00269             
00270             goto exit2;
00271             } /*if*/
00272 
00273         } /*if*/
00274     
00275     // Get the version number and test for 1.1
00276     if (!opxmlgetattribute (htopmldocument, STR_version, stringvaluetype, &vvers))
00277         goto exit2;
00278 
00279     pullstringvalue (&vvers, bsvers);
00280 
00281     dateversionlessthan (bsvers, BIGSTRING ("\x03" "1.1"), &v);
00282 
00283     flcanhavecloud = !v.data.flvalue;
00284 
00285     /*Get <body> item and convert it to an outline.*/
00286     
00287     if (!opxmlfindtableitem (htopmldocument, STR_body, &htbody)) { /*<body> is not optional*/
00288 
00289         langerrormessage (STR_errornobody);
00290 
00291         goto exit2;
00292         } /*if*/
00293     
00294     oppushoutline (ho);
00295 
00296     if (!flnewoutline) { /*7.1b12 PBS: Inhibit display*/
00297 
00298         florigdisplayenabled = (**ho).flinhibitdisplay;
00299         
00300         (**ho).flinhibitdisplay = true;
00301         }
00302 
00303     if (!opxmltooutlinevisit (htbody, 0, STR_body, true)) { /*Convert XML to outline -- recursive routine*/
00304 
00305         langerrormessage (STR_errornooutlines);
00306 
00307         oppopoutline ();
00308 
00309         goto exit2;
00310 
00311         } /*if*/
00312 
00313     if (!flnewoutline) { /*7.1b12 PBS: Restore display setting; update window*/
00314         
00315         hdlwindowinfo hinfo;
00316 
00317         (**ho).flinhibitdisplay = florigdisplayenabled;
00318         
00319         if (shellfinddatawindow ((Handle) ho, &hinfo)) { /*get window info*/
00320 
00321             shellupdatenow ((**hinfo).macwindow);
00322             } /*if*/
00323         } /*if*/
00324 
00325     
00326     oppopoutline ();
00327         
00328     /*Get <head> item and set the window attributes if this is a new outline.*/
00329     
00330 //  head:
00331     
00332     disablelangerror ();
00333 
00334     flheadfound = opxmlheadexists (htopmldocument);  /* 2006-03-26 SMD - this used to call opxmlfindtableitem, which was a problem when the head element was empty */
00335 
00336     if (flnewoutline && flheadfound) {
00337         
00338         if (opxmlfindtableitem (htopmldocument, STR_head, &hthead)) {
00339             
00340             oppushoutline (ho);
00341             
00342             opxmlsetwindowatts (hthead, ho, hto, bso, vo); /*set window attributes*/
00343             
00344             oppopoutline ();
00345             }
00346         
00347         } /*if*/
00348 
00349     enablelangerror ();
00350 
00351     if (!flheadfound) { /*7.0b33 PBS: make sure there's a head section of the document.*/
00352 
00353         assert (!opxmlheadexists (htopmldocument));
00354 
00355         langerrormessage (STR_errornohead);
00356 
00357         goto exit2;
00358         } /*if*/
00359 
00360     if (hcloud != nil && flcanhavecloud) { /*7.1b43 dmb: load the cloud elements into the table*/
00361 
00362         if (!opxmlgetcloudatts (hthead, hcloud))
00363             goto exit2;
00364         }
00365     
00366     fl = true;
00367     
00368     exit2:
00369     
00370     disposehashtable (ht, false);
00371     
00372     exit1:
00373     
00374     return (fl);
00375     } /*opxmltooutline*/
00376 
00377 
00378 static boolean opxmlgetwindowscrollstate (hdloutlinerecord ho, long *ix) {
00379     
00380     /*
00381     7.0b21 PBS: get the scroll state of an outline.
00382     */
00383     
00384     tyvaluerecord val;
00385     boolean fl = false;
00386     
00387     oppushoutline (ho);
00388     
00389     if (!opgetscrollstateverb (&val)) /*Call the standard verb for getting the scroll state.*/
00390         goto exit;
00391     
00392     fl = true;
00393     
00394     *ix = val.data.longvalue;
00395     
00396     exit:
00397     
00398     oppopoutline ();
00399     
00400     disposevaluerecord (val, false);
00401     
00402     return (fl);
00403     } /*opxmlgetwindowscrollstate*/
00404 
00405 
00406 static boolean opxmlgetwindowexpansionstate (hdloutlinerecord ho, Handle *hstate) {
00407     
00408     /*
00409     7.0b21 PBS: get the expansion state.
00410     */
00411     
00412     tyvaluerecord val;
00413     boolean fl = false;
00414     char p [1];
00415     
00416     oppushoutline (ho);
00417     
00418     if (!opgetexpansionstateverb (&val)) /*Call the standard verb for getting the expansion state.*/
00419         goto exit;
00420     
00421     if (!coercevalue (&val, stringvaluetype)) /*Verb returns a list -- but a string is desired.*/
00422         goto exit;
00423     
00424     if (!copyhandle (val.data.stringvalue, hstate))
00425         goto exit;
00426     
00427     /*Remove braces from beginning and end of string.*/
00428     
00429     pullfromhandle (*hstate, gethandlesize (*hstate) - 1, 1, p); /*pop trailing brace*/
00430     
00431     pullfromhandle (*hstate, 0, 1, p); /*pop leading brace*/
00432     
00433     fl = true;
00434     
00435     exit:
00436     
00437     disposevaluerecord (val, false);
00438     
00439     oppopoutline ();
00440     
00441     return (fl);
00442     } /*opxmlgetwindowexpansionstate*/
00443 
00444 
00445 static boolean opxmlbuildtaggedstring (bigstring bstag, Handle hvalue, Handle hdest) {
00446     
00447     /*
00448     7.0b21 PBS: build a string like <tag>value</tag>.
00449     */
00450     
00451     boolean fl = false;
00452     
00453     if (!pushtexthandle (BIGSTRING ("\x01""<"), hdest)) /*<*/
00454         goto exit;
00455         
00456     if (!pushtexthandle (bstag, hdest)) /*<tag*/
00457         goto exit;
00458         
00459     if (!pushtexthandle (BIGSTRING ("\x01"">"), hdest)) /*<tag>*/
00460         goto exit;
00461         
00462     if (!pushhandle (hvalue, hdest)) /*<tag>value*/
00463         goto exit;
00464         
00465     if (!pushtexthandle (BIGSTRING ("\x02""</"), hdest)) /*<tag>value</*/
00466         goto exit;
00467         
00468     if (!pushtexthandle (bstag, hdest)) /*<tag>value</tag*/
00469         goto exit;
00470         
00471     if (!pushtexthandle (BIGSTRING ("\x01"">"), hdest)) /*<tag>value</tag>*/
00472         goto exit;
00473         
00474     fl = true; /*success*/
00475     
00476     exit:
00477     
00478     return (fl);
00479     } /*opxmlbuildtaggedstring*/
00480 
00481 
00482 static boolean opxmlpushonetag (bigstring bstag, Handle hvalue, short indentlevel, Handle htext) {
00483 
00484     /*
00485     7.0b21 PBS: Take <tag> and a value and push it on the text we're building.
00486     */
00487     
00488     Handle hdest;
00489     boolean fl = false;
00490     
00491     if (!newemptyhandle (&hdest))
00492         return (false);
00493     
00494     if (!opxmlbuildtaggedstring (bstag, hvalue, hdest))
00495         goto exit;
00496 
00497     opxmlpushhandleline (htext, hdest, indentlevel);
00498 
00499     fl = true;
00500     
00501     exit:
00502     
00503     disposehandle (hdest);
00504     
00505     return (fl);
00506     } /*opxmlpushonetag*/
00507 
00508 
00509 static boolean opxmlpushonetaglong (bigstring bstag, long v, short indentlevel, Handle htext) {
00510     
00511     /*
00512     7.0b21 PBS: push a tag line with a number value.
00513     */
00514     
00515     Handle h;
00516     bigstring bs;
00517     boolean fl = false;
00518     
00519     numbertostring (v, bs);
00520 
00521     if (!newemptyhandle (&h))
00522         return (false);
00523     
00524     if (!pushtexthandle (bs, h))
00525         goto exit;
00526     
00527     fl = opxmlpushonetag (bstag, h, indentlevel, htext);
00528     
00529     exit:
00530     
00531     disposehandle (h);
00532     
00533     return (fl);
00534     } /*opxmlpushonetaglong*/
00535 
00536 
00537 static boolean teststringvalue (const tyvaluerecord *val, bigstring legalvalues) {
00538 
00539     /*
00540     7.1b43 dmb: validate the string value against the list provided
00541     */
00542     
00543     bigstring bsval;
00544     bigstring bslegal;
00545     int i;
00546 
00547     if (legalvalues == nil)
00548         return (true);
00549     
00550     pullstringvalue (val, bsval);
00551 
00552     for (i = 0; i < countwords (legalvalues, CH_legaldelim); i++ ) {
00553 
00554         nthword (legalvalues, i, CH_legaldelim, bslegal);
00555 
00556         if (equalstrings (bslegal, bsval))
00557             return (true);
00558         }
00559 
00560     return (false);
00561     } /*teststringvalue*/
00562 
00563 
00564 static boolean opxmlpushcloudattribute (Handle htag, hdlhashtable hcloud, bigstring bsatt, bigstring legalvalues) {
00565 
00566     /*
00567     7.1b43 dmb: push the named attribute into the cloud tag, getting the value from the hcloud table
00568                 if legalvalues is not nil, it's a |-delimited list of legal string values for this attribute
00569     */
00570     
00571     tyvaluerecord v;
00572     hdlhashnode hn;
00573 
00574     if (!hashtablelookup (hcloud, bsatt, &v, &hn) ||
00575             !copyvaluerecord (v, &v) ||
00576             !coercetostring (&v) ||
00577             !teststringvalue (&v, legalvalues)) {
00578 
00579         langparamerror (cloudspecerror, bsatt);
00580 
00581         return (false);
00582         }
00583 
00584     if (!opxmlpushoneattribute (htag, bsatt, v.data.stringvalue)) //Add att to returned text.
00585         return (false);
00586 
00587     disposevaluerecord (v, false);
00588 
00589     return (true);
00590     } /*opxmlpushcloudattribute*/
00591 
00592 
00593 static boolean opxmlpushcloudtag (hdlhashtable hcloud, short indentlevel, Handle htext) {
00594     
00595     /*
00596     7.1b43 dmb: push a cloud tag with attributes coming from hcloud table values
00597     */
00598     
00599     Handle hcloudtag;
00600     boolean fl = false;
00601     
00602     if (!newtexthandle (STR_opencloud, &hcloudtag))
00603         return (false);
00604     
00605     if (!opxmlpushcloudattribute (hcloudtag, hcloud, STR_domain, nil))
00606         goto exit;
00607 
00608     if (!opxmlpushcloudattribute (hcloudtag, hcloud, STR_port, nil))
00609         goto exit;
00610 
00611     if (!opxmlpushcloudattribute (hcloudtag, hcloud, STR_path, nil))
00612         goto exit;
00613 
00614     if (!opxmlpushcloudattribute (hcloudtag, hcloud, STR_regProcedure, nil))
00615         goto exit;
00616 
00617     if (!opxmlpushcloudattribute (hcloudtag, hcloud, STR_protocol, STR_legalprotocols))
00618         goto exit;
00619 
00620     if (!pushtexthandle (BIGSTRING ("\x02" "/>"), hcloudtag))
00621         goto exit;
00622     
00623     fl = opxmlpushhandleline (htext, hcloudtag, indentlevel);
00624     
00625     exit:
00626     
00627     disposehandle (hcloudtag);
00628     
00629     return (fl);
00630     } /*opxmlpushcloudtag*/
00631 
00632 
00633 static boolean opxmlpushstringindented (bigstring bs, Handle htext, short indentlevel) {
00634     
00635     /*
00636     7.0b21 PBS: push one indent string plus a string on the returned text.
00637     */
00638     
00639     if (!opxmlpushindents (htext, indentlevel)) /*Push indent tabs*/
00640     
00641         return (false);
00642     
00643     return (pushtexthandle (bs, htext)); /*Push the string on the handle*/
00644     } /*opxmlpushstringindented*/
00645 
00646 
00647 static boolean opxmlpushoutlinetext (Handle headlinetext, Handle htext, short indentlevel) {
00648     
00649     /*
00650     7.0b21 PBS: push \t\t\t<outline text=" on the handle.
00651     */
00652     
00653     Handle h;
00654     boolean fl = false;
00655     
00656     if (!newemptyhandle (&h))
00657         return (false);
00658     
00659     if (!opxmlpushstringindented (STR_openoutlinetext, htext, indentlevel)) /*Push <outline text="*/
00660         goto exit;
00661     
00662     if (!pushhandle (headlinetext, h)) /*Make a copy.*/
00663         goto exit;
00664     
00665     if (!opxmlencodetext (h)) /*Encode the text, make it legal for XML.*/
00666         goto exit;
00667         
00668     if (!pushhandle (h, htext)) /*push encoded headline text on the handle*/
00669         goto exit;
00670         
00671     fl = pushtexthandle (STR_quot_replace, htext); /*Push closing quotation mark.*/
00672     
00673     exit:
00674     
00675     disposehandle (h);
00676     
00677     return (fl);    
00678     } /*opxmlpushoutlinetext*/
00679 
00680 
00681 static boolean opxmlpushclosingoutlinetags (Handle htext, short currlevel, short destlevel) {
00682     
00683     /*
00684     7.0b21 PBS: push closing </outline> tags until we're at the right level.
00685     */
00686     
00687     short ixlevel = currlevel;
00688     
00689     while (ixlevel > destlevel) { /*Add closing outline tags until we're at the next level.*/
00690             
00691         if (!opxmlpushstringline (htext, STR_closeoutline, ixlevel))
00692             return (false); /*error of some kind, return early*/
00693             
00694         ixlevel--;          
00695         } /*while*/
00696 
00697     return (true);
00698     } /*opxmlpushclosingoutlinetags*/
00699 
00700 
00701 static boolean opxmlpushoneattribute (Handle htext, bigstring bsname, Handle hvalue) {
00702     
00703     /*
00704     7.0b21 PBS: Push one attribute onto the returned text.
00705     */
00706     
00707     Handle h;
00708     boolean fl = false;
00709     
00710     if (!newemptyhandle (&h))
00711         return (false);
00712     
00713     if (!pushhandle (hvalue, h)) /*copy*/
00714         goto exit;
00715         
00716     if (!opxmlencodetext (h)) /*Encode special characters.*/
00717         goto exit;
00718         
00719     if (!pushtexthandle (STR_space, htext)) /*add a space character*/
00720         goto exit;
00721         
00722     if (!pushtexthandle (bsname, htext)) /*add the attribute name*/
00723         goto exit;
00724         
00725     if (!pushtexthandle (STR_equalsquotes, htext)) /*add ="*/
00726         goto exit;
00727         
00728     if (!pushhandle (h, htext)) /*add the value*/
00729         goto exit;
00730         
00731     fl = pushtexthandle (STR_quot_replace, htext); /*add "*/
00732         
00733     exit:
00734     
00735     disposehandle (h);
00736     
00737     return (fl);
00738     } /*opxmlpushoneattribute*/
00739 
00740 
00741 static boolean opxmlpushattributes (hdlheadrecord hnode, Handle htext, short indentlevel) {
00742 #pragma unused(indentlevel)
00743 
00744     /*
00745     7.0b21 PBS: push the attributes onto the current <outline> item.
00746     */
00747     
00748     tyvaluerecord v;
00749     hdlhashtable ht;
00750     hdlhashnode hn = nil, hn2 = nil;
00751     boolean fl = false;
00752     boolean flhasatts = false;
00753     Handle htrue;
00754     
00755     /*Possibly set isComment and isBreakpoint.*/
00756     
00757     if (!newemptyhandle (&htrue))
00758         return (false);
00759     
00760     if (!pushtexthandle (STR_booleantrue, htrue))
00761         goto exit;
00762     
00763     if ((**hnode).flcomment)
00764     
00765         if (!opxmlpushoneattribute (htext, STR_iscomment, htrue)) /*isComment="true"*/
00766             goto exit;
00767     
00768     if ((**hnode).flbreakpoint)
00769     
00770         if (!opxmlpushoneattribute (htext, STR_isbreakpoint, htrue)) /*isBreakpoint="true"*/
00771             goto exit;
00772     
00773     /*Get other attributes from the refcon -- the packed table.*/
00774     
00775     disablelangerror ();
00776     
00777     flhasatts = opattributesgetpackedtablevalue (hnode, &v);
00778     
00779     enablelangerror ();
00780     
00781     if (!flhasatts) {
00782         
00783         fl = true;
00784         
00785         goto exit; /*no atts -- not an error*/
00786         } /*if*/
00787     
00788     if (!tablevaltotable (v, &ht, hn))
00789         goto exit; /*Error.*/
00790     
00791     /*Loop through the table*/
00792     
00793     for (hn2 = (**ht).hfirstsort; hn2 != nil; hn2 = (**hn2).sortedlink) { 
00794         
00795         bigstring bsname;
00796 
00797         if (coercevalue (&((**hn2).val), stringvaluetype)) { /*Does the coercion to string succeed?*/
00798         
00799             gethashkey (hn2, bsname); /*Get att name*/
00800             
00801             if (!opxmlpushoneattribute (htext, bsname, (**hn2).val.data.stringvalue)) /*Add att to returned text.*/
00802                 goto exit;  
00803             } /*if*/
00804         } /*for*/
00805     
00806     fl = true; /*success*/
00807     
00808     exit:
00809     
00810     disposehandle (htrue);
00811     
00812     if (flhasatts)
00813         disposevaluerecord (v, false);
00814     
00815     return (fl);
00816     } /*opxmlpushattributes*/
00817 
00818 
00819 static boolean opxmlrecursivelyvisit (hdlheadrecord h, short lev, opvisitcallback visit, ptrvoid refcon) {
00820 
00821     register hdlheadrecord nomad, nextnomad;
00822 
00823     if (h == nil)
00824         return (true);
00825 
00826     nomad = (**h).headlinkright;
00827 
00828     if (nomad == h) /*nothing to the right*/
00829         return (true);
00830 
00831     while (true) {
00832 
00833         nextnomad = (**nomad).headlinkdown;
00834 
00835         if (!(*visit) (nomad, refcon))
00836             return (false);
00837 
00838         if (lev > 1) {
00839 
00840             if (!(**nomad).fldynamic) {
00841 
00842                 if (!oprecursivelyvisit (nomad, lev - 1, visit, refcon))
00843                     return (false);
00844                 } /*if*/
00845             }
00846 
00847         if (nextnomad == nomad) /*just processed last subhead*/
00848             return (true);
00849 
00850         nomad = nextnomad;
00851         } /*while*/
00852 
00853     } /*opxmlrecursivelyvisit*/
00854 
00855 
00856 static boolean opxmlvisitnondynamicnodes (opvisitcallback visit, ptrvoid refcon) {
00857 
00858     /*
00859     visit every node in the outline -- unless it's the child of a dynamic node.
00860     */
00861 
00862     hdlheadrecord nomad = (**outlinedata).hsummit, nextnomad;
00863 
00864     while (true) {
00865 
00866         nextnomad = (**nomad).headlinkdown;
00867 
00868         if (!(*visit) (nomad, refcon)) /*visit the summit*/
00869             return (false);
00870 
00871         if (!(**nomad).fldynamic) {
00872 
00873             if (!opxmlrecursivelyvisit (nomad, infinity, visit, refcon)) /*visit its subs*/
00874                 return (false);
00875             } /*if*/
00876 
00877         if (nextnomad == nomad)
00878             return (true);
00879 
00880         nomad = nextnomad;
00881         } /*while*/
00882 
00883     } /*opxmlvisitnondynamicnodes*/
00884 
00885 
00886 static boolean opxmlbodyvisit (hdlheadrecord hnode, ptrvoid htext) {
00887     
00888     /*
00889     7.0b21 PBS: process one headline, add it to the returned text.
00890     
00891     Look ahead to the next flatdown headline, and add a /> if no subs.
00892     If next headline is at a higher level, close off <outline> elements,
00893     as many as needed.
00894 
00895     7.0b30 PBS: handle a dynamic node -- it has subs, but pretend it doesn't,
00896 
00897     since the children should not be saved.
00898     */
00899     
00900     short indentlevel, nextlevel;
00901     Handle h;
00902     hdlheadrecord hflatdown;
00903     boolean fl = false;
00904 
00905     boolean flsubs = false;
00906     
00907     if (!copyhandle ((**hnode).headstring, &h))
00908         return (false);
00909     
00910     indentlevel = (**hnode).headlevel + 2;
00911     
00912     if (!opxmlpushoutlinetext (h, htext, indentlevel))
00913         goto exit;
00914     
00915     if (!opxmlpushattributes (hnode, htext, indentlevel))
00916         goto exit;
00917     
00918     hflatdown = opbumpflatdown (hnode, false);
00919     
00920     nextlevel = (**hflatdown).headlevel + 2;
00921     
00922     if (nextlevel == indentlevel)
00923         fl = true;
00924 
00925     if (nextlevel > indentlevel)
00926         flsubs = true;
00927 
00928     if ((**hnode).fldynamic) /*7.0b30: dynamic nodes may have subs, but we ignore them.*/
00929         flsubs = false;
00930     
00931     if (flsubs) /*Has subs?*/
00932         fl = pushtexthandle (BIGSTRING ("\x02"">\r"), htext); /*Add closing > and carriage return.*/
00933     else { /*No subs*/
00934     
00935         if (!pushtexthandle (BIGSTRING ("\x03""/>\r"), htext)) /*Add closing /> and carriage return.*/
00936             goto exit;
00937         
00938         fl = true;
00939         } /*if*/
00940     
00941     if (nextlevel < indentlevel) /*Need to close off outline items?*/
00942         fl = opxmlpushclosingoutlinetags (htext, indentlevel, nextlevel); /*Add as many </outline> tags as needed.*/
00943     
00944     if (hnode == hflatdown) /*At the end of the outline?*/
00945         fl = opxmlpushclosingoutlinetags (htext, indentlevel, 2); /*Add as many </outline> tags as needed.*/
00946     
00947 exit:
00948     
00949     disposehandle (h);
00950     
00951     return (fl);
00952     } /*opxmlbodyvisit*/
00953 
00954 
00955 static boolean opxmlbuildbody (hdloutlinerecord ho, Handle htext, short indentlevel) {
00956     
00957     /*
00958     7.0b21 PBS: Build the <body> section.
00959 
00960     7.0b30 PBS: don't save children of dynamic headlines.
00961     
00962     2006-02-27 aradke: de-hoist outline before collecting body text to capture all nodes, avoids data loss
00963         http://sourceforge.net/tracker/index.php?func=detail&aid=1259245&group_id=120666&atid=687798
00964     */
00965     
00966     boolean flpoppedhoists;
00967     boolean fl = false;
00968     
00969     if (!opxmlpushstringline (htext, STR_openbody, indentlevel)) /*<body>*/
00970         goto exit;
00971 
00972     indentlevel++;
00973     
00974     oppushoutline (ho);
00975     
00976     flpoppedhoists = oppopallhoists (); /*2006-02-27 aradke: needs outline pushed*/
00977     
00978     if (!opxmlvisitnondynamicnodes (&opxmlbodyvisit, htext)) /*visit every headline, top to bottom, calling opxmlbodyvisit on each*/
00979         goto exit;
00980     
00981     if (flpoppedhoists) /*2006-02-27 aradke*/
00982         oprestorehoists ();
00983     
00984     oppopoutline ();
00985     
00986     fl = opxmlpushstringline (htext, STR_closebody, indentlevel); /*</body>*/
00987 
00988     exit:
00989     
00990     return (fl);
00991     } /*opxmlbuildbody*/
00992 
00993 
00994 static boolean opxmlensureopenwindow (hdloutlinerecord ho, hdlhashtable hto, bigstring bso, tyvaluerecord vo, hdlwindowinfo *hinfo, boolean *flwasopen) {
00995     
00996     /*
00997     7.0b21 PBS: make sure the window is open. *hinfo gets the window info.
00998     */
00999     
01000     *flwasopen = true;
01001     
01002     if (!shellfinddatawindow ((Handle) ho, hinfo)) { /*try to find window -- it might be open*/
01003         
01004         *flwasopen = false;
01005         
01006         if (!langzoomvalwindow  (hto, bso, vo, false)) /*open window*/
01007             return (false);
01008         } /*if*/
01009         
01010     if (!shellfinddatawindow ((Handle) ho, hinfo)) /*get window info*/
01011         return (false);
01012 
01013     return (true);
01014     } /*opxmlensureopenwindow*/
01015 
01016 
01017 static boolean opxmlbuildhead (Handle htext, hdloutlinerecord ho, Handle hname, Handle hemail, short indentlevel, hdlwindowinfo hinfo, hdlhashtable hcloud) {
01018     
01019     /*
01020     7.0b21 PBS: build the <head> section of the document.
01021     
01022     First get info about the window -- title, rect, etc. -- then push the tagged values on the returned text.
01023     */
01024     
01025     long scrollstate;
01026     Handle hexpansionstate;
01027     Rect r;
01028     boolean fl = false;
01029     unsigned long timecreated, timemodified;
01030     tyvaluerecord vtimecreated, vtimemodified;
01031     bigstring bstitle;
01032     Handle htitle;
01033     
01034     /*Get window info.*/
01035     
01036     if (!opxmlgetwindowscrollstate (ho, &scrollstate)) /*vertical scroll state*/
01037         return (false);
01038     
01039     if (!opxmlgetwindowexpansionstate (ho, &hexpansionstate)) /*expansion state*/
01040         goto exit;
01041         
01042     if (!shellgetglobalwindowrect (hinfo, &r)) /*window rect*/
01043         goto exit;
01044     
01045     shellgetwindowtitle (hinfo, bstitle); /*window title -- no return value*/
01046     
01047     timecreated = (**ho).timecreated; /*time created*/
01048     
01049     timemodified = (**ho).timelastsave; /*time last saved*/
01050     
01051     if (!datenetstandardstring (timecreated, &vtimecreated)) /*Convert to date net standard strings*/
01052         goto exit;
01053     
01054     if (!datenetstandardstring (timemodified, &vtimemodified))
01055         goto exit2;
01056         
01057     /*Push head items*/
01058     
01059     if (!opxmlpushstringline (htext, STR_openhead, indentlevel))                            /*<head>*/
01060         goto exit3;
01061     
01062     indentlevel++;
01063     
01064     if (!newemptyhandle (&htitle))
01065         goto exit3;
01066     
01067     if (!pushtexthandle (bstitle, htitle))
01068         goto exit3;
01069     
01070     if (!opxmlpushonetag (STR_title, htitle, indentlevel, htext))                               /*<title>*/
01071         goto exit3;
01072     
01073     disposehandle (htitle);
01074     
01075     if (!opxmlpushonetag (STR_datecreated, vtimecreated.data.stringvalue, indentlevel, htext))  /*<dateCreated>*/
01076         goto exit3;
01077     
01078     if (!opxmlpushonetag (STR_datemodified, vtimemodified.data.stringvalue, indentlevel, htext))/*<dateModified>*/
01079         goto exit3;
01080     
01081     if (!opxmlpushonetag (STR_ownername, hname, indentlevel, htext))                            /*<ownerName>*/
01082         goto exit3;
01083     
01084     if (!opxmlpushonetag (STR_owneremail, hemail, indentlevel, htext))                          /*<ownerEmail>*/
01085         goto exit3;
01086     
01087     if (!opxmlpushonetag (STR_expansionstate, hexpansionstate, indentlevel, htext))             /*<expansionState>*/    
01088         goto exit3;
01089     
01090     if (!opxmlpushonetaglong (STR_vertscrollstate, scrollstate, indentlevel, htext))            /*<vertScrollState>*/
01091         goto exit3;
01092     
01093     if (!opxmlpushonetaglong (STR_windowtop, r.top, indentlevel, htext))                        /*<windowTop>*/
01094         goto exit3;
01095     
01096     if (!opxmlpushonetaglong (STR_windowleft, r.left, indentlevel, htext))                      /*<windowLeft>*/
01097         goto exit3;
01098     
01099     if (!opxmlpushonetaglong (STR_windowbottom, r.bottom, indentlevel, htext))                  /*<windowBottom>*/
01100         goto exit3;
01101 
01102     if (!opxmlpushonetaglong (STR_windowright, r.right, indentlevel, htext))                    /*<windowRight>*/
01103         goto exit3;
01104 
01105     if (hcloud != nil)
01106         if (!opxmlpushcloudtag (hcloud, indentlevel, htext))
01107             goto exit3;
01108 
01109     if (!opxmlpushstringline (htext, STR_closehead, indentlevel))                               /*</head>*/
01110         goto exit3;
01111     
01112     fl = true; /*success*/
01113     
01114     /*Clean up*/
01115     
01116 exit3:
01117     
01118     disposevaluerecord (vtimemodified, false);
01119     
01120 exit2:
01121     
01122     disposevaluerecord (vtimecreated, false);
01123     
01124 exit:
01125     
01126     disposehandle (hexpansionstate);
01127     
01128     return (fl);
01129     } /*opxmlbuildhead*/
01130 
01131 
01132 static boolean opxmlencodetext (Handle htext) {
01133     
01134     /*
01135     7.0b21 PBS: encode text -- translate & to &amp;, etc.
01136     
01137     The opposite translation happens in
01138     opxmldecodetext when converting from XML
01139     to an outline.
01140     */
01141     
01142     if (!replaceallinhandle (STR_amp_replace, STR_amp, htext))
01143         return (false);
01144     
01145     if (!replaceallinhandle (STR_quot_replace, STR_quot, htext))
01146         return (false);
01147     
01148     if (!replaceallinhandle (STR_lt_replace, STR_lt, htext))
01149         return (false);
01150     
01151     if (!replaceallinhandle (STR_gt_replace, STR_gt, htext))
01152         return (false);
01153 
01154     return (true);
01155     } /*opxmlencodetext*/
01156 
01157 
01158 static boolean opxmldecodetext (Handle htext) {
01159     
01160     /*
01161     7.0b21 PBS: decode text -- translate &amp; to &, etc.
01162     
01163     This is the inverse of opxmlencodetext.
01164     */
01165     
01166     replaceallinhandle (STR_quot, STR_quot_replace, htext);
01167     
01168     replaceallinhandle (STR_lt, STR_lt_replace, htext); 
01169 
01170     replaceallinhandle (STR_gt, STR_gt_replace, htext); 
01171 
01172     replaceallinhandle (STR_amp, STR_amp_replace, htext);
01173 
01174     return (true);
01175     } /*opxmldecodetext*/
01176 
01177 
01178 static boolean opxmlpushindents (Handle htext, short indentlevel) {
01179     
01180     /*
01181     7.0b21 PBS: push indentlevel \t's at the end of htext.
01182     */
01183     
01184     bigstring bs;
01185     short ix = 1;
01186     
01187     if (indentlevel < 1)
01188         return (true); /*nothing to do*/
01189     
01190     setemptystring (bs);
01191     
01192     if (indentlevel > 255) /*maximum indentlevel is maximum characters in a bigstring*/
01193         indentlevel = 255; /*indentlevel might be larger -- that's alright -- just stop pretty printing at this absurd level*/
01194     
01195     setstringlength (bs, indentlevel);
01196     
01197     while (ix <= indentlevel) {
01198         
01199         bs [ix] = '\t'; /*Add a \t to the indent string*/
01200         
01201         ix++;
01202         } /*while*/
01203     
01204     return (pushtexthandle (bs, htext)); /*push indents at the end of htext*/
01205     } /*opxmlpushindents*/
01206 
01207 
01208 static boolean opxmlpushstringline (Handle htext, bigstring bs, short indentlevel) {
01209     
01210     /*
01211     7.0b21 PBS: push a string that's an entire line, such as the XML header. Add
01212     a \r to the end.
01213     
01214     This the equivalent of the Frontier line: xmltext = xmltext + string.filledString ("\t", indentlevel) + s + "\r"
01215     */
01216     
01217     if (!opxmlpushindents (htext, indentlevel)) /*Add \t characters.*/
01218         return (false);
01219     
01220     if (!pushtexthandle (bs, htext)) /*Add string to htext.*/
01221         return (false);
01222     
01223     return (pushtexthandle (BIGSTRING ("\x01" "\r"), htext)); /*Add \r to htext.*/
01224     } /*opxmlpushstringline*/
01225 
01226 
01227 static boolean opxmlpushhandleline (Handle htext, Handle h, short indentlevel) {
01228 
01229     /*
01230     7.0b21 PBS: push a handle that's an entire line, such as the XML header. Add
01231     a \r to the end.
01232     
01233     This the equivalent of the Frontier line: xmltext = xmltext + string.filledString ("\t", indentlevel) + s + "\r"
01234     */
01235 
01236     if (!opxmlpushindents (htext, indentlevel)) /*Add \t characters.*/
01237         return (false);
01238     
01239     if (!pushhandle (h, htext)) /*Add h to htext.*/
01240         return (false);
01241     
01242     return (pushtexthandle (BIGSTRING ("\x01" "\r"), htext)); /*Add \r to htext.*/
01243     } /*opxmlpushhandleline*/
01244     
01245 
01246 static boolean opxmlfindtableitem (hdlhashtable ht, bigstring bsname, hdlhashtable *htfound) {
01247     
01248     /*
01249     7.0b21 PBS: find one table item in a table, such as an <outlineDocument>,
01250     <head>, or <body> item.
01251     */
01252     
01253     hdlhashnode hn;
01254     
01255     for (hn = (**ht).hfirstsort; hn != nil; hn = (**hn).sortedlink) { /*loop through the table*/
01256         
01257         if (isxmlmatch (hn, bsname)) { /*is this the name we're looking for?*/
01258             
01259             if (gethashnodetable (hn, htfound)) { /*Try to get the table*/
01260             
01261                 return (true); /*Found, it's a table, return true.*/
01262                 } /*if*/
01263             } /*if*/
01264         } /*for*/
01265 
01266     return (false);
01267     } /*opxmlfindtableitem*/
01268 
01269 
01270 static boolean opxmlheadexists (hdlhashtable ht) {
01271 
01272     /*
01273     7.0b33 PBS: return true if there's a required <head> section of the document.
01274     */
01275 
01276     hdlhashnode hn;
01277 
01278     for (hn = (**ht).hfirstsort; hn != nil; hn = (**hn).sortedlink) { /*loop through the table*/
01279 
01280         if (isxmlmatch (hn, STR_head)) /*is this the name we're looking for?*/
01281             return (true); /*Found; return true.*/
01282         } /*for*/
01283 
01284     return (false);
01285     } /*opxmlheadexists*/
01286 
01287 
01288 static boolean opxmlgetonevalue (hdlhashtable ht, bigstring bsname, Handle htext) {
01289     
01290     /*
01291     7.0b21 PBS: get the value of one item from a table.
01292     
01293     Everything is text at this level -- if you're not expecting text,
01294     don't use this routine. Other wrapper routines convert from text
01295     to numbers or lists or whatever.
01296     */
01297     
01298     tyvaluerecord val;
01299     hdlhashnode hn;
01300     boolean fl = false;
01301     
01302     for (hn = (**ht).hfirstsort; hn != nil; hn = (**hn).sortedlink) {
01303         
01304         if (isxmlmatch (hn, bsname)) {
01305         
01306             val = (**hn).val;
01307             
01308             if (val.valuetype == stringvaluetype) { /*Everything we're looking for is expected to be a string. Check anyway.*/
01309             
01310                 if (copyhandlecontents (val.data.stringvalue, htext)) {
01311                 
01312                     fl = true;
01313                     } /*if*/
01314                 } /*if*/
01315                 
01316             break; /*Break once the item has been found, whether or not htext contains the data sought.*/
01317             } /*if*/
01318         } /*for*/
01319 
01320     return (fl);
01321     } /*opxmlgetonevalue*/
01322 
01323 
01324 static boolean opxmlgetonelongvalue (hdlhashtable ht, bigstring bsname, long *v) {
01325     
01326     /*
01327     7.0b21 PBS: get one long value. See comments in opxmlgetoneshortvalue.
01328     */
01329     
01330     Handle h;
01331     bigstring bs;
01332     
01333     newemptyhandle (&h);
01334     
01335     if (!opxmlgetonevalue (ht, bsname, h)) /*Get value in Handle h*/
01336         return (false);
01337     
01338     texthandletostring (h, bs); /*Convert to bigstring -- it's going to be a number, so a bigstring's size limit is okay*/
01339     
01340     disposehandle (h);
01341     
01342     return (stringtonumber (bs, v)); /*Convert bigstring to a long*/
01343     } /*opxmlgetonelongvalue*/
01344 
01345 
01346 static boolean opxmlgetoneshortvalue (hdlhashtable ht, bigstring bsname, short *v) {
01347     
01348     /*
01349     7.0b21 PBS: get one number value.
01350     
01351     This function goes from handle to bigstring to short. Why? Because I wanted just one
01352     routine that gets the value -- that's opxmlgetonevalue. All other routines use
01353     that routine to get a value, then do coercions. Is that a performance problem? I seriously
01354     doubt it, but testing will tell.
01355     */
01356     
01357     Handle h;
01358     bigstring bs;
01359     
01360     newemptyhandle (&h);
01361     
01362     if (!opxmlgetonevalue (ht, bsname, h)) /*Get value in Handle h*/
01363         return (false);
01364     
01365     texthandletostring (h, bs); /*Convert to bigstring -- it's going to be a number, so a bigstring's size limit is okay*/
01366     
01367     disposehandle (h);
01368     
01369     return (stringtoshort (bs, v)); /*Convert bigstring to a short*/
01370     } /*opxmlgetoneshortvalue*/
01371 
01372 
01373 static boolean opxmlsetwindowpositionandsize (hdlhashtable ht, hdlwindowinfo hinfo) {
01374     
01375     /*
01376     7.0b21 PBS: set the window's position and size.
01377     
01378     Get windowtop, windowleft, windowbottom, and windowright from the <head>
01379     section of the XML.
01380     
01381     Even though the return value is ignored by opxmlsetwindowatts, this script still returns
01382     a boolean just in case at some point later someone does care about success or failure.
01383     */
01384     
01385     short windowtop, windowleft, windowbottom, windowright;
01386     
01387     /*Set window position*/
01388 
01389     if (!opxmlgetoneshortvalue (ht, STR_windowtop, &windowtop))
01390         return (false);
01391 
01392     if (!opxmlgetoneshortvalue (ht, STR_windowleft, &windowleft))
01393         return (false);
01394     
01395 //  if (!shellmovewindow (hinfo, windowleft, windowtop)) /*Set window position*/
01396 //      return (false); /*shellmovewindow always returns true at this writing, but that could change*/
01397 
01398     if (!shellmovewindowhidden (hinfo, windowleft, windowtop)) /*Set window position*/
01399         return (false); /*shellmovewindow always returns true at this writing, but that could change*/
01400     
01401     /*Set the window size*/
01402 
01403     if (!opxmlgetoneshortvalue (ht, STR_windowright, &windowright))
01404         return (false);
01405     
01406     if (!opxmlgetoneshortvalue (ht, STR_windowbottom, &windowbottom))
01407         return (false);
01408     
01409     if (!shellsizewindowhidden (hinfo, windowright - windowleft, windowbottom - windowtop)) /*Set window size*/
01410         return (false); /*shellsizewindow returns false if the window isn't growable*/
01411 
01412     return (true);
01413     } /*opxmlsetwindowpositionandsize*/
01414 
01415 
01416 static boolean opxmlsetwindowtitle (hdlhashtable ht, hdlwindowinfo hinfo) {
01417     
01418     /*
01419     7.0b21 PBS: set the window title.
01420     */
01421     
01422     Handle htext;
01423     bigstring bstitle;
01424     
01425     if (!newemptyhandle (&htext))
01426         return (false);
01427     
01428     if (!opxmlgetonevalue (ht, STR_title, htext)) /*Get the <title> value*/
01429         return (false);
01430     
01431     texthandletostring (htext, bstitle); /*Convert to bigstring -- window titles are bigstrings*/
01432     
01433     return (shellsetwindowtitle (hinfo, bstitle)); /*Set the window title*/
01434     } /*opxmlsetwindowtitle*/
01435 
01436 
01437 static boolean opxmlsetwindowexpansionstate (hdlhashtable ht, hdlwindowinfo hinfo) {
01438     
01439     /*
01440     7.0b21 PBS: set the expansion state for a window.
01441     */
01442     
01443     Handle htext;
01444     tyvaluerecord val, v;
01445     boolean fl = false;
01446     
01447     if (!newemptyhandle (&htext))
01448         return (false);
01449     
01450     if (!opxmlgetonevalue (ht, STR_expansionstate, htext))
01451         goto exit1;
01452     
01453     /*Surround text with { and }, so it can be coerced to a list.*/
01454     
01455     if (!insertinhandle (htext, 0, "{", 1)) /*text = { + text*/
01456         goto exit1;
01457 
01458     if (!pushtexthandle (BIGSTRING ("\x01" "}"), htext)) /*text = text + }*/
01459         goto exit1;
01460     
01461     /*Create a value record containing the text.*/
01462     
01463     initvalue (&val, stringvaluetype); /*no return value*/
01464     
01465     val.data.stringvalue = htext;
01466     
01467     /*Coerce to a list.*/
01468     
01469     if (!coercevalue (&val, listvaluetype))
01470         goto exit2;
01471     
01472     /*Set the expansion state of the window.*/
01473     
01474     if (!shellpushwindowglobals (hinfo)) /*Make our window the current window, so it can be updated.*/
01475         goto exit2;
01476         
01477     fl = opsetexpansionstateverb (&val, &v); /*v is asked for but never referenced.*/
01478 
01479     //shellsetscrollbars ((**hinfo).macwindow); /*Update scroll bars*/
01480     
01481     shellpopglobals (); /*Finished updating.*/
01482     
01483     exit2:
01484     
01485     disposevaluerecord (val, false); /*disposes htext*/
01486     
01487     htext = nil;
01488     
01489 exit1:
01490     
01491     if (htext != nil)
01492         disposehandle (htext);
01493     
01494     return (fl);
01495     } /*opxmlsetwindowexpansionstate*/
01496 
01497 
01498 static boolean opxmlsetwindowverticalscrollstate (hdlhashtable ht, hdlwindowinfo hinfo) {
01499     
01500     /*
01501     7.0b21 PBS: set vertical scroll state for the outline window.
01502 
01503     7.0b22 PBS: fix display glitch by updating the outline window.
01504 
01505 
01506 
01507     7.0b23 PBS: display glitch fix part two -- set hline1 to hbarcursor, not the
01508 
01509     other way around. It's hbarcursor that's correct.
01510     */
01511     
01512     long line1;
01513     tyvaluerecord val; /*needed by opsetscrollstateverb*/
01514     hdlwindowinfo oldoutlinewindow;
01515     
01516     if (!opxmlgetonelongvalue (ht, STR_vertscrollstate, &line1)) /*Get vertical scroll state number.*/
01517         return (false);
01518 
01519     if (!shellpushwindowglobals (hinfo)) /*Push window globals so the window can be updated.*/
01520         return (false);
01521 
01522     opsetscrollstateverb (line1, &val); /*return value is uninteresting*/
01523 
01524     (**outlinedata).hline1 = (**outlinedata).hbarcursor; /*7.0b23: these were switched, now they're correct.*/
01525 
01526     /*7.0b22 PBS: update the window, fix display glitch.*/
01527 
01528     oldoutlinewindow = outlinewindowinfo;
01529 
01530     outlinewindowinfo = hinfo;
01531 
01532     oppushoutline (outlinedata);
01533 
01534     oppostfontchange (); /*adjust display area*/
01535         
01536     opresetscrollbars (); /*make sure scrollbars are accurate*/
01537 
01538     #ifdef MACVERSION
01539     
01540         shellupdatewindow ((**hinfo).macwindow);
01541 
01542     #endif
01543     
01544     outlinewindowinfo = oldoutlinewindow;
01545 
01546     oppopoutline ();
01547 
01548     shellpopglobals (); /*Finished updating*/
01549     
01550     disposevaluerecord (val, false);
01551     
01552     return (true);
01553     } /*opxmlsetwindowverticalscrollstate*/
01554 
01555 
01556 static boolean opxmlsetwindowatts (hdlhashtable ht, hdloutlinerecord ho, hdlhashtable hto, bigstring bso, tyvaluerecord vo) {
01557     
01558     /*
01559     7.0b21 PBS: set window attributes from the head section of the outlineDocument.
01560     */
01561     
01562     hdlwindowinfo hinfo;
01563     
01564     /*Open window as hidden. Get window info handle.*/
01565     
01566     if (!langzoomvalwindow  (hto, bso, vo, false)) /*open window*/
01567         return (false);
01568         
01569     if (!shellfinddatawindow ((Handle) ho, &hinfo)) /*get window info*/
01570         return (false);
01571     
01572     /*Set window position and size.*/
01573     
01574     opxmlsetwindowpositionandsize (ht, hinfo); /*Errors are non-fatal -- in the script this is in a try block*/
01575     
01576     /*Set expansion state.*/
01577     
01578     oppushoutline (ho);
01579     
01580     opxmlsetwindowexpansionstate (ht, hinfo); /*Errors non-fatal*/
01581     
01582     oppopoutline ();
01583     
01584     /*Set vertical scroll state.*/
01585     
01586     oppushoutline (ho);
01587 
01588     opxmlsetwindowverticalscrollstate (ht, hinfo); /*Errors non-fatal*/
01589     
01590     oppopoutline ();
01591 
01592     /*Set window title.*/
01593     
01594     opxmlsetwindowtitle (ht, hinfo); /*Errors non-fatal*/
01595 
01596     return (true);  
01597     } /*opxmlsetwindowatts*/
01598 
01599 
01600 static boolean opxmlgetattribute (hdlhashtable ht, bigstring bsname, tyvaluetype type, tyvaluerecord *val) {
01601 
01602     /*
01603     12/19/01 dmb: get one attribute value of the given type. val result is a temp value
01604     */
01605     
01606     hdlhashnode hn;
01607 
01608     if (!xmlgetattribute (ht, bsname, &ht)) /*find the attribute in the /atts table*/
01609         return (false);
01610     
01611     if (!hashtablelookup (ht, bsname, val, &hn)) /*find the hash node*/
01612         return (false);
01613     
01614     if (!copyvaluerecord (*val, val))
01615         return (false);
01616 
01617     if (type != novaluetype)
01618         if (!coercevalue (val, type))
01619             return (false);
01620 
01621     return (true);
01622     } /*opxmlgetattribute*/
01623 
01624 
01625 static boolean opxmlpullcloudattribute (hdlhashtable ht, bigstring bsatt, tyvaluetype type, bigstring legalvalues, hdlhashtable hatts) {
01626 
01627     /*
01628     12/19/01 dmb: pull an attribute out of ht and put it into hatts
01629     */
01630 
01631     tyvaluerecord val;
01632     boolean fl;
01633 
01634     disablelangerror();
01635 
01636     fl = opxmlgetattribute (ht, bsatt, type, &val) && teststringvalue (&val, legalvalues);
01637 
01638     enablelangerror();
01639 
01640     if (!fl) {
01641 
01642         langparamerror (cloudelementerror, bsatt);
01643 
01644         return (false);
01645         }
01646 
01647     if (!hashtableassign (hatts, bsatt, val))
01648         return (false);
01649     
01650     exemptfromtmpstack (&val);
01651 
01652     return (true);
01653     } /*opxmlpullattribute*/
01654 
01655 
01656 static boolean opxmlgetcloudatts (hdlhashtable hhead, hdlhashtable hcloud) {
01657     
01658     /*
01659     7.1b43 dmb: get the cloud attributes from the head section of the outlineDocument.
01660                 populdate hcloud with the values
01661     */
01662 
01663     hdlhashtable hcloudtag;
01664     
01665     if (hcloud == nil)
01666         return (true);
01667 
01668     if (!opxmlfindtableitem (hhead, STR_cloud, &hcloudtag))
01669         return (false);
01670 
01671     if (!opxmlpullcloudattribute (hcloudtag, STR_domain, stringvaluetype, nil, hcloud))
01672         return (false);
01673 
01674     if (!opxmlpullcloudattribute (hcloudtag, STR_port, intvaluetype, nil, hcloud))
01675         return (false);
01676 
01677     if (!opxmlpullcloudattribute (hcloudtag, STR_path, stringvaluetype, nil, hcloud))
01678         return (false);
01679 
01680     if (!opxmlpullcloudattribute (hcloudtag, STR_regProcedure, stringvaluetype, nil, hcloud))
01681         return (false);
01682 
01683     if (!opxmlpullcloudattribute (hcloudtag, STR_protocol, stringvaluetype, STR_legalprotocols, hcloud))
01684         return (false);
01685 
01686     return (true);
01687     } /*opxmlgetcloudatts*/
01688 
01689 
01690 static boolean opxmlgetheadlinetextfromatts (hdlhashtable ht, Handle htext) {
01691     
01692     /*
01693     7.0b21 PBS: get the headline text from an <outline...> item.
01694     */
01695     
01696     tyvaluerecord val, vcopy;
01697     hdlhashnode hnode;
01698     
01699     if (!xmlgetattribute (ht, STR_textitemname, &ht)) /*find the attribute in the /atts table*/
01700         return (false);
01701     
01702     if (!hashtablelookup (ht, STR_textitemname, &val, &hnode)) /*find the hash node*/
01703         return (true); /*Not an error -- text is optional attribute.*/
01704     
01705     copyvaluerecord (val, &vcopy);
01706     
01707     if (!copyhandlecontents (vcopy.data.stringvalue, htext))
01708         return (false);
01709     
01710     /*Replace entities with the real characters.*/
01711     
01712     opxmldecodetext (htext);
01713     
01714     disposevaluerecord (vcopy, false);
01715     
01716     return (true);
01717     } /*opxmlgetheadlinetextfromatts*/
01718 
01719 
01720 static boolean opxmldeleteitemfromatts (hdlhashtable htatts, bigstring bsitemtodelete) {
01721     
01722     /*
01723     7.0b21 PBS: delete an item from the /atts table.
01724     
01725     If item is not found, it's not an error.
01726     */
01727     
01728     if (!pushhashtable (htatts))
01729         return (false);
01730 
01731     disablelangerror (); /*if not found, not an error*/
01732     
01733     hashdelete (bsitemtodelete, true, false);
01734     
01735     enablelangerror ();
01736     
01737     if (!pophashtable ())
01738         return (false);
01739     
01740     return (true);
01741     } /*opxmldeleteitemfromatts*/
01742 
01743 
01744 static boolean opxmldecodeattstablevalues (hdlhashtable ht) {
01745     
01746     /*
01747     7.0b21 PBS: Decode all string values in the atts table.
01748     */
01749     
01750     tyvaluerecord val;
01751     hdlhashnode hn;
01752     boolean fl = false;
01753     
01754     for (hn = (**ht).hfirstsort; hn != nil; hn = (**hn).sortedlink) {
01755         
01756             val = (**hn).val;
01757             
01758             if (val.valuetype == stringvaluetype) /*Decode text only.*/
01759                 
01760                 opxmldecodetext (val.data.stringvalue); /*Decode this text.*/       
01761         } /*for*/
01762 
01763     fl = true; /*Success*/
01764     
01765     return (fl);
01766     } /*opxmldecodeattstablevalues*/
01767 
01768 
01769 static boolean opxmlsetrefcon (hdlhashtable ht) {
01770     
01771     /*
01772     7.0b21 PBS: set the nodetype refcon.
01773     
01774     If ht contains an /atts table, pack the table, pack into a binary,
01775     then set the refcon to the packed binary.
01776     */
01777     
01778     hdlhashtable htatts;
01779     tyvaluerecord val;
01780     hdlhashnode hnode;
01781     Handle hpackedtable, hpackedbinary;
01782     tyvaluerecord vbinary;
01783     hdlheadrecord hbarcursor;
01784     boolean fl = false;
01785     
01786     /*Get the /atts table.*/
01787 
01788     if (!hashtablelookup (ht, STR_attstablename, &val, &hnode)) /*Is there an /atts table?*/
01789         return (false);
01790 
01791     if (!langexternalvaltotable (val, &htatts, hnode)) /*Try to get the atts table*/
01792         goto exit1;
01793     
01794     /*Delete the text, isBreakpoint, and isComment items from the /atts table.*/
01795     
01796     opxmldeleteitemfromatts (htatts, STR_textitemname); /*text*/
01797     
01798     opxmldeleteitemfromatts (htatts, STR_isbreakpoint); /*isBreakpoint*/
01799     
01800     opxmldeleteitemfromatts (htatts, STR_iscomment); /*isComment*/
01801     
01802     /*Decode values in the atts table.*/
01803     
01804     opxmldecodeattstablevalues (htatts);
01805     
01806     /*Pack the table; pack the binary.*/
01807     
01808     if (!langpackvalue (val, &hpackedtable, HNoNode)) /*Try to pack the table*/
01809         goto exit1;
01810     
01811     initvalue (&vbinary, binaryvaluetype);
01812     
01813     vbinary.data.binaryvalue = hpackedtable;
01814     
01815     if (!langpackvalue (vbinary, &hpackedbinary, HNoNode)) /*try to pack the binary*/
01816         goto exit2;
01817     
01818     /*Set the refcon.*/
01819     
01820     hbarcursor = (**outlinedata).hbarcursor;
01821     
01822     disposehandle ((**hbarcursor).hrefcon); /*dispose old refcon*/
01823 
01824     (**hbarcursor).hrefcon = hpackedbinary;
01825     
01826     fl = true; /*success*/
01827         
01828 exit2:
01829     
01830     disposevaluerecord (vbinary, false);
01831     
01832 exit1:
01833         
01834     return (fl);
01835     } /*opxmlsetrefcon*/
01836 
01837 
01838 static boolean opxmlsetcommentandbreakpoint (hdlhashtable ht) {
01839     
01840     /*
01841     7.0b21 PBS: set the comment and breakpoint atts of this headline, if present.
01842     */
01843     
01844     hdlhashtable htatts;
01845     tyvaluerecord val;
01846     hdlhashnode hnode;
01847     boolean fl = false;
01848     bigstring bs;
01849     hdlheadrecord hcursor;
01850     
01851     /*Get the /atts table.*/
01852 
01853     if (!hashtablelookup (ht, STR_attstablename, &val, &hnode)) /*Is there an /atts table?*/
01854         return (false);
01855     
01856     if (!langexternalvaltotable (val, &htatts, hnode)) /*Try to get the atts table*/
01857         goto exit;
01858     
01859     hcursor = (**outlinedata).hbarcursor;
01860     
01861     /*Is this is a comment?*/
01862         
01863     if (hashtablelookup (htatts, STR_iscomment, &val, &hnode)) {
01864         
01865         if (val.valuetype == stringvaluetype) {
01866             
01867             texthandletostring (val.data.stringvalue, bs);
01868             
01869             if (equalidentifiers (bs, STR_booleantrue))
01870             
01871                 (**hcursor).flcomment = true;
01872             } /*if*/
01873         } /*if*/
01874     
01875     /*Is this a breakpoint?*/
01876     
01877     if (hashtablelookup (htatts, STR_isbreakpoint, &val, &hnode)) {
01878         
01879         if (val.valuetype == stringvaluetype) {
01880             
01881             texthandletostring (val.data.stringvalue, bs);
01882             
01883             if (equalidentifiers (bs, STR_booleantrue))
01884             
01885                 (**hcursor).flbreakpoint = true;
01886             } /*if*/
01887         } /*if*/
01888     
01889     fl = true; /*success*/
01890     
01891 exit:
01892     
01893     return (fl);
01894     } /*opxmlsetcommentandbreakpoint*/
01895 
01896 
01897 extern boolean opsetheadtext (hdlheadrecord hnode, Handle hstring);
01898 
01899 static boolean opxmltooutlinevisit (hdlhashtable ht, short ixlevel, bigstring bsname, boolean flfirstline) {
01900 #pragma unused (bsname)
01901 
01902     /*
01903     7.0b21 PBS -- recursive routine for converting an XML outlineDocument structure to an outline structure.
01904     */
01905     
01906     hdlhashnode hn;
01907     tydirection dir = right;
01908     boolean flatleastoneinserted = false;
01909     hdlhashtable h;
01910 
01911     /*loop through all of the items in the table*/
01912     
01913     for (hn = (**ht).hfirstsort; hn != nil; hn = (**hn).sortedlink) {
01914         
01915         Handle htext;
01916         bigstring nameitem;
01917                         
01918         if (langexternalgettype ((**hn).val) == idtableprocessor) {
01919     
01920             gethashkey (hn, nameitem);
01921         
01922             xmlgetname (nameitem);
01923             
01924             alllower (nameitem);
01925             
01926             if (equalidentifiers (STR_outlinetag, nameitem)) { /*is it an <outline...> item?*/
01927                         
01928                 gethashnodetable (hn, &h);
01929                 
01930                 newemptyhandle (&htext);
01931                 
01932                 oppushoutline (outlinedata);
01933                 
01934                 opxmlgetheadlinetextfromatts (h, htext); /*text att is optional, so htext may be empty, which is okay.*/
01935                                         
01936                 if (flfirstline) { /*is it the very first headline in the XML file?*/
01937 
01938                     opsetheadtext ((**outlinedata).hbarcursor, htext); /*consumes htext*/
01939                     
01940                     flfirstline = false;
01941                     } /*if*/
01942                 
01943                 else {                  
01944         
01945                     opinserthandle (htext, dir);
01946                     
01947                     disposehandle (htext);
01948 
01949                     } /*else*/
01950                 
01951                 oppopoutline ();
01952                     
01953                 opxmlsetcommentandbreakpoint (h); /*Set comment and breakpoint attributes.*/
01954                 
01955                 opxmlsetrefcon (h); /*Set the refcon -- node types*/
01956                 
01957                 dir = down;
01958                 
01959                 flatleastoneinserted = true;
01960                 
01961                 } /*if*/
01962 
01963             switch (getstringcharacter (nameitem, 0)) {
01964             
01965                 case '/': /*special tables*/
01966                 case '?': 
01967                     break;
01968                 
01969                 default:
01970 
01971                     gethashnodetable (hn, &ht);
01972                     
01973                     if (opxmltooutlinevisit (ht, ixlevel + 1, nameitem, flfirstline))
01974                     
01975                         opmotionkey (left, 1, false);                   
01976                 } /*switch*/
01977             } /*if*/
01978         } /*for*/
01979     
01980     return (flatleastoneinserted);
01981     } /*opxmltooutlinevisit*/
01982 
01983 
01984 
01985 /* Original scripts
01986 
01987 on outlineToXml (adroutline) { //7/19/00; 6:30:02 PM by DW
01988     «Changes:
01989         «Wednesday, July 26, 2000 at 6:38:36 PM by DW
01990             «Encode ampersands, quotes and less-thans in attributes.
01991         «07/27/00; 3:24:37 PM by PBS
01992             «Encode > characters as &gt;, so the generated XML can be compiled later.
01993         «Friday, August 25, 2000 at 11:13:16 AM by DW
01994             «Version 1.0d2. Add <ownerName> and <ownerEmail> to the <head>.
01995         «Thu, Sep 7, 2000 at 2:53:03 PM by JES
01996             «Set the target to oldTarget before returning xmltext.
01997     local (scrollstate, expansionstate, windowtop, windowleft, windowheight, windowwidth, windowtitle);
01998     on encode (s) {
01999         s = string.replaceall (s, "&", "&amp;");
02000         s = string.replaceall (s, "\"", "&quot;");
02001         s = string.replaceall (s, "<", "&lt;");
02002         s = string.replaceall (s, ">", "&gt;"); //PBS 07/27/00: encode > characters, so XML can be compiled later
02003         return (s)};
02004     bundle { //set state variables based on the original window
02005         local (oldtarget = target.set (adroutline));
02006         scrollstate = op.getscrollstate ();
02007         expansionstate = op.getexpansionstate ();
02008         window.getSize (adroutline, @windowwidth, @windowheight);
02009         window.getPosition (adroutline, @windowleft, @windowtop);
02010         windowtitle = window.gettitle (adroutline);
02011         };«target.set (oldtarget)
02012     local (xmltext = "", indentlevel = 0);
02013     on add (s) {
02014         xmltext = xmltext + string.filledstring ("\t", indentlevel) + s + "\r"};
02015     add ("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
02016     local (localoutline);
02017     localoutline = adroutline^;
02018     local (oldtarget = target.set (@localoutline));
02019     add ("<outlineDocument version=\"1.0d2\">"); indentlevel++;
02020     bundle { //add <head>
02021         add ("<head>"); indentlevel++;
02022         add ("<title>" + windowtitle + "</title>");
02023         add ("<dateCreated>" + date.netstandardstring (timecreated (adroutline)) + "</dateCreated>");
02024         add ("<dateModified>" + date.netstandardstring (timemodified (adroutline)) + "</dateModified>");
02025         add ("<ownerName>" + user.prefs.name + "</ownerName>");
02026         add ("<ownerEmail>" + user.prefs.mailAddress + "</ownerEmail>");
02027         bundle { //add expansion state
02028             local (expansionlist = string (expansionstate), num, s = "");
02029             for num in expansionlist {
02030                 s = s + num + ","};
02031             s = string.delete (s, sizeof (s), 1); //delete last comma
02032             add ("<expansionState>" + s + "</expansionState>")};
02033         add ("<vertScrollState>" + scrollstate + "</vertScrollState>");
02034         bundle { //add <windowXxx> elements
02035             add ("<windowTop>" + windowtop + "</windowTop>");
02036             add ("<windowLeft>" + windowleft + "</windowLeft>");
02037             add ("<windowBottom>" + (windowtop + windowheight) + "</windowBottom>");
02038             add ("<windowRight>" + (windowleft + windowwidth) + "</windowRight>")};
02039         add ("</head>"); indentlevel--};
02040     bundle { //add <body>
02041         add ("<body>"); indentlevel++;
02042         op.fullexpand ();
02043         op.firstsummit ();
02044         on visitLevel () {
02045             local (s);
02046             loop {
02047                 s = "<outline text=\"" + encode (op.getlinetext ()) + "\"";
02048                 bundle { //add attributes from refcon, if there are any
02049                     local (data = op.getrefcon ());
02050                     if typeof (data) == binarytype { //has attributes
02051                         local (attstable);
02052                         unpack (@data, @attstable);
02053                         for adr in @attstable {
02054                             s = s + " " + nameof (adr^) + "=\"" + encode (adr^) + "\""}}}; //7/26/00 DW
02055                 if script.isComment () {
02056                     s = s + " isComment=\"true\""};
02057                 if op.go (right, 1) {
02058                     add (s + ">"); indentlevel++;
02059                     visitLevel ();
02060                     add ("</outline>"); indentlevel--;
02061                     op.go (left, 1)}
02062                 else {
02063                     add (s + "\/>")};
02064                 if not op.go (down, 1) {
02065                     break}}};
02066         visitLevel ();
02067         add ("</body>"); indentlevel--};
02068     add ("</outlineDocument>"); indentlevel--;
02069     target.set (oldTarget); // 09/07/00 JES
02070     return (xmltext)}
02071     
02072 
02073 on xmlToOutline (xmltext, adroutline, flnewoutline = true) { //7/19/00; 6:51:02 PM by DW
02074     «Changes:
02075         «07/25/00; 8:52:21 PM by PBS
02076             «Set refcon only if there's data to set.
02077         «07/27/00; 3:27:12 PM by PBS
02078             «Decode &quot;, &lt;, &gt; and &amp; in text attributes so round-trip of HTML-in-XML works.
02079         «Tuesday, August 08, 2000 at 6:01:44 PM by DW
02080             «Allow any attributes to be linked to a headline through the refcon. We have to make assumptions about the XML structure that xml.compile generates, there's no way to do this  through the procedural interface.
02081         «Tuesday, August 08, 2000 at 6:24:31 PM by DW
02082             «Commented debugging code that had accidentally been left uncommented.
02083         «Tuesday, August 15, 2000 at 1:29:57 PM by JES
02084             «Bug fix -- no longer fails when converting deeply nested outlines.
02085     if flnewoutline {
02086         new (outlinetype, adroutline)};
02087     local (xstruct);
02088     local (oldtarget = target.set (adroutline));
02089     xml.compile (xmltext, @xstruct);
02090     «scratchpad.xstruct = xstruct; wp.newtextobject (xmltext, @scratchpad.xtext)
02091     on dolevel (adrxoutline) {
02092         local (insertdir = right, flatleastoneinserted = false);
02093         local (item, text, attstable);
02094         for item in adrxoutline {
02095             if nameOf (item^) endsWith "\toutline" {
02096                 bundle { //fill the atts table with atts we understand
02097                     new (tabletype, @attstable);
02098                     local (adratts = @item^.["/atts"], adratt);
02099                     for adratt in adratts {
02100                         attstable.[nameof (adratt^)] = adratt^};
02101                     try {text = attstable.text; delete (@attstable.text)} else {text = ""}};
02102                 bundle { //PBS 07/27/00: decode &quot;, &gt;, &lt; &amp;
02103                     text = string.replaceall (text, "&quot;", "\"");
02104                     text = string.replaceall (text, "&lt;", "<");
02105                     text = string.replaceall (text, "&gt;", ">");
02106                     text = string.replaceall (text, "&amp;", "&")};
02107                 op.insert (text, insertdir); insertdir = down;
02108                 if sizeOf (attstable) > 0 { //PBS 07/25/00: set refcon only if there's data to set
02109                     local (data);
02110                     pack (attstable, @data);
02111                     op.setrefcon (data)};
02112                 flatleastoneinserted = true;
02113                 if dolevel (item) { //at least one item added
02114                     op.go (left, 1)}}};
02115         return (flatleastoneinserted)};
02116     local (adroutlinedocument = xml.getaddress (@xstruct, "outlineDocument"));
02117     local (adrbody = xml.getaddress (adroutlinedocument, "body"));
02118     dolevel (adrbody);
02119     bundle { //process <head>, if new outline
02120         if flnewoutline {
02121             bundle { //perform outline surgery
02122                 op.firstsummit ();
02123                 op.promote ();
02124                 op.deleteline ()};
02125             local (adrhead = xml.getaddress (adroutlinedocument, "head"));
02126             try { //set the window position/size
02127                 local (windowTop = number (xml.getaddress (adrhead, "windowTop")^));
02128                 local (windowLeft = number (xml.getaddress (adrhead, "windowLeft")^));
02129                 local (windowBottom = number (xml.getaddress (adrhead, "windowBottom")^));
02130                 local (windowRight = number (xml.getaddress (adrhead, "windowRight")^));
02131                 window.setposition (adroutline, windowLeft, windowTop);
02132                 window.setsize (adroutline, windowRight - windowLeft, windowBottom - windowTop)};
02133             try { //set the expansion state
02134                 local (expansionString = xml.getaddress (adrhead, "expansionState")^);
02135                 local (expansionList = {}, i);
02136                 for i = 1 to string.countfields (expansionString, ',') {
02137                     expansionList = expansionList + string.nthfield (expansionString, ',', i)};
02138                 op.setexpansionstate (expansionList)};
02139             try { //set the vertical scroll state
02140                 op.setscrollstate (xml.getaddress (adrhead, "vertScrollState")^)};
02141             try { //set the window title
02142                 parentOf (adroutline^)^.title = xml.getaddress (adrhead, "title")^}}};
02143     target.set (oldtarget);
02144     return (true)}
02145 
02146 */

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