claybrowservalidate.c

Go to the documentation of this file.
00001 
00002 /*  $Id: claybrowservalidate.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 "dialogs.h"
00032 #include "error.h"
00033 #include "strings.h"
00034 #include "opinternal.h"
00035 #include "claybrowserstruc.h"
00036 #include "claybrowservalidate.h"
00037 #include "langinternal.h" /* 2005-09-26 creedon */
00038 #include "tablestructure.h" /* 2005-09-26 creedon */
00039 
00040 #define collidewithequal 0x0001
00041 #define collidewitholder 0x0002
00042 #define collidewithnewer 0x0004
00043 
00044 #define nocollisions 0
00045 
00046 #define bilateralcollision (collidewitholder + collidewithnewer)
00047 
00048 static long dragmodified;
00049 
00050 //static char *pastefname;
00051 
00052 typedef enum tyaction {
00053     
00054     validatemove,
00055     
00056     validatepaste
00057     } tyaction;
00058 
00059 
00060 byte * actionstrings [] = {
00061     
00062     BIGSTRING ("\x06" "moving"),
00063     BIGSTRING ("\x07" "pasting")
00064     };
00065 
00066 
00067 enum {
00068     ixsomeitems,
00069     ixan,
00070     ixanewer,
00071     ixanolder,
00072     ixitemnamed,
00073     ixalreadyexists
00074     };
00075 
00076 
00077 byte * dialogstrings [] = {
00078     BIGSTRING ("\x40" "Some items in this location have the same names as items you're "),
00079     BIGSTRING ("\x02" "An"),
00080     BIGSTRING ("\x07" "A newer"),
00081     BIGSTRING ("\x08" "An older"),
00082     #ifdef MACVERSION
00083         BIGSTRING ("\x0d" " item named Ň"),
00084         BIGSTRING ("\x22" "Ó already exists in this location.")
00085     #else
00086         BIGSTRING ("\x0d" " item named \""),
00087         BIGSTRING ("\x22" "\" already exists in this location.")
00088     #endif
00089     };
00090 
00091 typedef struct tydraginfo {
00092 
00093     long ctcollisions;
00094 
00095     short collisiontype;
00096     
00097     tyaction action;
00098     
00099     hdlheadrecord hdrag;
00100     
00101     hdlheadrecord hdest;
00102     
00103     tydirection dir;
00104 
00105     hdlheadrecord hcollided;
00106 
00107     hdlheadrecord hcompare;
00108     } tydraginfo, *ptrdraginfo;
00109 
00110 
00111 boolean browservalidatedrag (hdlheadrecord hsource, hdlheadrecord hdest, tydirection dir) {
00112 #pragma unused (hsource)
00113 
00114     /*
00115     5.0a5 dmb: same level, resort check is bogus; headlink lefts can be the same for a 
00116     summit and its child, and two summits have different headlinklefts. but we don't 
00117     want to enforce this anyway, so I just commented it out
00118 
00119     5.0b15 dmb: removed vestigal sourceinfo code
00120     */
00121     
00122     tybrowserinfo destinfo;
00123     
00124     browsergetrefcon (hdest, &destinfo);
00125     
00126     if (destinfo.flvolume) {
00127         
00128         if (dir == down)
00129             return (false);
00130         
00131     #if filebrowser
00132         if (destinfo.fllocked || destinfo.flhardwarelock)
00133             return (false);
00134     #endif
00135         }
00136         
00137     if ((!destinfo.flfolder) && (dir == right)) /*can't move to the right of a file*/
00138         return (false);
00139     
00140     /*
00141     if ((**hsource).headlinkleft == (**hdest).headlinkleft) { //they're at the same level
00142     
00143         if ((dir == up) || (dir == down)) //can't re-sort the list with dragging move
00144             return (false);
00145         }
00146     
00147     browsergetrefcon (hsource, &sourceinfo);
00148     */
00149     
00150     return (true);
00151     } /*browservalidatedrag*/
00152 
00153 
00154 static boolean browsercompareforcollision (hdlheadrecord hnode, long pdragmodified, bigstring bs1, bigstring bs2, ptrdraginfo draginfo) {
00155 // 2006-04-03 - kw --- renamed dragmodified
00156     /*
00157     5.0.2b18 dmb: set tmpbit of subs too, so we can detect illegal moves
00158     */
00159     
00160     tybrowserinfo info;
00161     
00162     if (equalidentifiers (bs1, bs2)) {
00163         
00164         opsettmpbitvisit (hnode, (ptrvoid) true);
00165         
00166         oprecursivelyvisit (hnode, infinity, &opsettmpbitvisit, (ptrvoid) true); // set subs too
00167         
00168         ++(*draginfo).ctcollisions;
00169         
00170         (*draginfo).hcollided = hnode; /*last collision*/
00171         
00172         if ((*draginfo).collisiontype < bilateralcollision) { /*still useful to check dates*/
00173             
00174             browsergetrefcon (hnode, &info);
00175             
00176             switch (sgn (pdragmodified - info.timemodified)) {
00177                 
00178                 case +1:
00179                     (*draginfo).collisiontype |= collidewitholder; break;
00180                 
00181                 case 0:
00182                     (*draginfo).collisiontype |= collidewithequal; break;
00183                 
00184                 case -1:
00185                     (*draginfo).collisiontype |= collidewithnewer; break;
00186                 } /*switch*/
00187             }
00188         }
00189     
00190     return (true);  
00191     } /*browsercompareforcollision*/
00192 
00193 
00194 static boolean collisionvisit (hdlheadrecord hnode, ptrvoid refcon) {
00195     
00196     /*
00197     5.0b9 dmb: don't conflict with ourself
00198     */
00199     
00200     bigstring bsnode, bsdrag;
00201     ptrdraginfo draginfo = (ptrdraginfo) refcon;
00202     
00203     if (hnode == (*draginfo).hdrag)
00204         return (true);
00205     
00206     opgetheadstring (hnode, bsnode);
00207     
00208     opgetheadstring ((*draginfo).hdrag, bsdrag);
00209     
00210     return (browsercompareforcollision (hnode, dragmodified, bsnode, bsdrag, draginfo));
00211     } /*collisionvisit*/
00212         
00213 
00214 static boolean browsercollisiondialog (hdlheadrecord hdest, ptrdraginfo draginfo) {
00215 #pragma unused (hdest)
00216 
00217     /*
00218     2005-09-26 creedon: changed default order of buttons, default is Duplicate which is the safe option, checks user.prefs.flReplaceDialogExpertMode and if true Replace is the default option
00219     */
00220     
00221     bigstring bs, bscollided, prompt;
00222     bigstring nobutton, yesbutton;
00223     short itemhit;
00224     boolean fl, flExpertMode = false;
00225     
00226     if ((*draginfo).collisiontype == nocollisions) /*no confirmation or deletions needed*/  
00227         return (true);
00228         
00229     if ((*draginfo).ctcollisions > 1) {
00230     
00231         copystring (dialogstrings [ixsomeitems], prompt);
00232         
00233         pushstring (actionstrings [(*draginfo).action], prompt);
00234         
00235         pushchar ('.', prompt);
00236         }
00237     else {
00238         copystring (dialogstrings [ixan], prompt);
00239         
00240         switch ((*draginfo).collisiontype) {
00241             
00242             case collidewithnewer:
00243                 copystring (dialogstrings [ixanewer], prompt);
00244                 
00245                 break;
00246             
00247             case collidewitholder:
00248                 copystring (dialogstrings [ixanolder], prompt);
00249                 
00250                 break;
00251             } /*switch*/
00252     
00253         pushstring (dialogstrings [ixitemnamed], prompt);
00254         
00255         opgetheadstring ((*draginfo).hcollided, bscollided);
00256         
00257         pushstring (bscollided, prompt);
00258     
00259         pushstring (dialogstrings [ixalreadyexists], prompt);
00260         }
00261     
00262     getsystemtablescript (idreplacedialogexpertmode, bs); // "user.prefs.flReplaceDialogExpertMode"
00263 
00264     disablelangerror ();
00265 
00266     fl = langrunstring (bs, bs);
00267     
00268     enablelangerror ();
00269     
00270     if (fl)
00271         stringisboolean (bs, &flExpertMode);
00272     
00273     if (flExpertMode) {
00274         copystring (duplicatebuttontext, nobutton);
00275         copystring (replacebuttontext, yesbutton);
00276         }
00277     else {
00278         copystring (duplicatebuttontext, yesbutton);
00279         copystring (replacebuttontext, nobutton);
00280         }
00281 
00282     itemhit = threewaydialog (prompt, yesbutton, nobutton, cancelbuttontext);
00283 
00284     if (flExpertMode)
00285         switch (itemhit) {
00286         
00287             case 1:
00288                 itemhit = 2;
00289                 
00290                 break;
00291             
00292             case 2:
00293                 itemhit = 1;
00294                 break;
00295             
00296             }
00297     
00298     switch (itemhit) {
00299     
00300         case 1:
00301             opcleartmpbits ();
00302             
00303             /*caller should rename items where conflicts occur*/
00304             
00305             return (true);
00306         
00307         case 2:
00308             /*caller should delete all files with their tmpbit set*/
00309             
00310             return (true);
00311         
00312         default:
00313             opcleartmpbits ();
00314             
00315             return (false);
00316         } /* switch */
00317 
00318     } /*browsercollisiondialog*/
00319 
00320 
00321 static boolean validatemovevisit (hdlheadrecord hnode, ptrvoid refcon) {
00322     
00323     tybrowserinfo info;
00324     ptrdraginfo draginfo = (ptrdraginfo) refcon;
00325     hdlheadrecord hdest = (*draginfo).hdest;
00326     
00327     (*draginfo).hdrag = hnode;
00328     
00329     browsergetrefcon (hnode, &info);
00330     
00331     dragmodified = info.timemodified;
00332     
00333     if ((*draginfo).dir == right)
00334         return (oprecursivelyvisit (hdest, 1, &collisionvisit, draginfo));
00335     else
00336         return (oplistvisit (opfirstatlevel (hdest), &collisionvisit, draginfo));
00337     } /*validatemovevisit*/
00338 
00339 
00340 static boolean browservalidateinsertion (hdlheadrecord hdest, hdlheadrecord hscrap, tydirection dir, tyaction action) {
00341     
00342     /*
00343     confirm that the user wants to overwrite existing files,
00344     we return false to cancel the operation.
00345     */
00346     
00347     tydraginfo draginfo;
00348     
00349     draginfo.hdest = hdest;
00350     
00351     draginfo.dir = dir;
00352 
00353     draginfo.ctcollisions = draginfo.collisiontype = 0;
00354     
00355     draginfo.action = action;
00356     
00357     opcleartmpbits ();
00358      
00359     if (hscrap == nil)
00360         opvisitmarked (down, &validatemovevisit, &draginfo);
00361     else 
00362         oplistvisit (hscrap, &validatemovevisit, &draginfo); 
00363     
00364     return (browsercollisiondialog (hdest, &draginfo));
00365     } /*browservalidateinsertion*/
00366 
00367 
00368 boolean browservalidatemove (hdlheadrecord hdest, hdlheadrecord hscrap, tydirection dir) {
00369     
00370     return (browservalidateinsertion (hdest, hscrap, dir, validatemove));
00371     } /*browservalidatemove*/
00372 
00373 
00374 boolean browservalidatepaste (hdlheadrecord hscrap, hdlheadrecord hdest, tydirection dir) {
00375     
00376     /*
00377     return false to cancel the paste.
00378     
00379     assume that paste always happens in the list of the cursor's parent.
00380     */
00381     
00382     #if filebrowser
00383     
00384     hdlheadrecord hfolder = (**hdest).headlinkleft;
00385     
00386     if (hfolder == hdest) {
00387         
00388         alertdialog (BIGSTRING ("\x32" "CanŐt paste at the top level of a browser outline."));
00389         
00390         return (false);
00391         }
00392     
00393     #endif
00394     
00395     if (!browservalidateinsertion (hdest, hscrap, dir, validatepaste)) /*user declined to replace already-existing files*/
00396         return (false);
00397     
00398     browserdeletenodeswithtmpbitset ();
00399     
00400     return (true);
00401     } /*browservalidatepaste*/
00402     
00403 
00404 #if 0 /*we're not doing a folder-based clipboard, but if we did, this is how you would validate a paste*/
00405 
00406 static boolean pastecollisionvisit (hdlheadrecord hnode, ptrdraginfo draginfo) {
00407     
00408     bigstring fname;
00409     bigstring bsnode;
00410     
00411     copystring (pastefname, fname);
00412     
00413     opgetheadstring (hnode, bsnode);
00414     
00415     return (browsercompareforcollision (hnode, dragmodified, bsnode, fname));
00416     } /*pastecollisionvisit*/
00417         
00418 
00419 static boolean validatepastecallback (bigstring fname, tyfileinfo *info, ptrdraginfo draginfo) {
00420     
00421     dragmodified = (*info).timemodified;
00422     
00423     pastefname = (char *) fname;
00424     
00425     return (oprecursivelyvisit ((*draginfo).hdest, 1, &pastecollisionvisit, draginfo));
00426     } /*validatepastecallback*/
00427     
00428     
00429 static boolean browservalidatefolderpaste (hdlheadrecord hfolder, FSSpec *clipfolderspec) {
00430     
00431     /*
00432     check for collisions -- if there already is a file in the target folder
00433     with the same name as one of the items we're pasting, a dialog appears
00434     confirming the replacement. all files that need to be deleted have their
00435     tmpbits set. the caller should delete them. we don't do the deletion 
00436     here so that the deletions can be undoable.
00437     */
00438     
00439     tydraginfo;
00440     
00441     if ((**hfolder).headlinkleft == hfolder) {
00442         
00443         alertdialog (BIGSTRING ("\x32" "CanŐt paste at the top level of a browser outline."));
00444         
00445         return (false);
00446         }
00447     
00448     draginfo.hdest = hfolder;
00449     
00450     draginfo.ctcollisions = draginfo.collisiontype = 0;
00451     
00452     opcleartmpbits ();
00453     
00454     folderloop (clipfolderspec, false, &validatepastecallback, &draginfo);
00455         
00456     return (browsercollisiondialog (hfolder, BIGSTRING ("\x07" "pasting")));
00457     } /*browservalidatefolderpaste*/
00458 
00459 #endif
00460 
00461 
00462 static ptrstring pcommand;
00463 
00464 
00465 static boolean compareforcopyvisit (hdlheadrecord hnode, ptrvoid refcon) {
00466     
00467     bigstring bs, bsnode;
00468     ptrdraginfo draginfo = (ptrdraginfo) refcon;
00469     
00470     if (hnode == (*draginfo).hcompare)
00471         return (true);
00472     
00473     opgetheadstring (hnode, bsnode);
00474     
00475     opgetheadstring ((*draginfo).hcompare, bs);
00476     
00477     if (!equalidentifiers (bsnode, bs)) 
00478         return (true);
00479     
00480     copystring (BIGSTRING ("\x06" "CanŐt "), bs);
00481     
00482     pushstring (pcommand, bs);
00483     
00484     pushstring (BIGSTRING ("\x35" " because there are two or more selected items named Ň"), bs);
00485     
00486     pushstring (bsnode, bs);
00487     
00488     pushstring (BIGSTRING ("\x02" "Ó."), bs);
00489     
00490     alertdialog (bs);
00491     
00492     return (false); /*stop both traversals*/
00493     } /*compareforcopyvisit*/
00494     
00495     
00496 static boolean validatecopyvisit (hdlheadrecord hnode, ptrvoid refcon) {
00497 #pragma unused (refcon)
00498 
00499     tydraginfo draginfo;
00500     
00501     draginfo.hcompare = hnode;
00502     
00503     return (opvisitmarked (down, &compareforcopyvisit, &draginfo));
00504     } /*validatecopyvisit*/
00505 
00506 
00507 boolean browservalidatecopy (bigstring bscommand) {
00508     
00509     /*
00510     don't allow a copy if there's a node selected that has the
00511     same name as another node that's selected. we do the dialog
00512     here, the caller should just exit if we return false.
00513     */
00514     
00515     pcommand = bscommand; /*set static to point to string*/
00516     
00517     return (opvisitmarked (down, &validatecopyvisit, nil));
00518     } /*browservalidatecopy*/
00519     
00520     

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