Fossil SCM
In /timeline allow p= and d= to have separate values, and the result is showing all check-ins that are both ancenstors of p= and descendents of d=.
Commit
d1d4cc7529eefa9e31f486c697030087940930f9d1ee60d1d656830fdad76500
Parent
e2e57aa9735cbe6…
1 file changed
+79
-37
+79
-37
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1703,11 +1703,11 @@ | ||
| 1703 | 1703 | int to_rid = name_choice("to","to2",&zTo2); /* to= for path timelines */ |
| 1704 | 1704 | int bShort = P("shortest")!=0; /* shortest possible path */ |
| 1705 | 1705 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 1706 | 1706 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 1707 | 1707 | int pd_rid; |
| 1708 | - const char *zDPName; /* Value of p=, d=, or dp= params */ | |
| 1708 | + const char *zDPNameP, *zDPNameD; /* Value of p=, d=, or dp= params */ | |
| 1709 | 1709 | double rBefore, rAfter, rCirca; /* Boundary times */ |
| 1710 | 1710 | const char *z; |
| 1711 | 1711 | char *zOlderButton = 0; /* URL for Older button at the bottom */ |
| 1712 | 1712 | char *zOlderButtonLabel = 0; /* Label for the Older Button */ |
| 1713 | 1713 | char *zNewerButton = 0; /* URL for Newer button at the top */ |
| @@ -1770,20 +1770,20 @@ | ||
| 1770 | 1770 | }else{ |
| 1771 | 1771 | nEntry = 50; |
| 1772 | 1772 | } |
| 1773 | 1773 | |
| 1774 | 1774 | /* Query parameters d=, p=, and f= and variants */ |
| 1775 | - p_rid = name_choice("p","p2", &zDPName); | |
| 1776 | - d_rid = name_choice("d","d2", &zDPName); | |
| 1775 | + p_rid = name_choice("p","p2", &zDPNameP); | |
| 1776 | + d_rid = name_choice("d","d2", &zDPNameD); | |
| 1777 | 1777 | z = P("f"); |
| 1778 | 1778 | f_rid = z ? name_to_typed_rid(z,"ci") : 0; |
| 1779 | 1779 | z = P("df"); |
| 1780 | 1780 | if( z && (d_rid = name_to_typed_rid(z,"ci"))!=0 ){ |
| 1781 | 1781 | nEntry = 0; |
| 1782 | 1782 | useDividers = 0; |
| 1783 | 1783 | cgi_replace_query_parameter("d",fossil_strdup(z)); |
| 1784 | - zDPName = z; | |
| 1784 | + zDPNameD = zDPNameP = z; | |
| 1785 | 1785 | } |
| 1786 | 1786 | |
| 1787 | 1787 | /* Undocumented query parameter to set JS mode */ |
| 1788 | 1788 | builtin_set_js_delivery_mode(P("jsmode"),1); |
| 1789 | 1789 | |
| @@ -1803,13 +1803,14 @@ | ||
| 1803 | 1803 | showCherrypicks = 0; |
| 1804 | 1804 | } |
| 1805 | 1805 | |
| 1806 | 1806 | /* To view the timeline, must have permission to read project data. |
| 1807 | 1807 | */ |
| 1808 | - pd_rid = name_choice("dp","dp2",&zDPName); | |
| 1808 | + pd_rid = name_choice("dp","dp2",&zDPNameP); | |
| 1809 | 1809 | if( pd_rid ){ |
| 1810 | 1810 | p_rid = d_rid = pd_rid; |
| 1811 | + zDPNameD = zDPNameP; | |
| 1811 | 1812 | } |
| 1812 | 1813 | if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum) |
| 1813 | 1814 | || (bisectLocal && !g.perm.Setup) |
| 1814 | 1815 | ){ |
| 1815 | 1816 | login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); |
| @@ -2226,39 +2227,47 @@ | ||
| 2226 | 2227 | } |
| 2227 | 2228 | } |
| 2228 | 2229 | } |
| 2229 | 2230 | addFileGlobDescription(zChng, &desc); |
| 2230 | 2231 | }else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){ |
| 2231 | - /* If p= or d= is present, ignore all other parameters other than n= */ | |
| 2232 | - char *zUuid; | |
| 2233 | - const char *zCiName; | |
| 2232 | + /* If either p= or d= or both are present, ignore all other parameters | |
| 2233 | + ** other than n=, ft=, and bt= */ | |
| 2234 | + const char *zBaseName; | |
| 2234 | 2235 | int np = 0, nd; |
| 2235 | 2236 | const char *zBackTo = 0; |
| 2236 | 2237 | const char *zFwdTo = 0; |
| 2237 | 2238 | int ridBackTo = 0; |
| 2238 | 2239 | int ridFwdTo = 0; |
| 2239 | 2240 | int bBackAdded = 0; /* True if the zBackTo node was added */ |
| 2240 | 2241 | int bFwdAdded = 0; /* True if the zBackTo node was added */ |
| 2242 | + int bSeparateDandP = 0; /* p_rid & d_rid both exist and are distinct */ | |
| 2241 | 2243 | |
| 2242 | 2244 | tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS; |
| 2243 | - if( p_rid && d_rid ){ | |
| 2244 | - if( p_rid!=d_rid ) p_rid = d_rid; | |
| 2245 | - if( !haveParameterN ) nEntry = 10; | |
| 2245 | + if( p_rid && d_rid && p_rid!=d_rid ){ | |
| 2246 | + bSeparateDandP = 1; | |
| 2247 | + db_multi_exec( | |
| 2248 | + "CREATE TEMP TABLE IF NOT EXISTS ok_d(rid INTEGER PRIMARY KEY)" | |
| 2249 | + ); | |
| 2250 | + }else{ | |
| 2251 | + zBaseName = p_rid ? zDPNameP : zDPNameD; | |
| 2246 | 2252 | } |
| 2247 | 2253 | db_multi_exec( |
| 2248 | - "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" | |
| 2254 | + "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" | |
| 2249 | 2255 | ); |
| 2250 | 2256 | add_extra_rids("ok", P("x")); |
| 2251 | - zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", | |
| 2252 | - p_rid ? p_rid : d_rid); | |
| 2253 | - zCiName = zDPName; | |
| 2254 | - if( zCiName==0 ) zCiName = zUuid; | |
| 2255 | 2257 | blob_append_sql(&sql, " AND event.objid IN ok"); |
| 2256 | 2258 | nd = 0; |
| 2257 | 2259 | if( d_rid ){ |
| 2258 | 2260 | double rStopTime = 9e99; |
| 2259 | 2261 | zFwdTo = P("ft"); |
| 2262 | + if( zFwdTo && bSeparateDandP ){ | |
| 2263 | + if( zError==0 ){ | |
| 2264 | + zError = "Cannot use the ft= query parameter when both p= and d= " | |
| 2265 | + "are used and have distinct values."; | |
| 2266 | + } | |
| 2267 | + zFwdTo = 0; | |
| 2268 | + } | |
| 2260 | 2269 | if( zFwdTo ){ |
| 2261 | 2270 | double rStartDate = mtime_of_rid(d_rid, 0.0); |
| 2262 | 2271 | ridFwdTo = first_checkin_with_tag_after_date(zFwdTo, rStartDate); |
| 2263 | 2272 | if( ridFwdTo==0 ){ |
| 2264 | 2273 | ridFwdTo = name_to_typed_rid(zBackTo,"ci"); |
| @@ -2265,10 +2274,13 @@ | ||
| 2265 | 2274 | } |
| 2266 | 2275 | if( ridFwdTo ){ |
| 2267 | 2276 | if( !haveParameterN ) nEntry = 0; |
| 2268 | 2277 | rStopTime = mtime_of_rid(ridFwdTo, 9e99); |
| 2269 | 2278 | } |
| 2279 | + }else if( bSeparateDandP ){ | |
| 2280 | + rStopTime = mtime_of_rid(p_rid, 9e99); | |
| 2281 | + nEntry = 0; | |
| 2270 | 2282 | } |
| 2271 | 2283 | if( rStopTime<9e99 ){ |
| 2272 | 2284 | rStopTime += 5.8e-6; /* Round up by 1/2 second */ |
| 2273 | 2285 | } |
| 2274 | 2286 | db_multi_exec( |
| @@ -2285,49 +2297,85 @@ | ||
| 2285 | 2297 | ); |
| 2286 | 2298 | if( ridFwdTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridFwdTo) ){ |
| 2287 | 2299 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridFwdTo); |
| 2288 | 2300 | bFwdAdded = 1; |
| 2289 | 2301 | } |
| 2290 | - nd = db_int(0, "SELECT count(*)-1 FROM ok"); | |
| 2291 | - if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); | |
| 2292 | - if( nd>0 || p_rid==0 ){ | |
| 2293 | - blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); | |
| 2302 | + if( bSeparateDandP ){ | |
| 2303 | + db_multi_exec( | |
| 2304 | + "INSERT INTO ok_d SELECT rid FROM ok;" | |
| 2305 | + "DELETE FROM ok;" | |
| 2306 | + ); | |
| 2307 | + }else{ | |
| 2308 | + nd = db_int(0, "SELECT count(*)-1 FROM ok"); | |
| 2309 | + if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); | |
| 2310 | + if( nd>0 || p_rid==0 ){ | |
| 2311 | + blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); | |
| 2312 | + } | |
| 2313 | + if( useDividers && !selectedRid ) selectedRid = d_rid; | |
| 2314 | + db_multi_exec("DELETE FROM ok"); | |
| 2294 | 2315 | } |
| 2295 | - if( useDividers && !selectedRid ) selectedRid = d_rid; | |
| 2296 | - db_multi_exec("DELETE FROM ok"); | |
| 2297 | 2316 | } |
| 2298 | 2317 | if( p_rid ){ |
| 2299 | 2318 | zBackTo = P("bt"); |
| 2319 | + if( zBackTo && bSeparateDandP ){ | |
| 2320 | + if( zError==0 ){ | |
| 2321 | + zError = "Cannot use the bt= query parameter when both p= and d= " | |
| 2322 | + "are used and have distinct values."; | |
| 2323 | + } | |
| 2324 | + zBackTo = 0; | |
| 2325 | + } | |
| 2300 | 2326 | if( zBackTo ){ |
| 2301 | 2327 | double rDateLimit = mtime_of_rid(p_rid, 0.0); |
| 2302 | 2328 | ridBackTo = last_checkin_with_tag_before_date(zBackTo, rDateLimit); |
| 2303 | 2329 | if( ridBackTo==0 ){ |
| 2304 | 2330 | ridBackTo = name_to_typed_rid(zBackTo,"ci"); |
| 2305 | 2331 | } |
| 2306 | 2332 | if( ridBackTo && !haveParameterN ) nEntry = 0; |
| 2333 | + }else if( bSeparateDandP ){ | |
| 2334 | + ridBackTo = d_rid; | |
| 2335 | + nEntry = 0; | |
| 2307 | 2336 | } |
| 2308 | 2337 | compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo); |
| 2309 | 2338 | if( ridBackTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridBackTo) ){ |
| 2310 | 2339 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridBackTo); |
| 2311 | 2340 | bBackAdded = 1; |
| 2312 | 2341 | } |
| 2313 | - np = db_int(0, "SELECT count(*)-1 FROM ok"); | |
| 2314 | - if( np>0 || nd==0 ){ | |
| 2315 | - if( nd>0 ) blob_appendf(&desc, " and "); | |
| 2316 | - blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s"); | |
| 2342 | + if( bSeparateDandP ){ | |
| 2343 | + db_multi_exec("DELETE FROM ok WHERE rid NOT IN ok_d;"); | |
| 2317 | 2344 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2345 | + }else{ | |
| 2346 | + np = db_int(0, "SELECT count(*)-1 FROM ok"); | |
| 2347 | + if( np>0 || nd==0 ){ | |
| 2348 | + if( nd>0 ) blob_appendf(&desc, " and "); | |
| 2349 | + blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s"); | |
| 2350 | + db_multi_exec("%s", blob_sql_text(&sql)); | |
| 2351 | + } | |
| 2352 | + if( useDividers && !selectedRid ) selectedRid = p_rid; | |
| 2318 | 2353 | } |
| 2319 | - if( useDividers && !selectedRid ) selectedRid = p_rid; | |
| 2320 | 2354 | } |
| 2321 | - blob_appendf(&desc, " of %z%h</a>", | |
| 2322 | - href("%R/info?name=%h", zCiName), zCiName); | |
| 2355 | + if( bSeparateDandP ){ | |
| 2356 | + int n = db_int(0, "SELECT count(*) FROM ok"); | |
| 2357 | + blob_reset(&desc); | |
| 2358 | + blob_appendf(&desc, | |
| 2359 | + "%d check-ins that are both ancestors of %z%h</a>" | |
| 2360 | + " and descendents of %z%h</a>", | |
| 2361 | + n, | |
| 2362 | + href("%R/info?name=%h",zDPNameP),zDPNameP, | |
| 2363 | + href("%R/info/name=%h",zDPNameD),zDPNameD | |
| 2364 | + ); | |
| 2365 | + ridBackTo = 0; | |
| 2366 | + ridFwdTo = 0; | |
| 2367 | + }else{ | |
| 2368 | + blob_appendf(&desc, " of %z%h</a>", | |
| 2369 | + href("%R/info?name=%h", zBaseName), zBaseName); | |
| 2370 | + } | |
| 2323 | 2371 | if( ridBackTo ){ |
| 2324 | 2372 | if( np==0 ){ |
| 2325 | 2373 | blob_reset(&desc); |
| 2326 | 2374 | blob_appendf(&desc, |
| 2327 | 2375 | "Check-in %z%h</a> only (%z%h</a> does not precede it)", |
| 2328 | - href("%R/info?name=%h",zCiName), zCiName, | |
| 2376 | + href("%R/info?name=%h",zBaseName), zBaseName, | |
| 2329 | 2377 | href("%R/info?name=%h",zBackTo), zBackTo); |
| 2330 | 2378 | }else{ |
| 2331 | 2379 | blob_appendf(&desc, " back to %z%h</a>%s", |
| 2332 | 2380 | href("%R/info?name=%h",zBackTo), zBackTo, |
| 2333 | 2381 | bBackAdded ? " (not a direct anscestor)" : ""); |
| @@ -2340,24 +2388,18 @@ | ||
| 2340 | 2388 | }else if( ridFwdTo ){ |
| 2341 | 2389 | if( nd==0 ){ |
| 2342 | 2390 | blob_reset(&desc); |
| 2343 | 2391 | blob_appendf(&desc, |
| 2344 | 2392 | "Check-in %z%h</a> only (%z%h</a> does not follow it)", |
| 2345 | - href("%R/info?name=%h",zCiName), zCiName, | |
| 2393 | + href("%R/info?name=%h",zBaseName), zBaseName, | |
| 2346 | 2394 | href("%R/info?name=%h",zFwdTo), zFwdTo); |
| 2347 | 2395 | }else{ |
| 2348 | 2396 | blob_appendf(&desc, " up to %z%h</a>%s", |
| 2349 | 2397 | href("%R/info?name=%h",zFwdTo), zFwdTo, |
| 2350 | 2398 | bFwdAdded ? " (not a direct descendent)":""); |
| 2351 | 2399 | } |
| 2352 | 2400 | } |
| 2353 | - if( d_rid ){ | |
| 2354 | - if( p_rid ){ | |
| 2355 | - /* If both p= and d= are set, we don't have the uuid of d yet. */ | |
| 2356 | - zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid); | |
| 2357 | - } | |
| 2358 | - } | |
| 2359 | 2401 | if( advancedMenu ){ |
| 2360 | 2402 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); |
| 2361 | 2403 | } |
| 2362 | 2404 | style_submenu_entry("n","Max:",4,0); |
| 2363 | 2405 | timeline_y_submenu(1); |
| 2364 | 2406 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1703,11 +1703,11 @@ | |
| 1703 | int to_rid = name_choice("to","to2",&zTo2); /* to= for path timelines */ |
| 1704 | int bShort = P("shortest")!=0; /* shortest possible path */ |
| 1705 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 1706 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 1707 | int pd_rid; |
| 1708 | const char *zDPName; /* Value of p=, d=, or dp= params */ |
| 1709 | double rBefore, rAfter, rCirca; /* Boundary times */ |
| 1710 | const char *z; |
| 1711 | char *zOlderButton = 0; /* URL for Older button at the bottom */ |
| 1712 | char *zOlderButtonLabel = 0; /* Label for the Older Button */ |
| 1713 | char *zNewerButton = 0; /* URL for Newer button at the top */ |
| @@ -1770,20 +1770,20 @@ | |
| 1770 | }else{ |
| 1771 | nEntry = 50; |
| 1772 | } |
| 1773 | |
| 1774 | /* Query parameters d=, p=, and f= and variants */ |
| 1775 | p_rid = name_choice("p","p2", &zDPName); |
| 1776 | d_rid = name_choice("d","d2", &zDPName); |
| 1777 | z = P("f"); |
| 1778 | f_rid = z ? name_to_typed_rid(z,"ci") : 0; |
| 1779 | z = P("df"); |
| 1780 | if( z && (d_rid = name_to_typed_rid(z,"ci"))!=0 ){ |
| 1781 | nEntry = 0; |
| 1782 | useDividers = 0; |
| 1783 | cgi_replace_query_parameter("d",fossil_strdup(z)); |
| 1784 | zDPName = z; |
| 1785 | } |
| 1786 | |
| 1787 | /* Undocumented query parameter to set JS mode */ |
| 1788 | builtin_set_js_delivery_mode(P("jsmode"),1); |
| 1789 | |
| @@ -1803,13 +1803,14 @@ | |
| 1803 | showCherrypicks = 0; |
| 1804 | } |
| 1805 | |
| 1806 | /* To view the timeline, must have permission to read project data. |
| 1807 | */ |
| 1808 | pd_rid = name_choice("dp","dp2",&zDPName); |
| 1809 | if( pd_rid ){ |
| 1810 | p_rid = d_rid = pd_rid; |
| 1811 | } |
| 1812 | if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum) |
| 1813 | || (bisectLocal && !g.perm.Setup) |
| 1814 | ){ |
| 1815 | login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); |
| @@ -2226,39 +2227,47 @@ | |
| 2226 | } |
| 2227 | } |
| 2228 | } |
| 2229 | addFileGlobDescription(zChng, &desc); |
| 2230 | }else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){ |
| 2231 | /* If p= or d= is present, ignore all other parameters other than n= */ |
| 2232 | char *zUuid; |
| 2233 | const char *zCiName; |
| 2234 | int np = 0, nd; |
| 2235 | const char *zBackTo = 0; |
| 2236 | const char *zFwdTo = 0; |
| 2237 | int ridBackTo = 0; |
| 2238 | int ridFwdTo = 0; |
| 2239 | int bBackAdded = 0; /* True if the zBackTo node was added */ |
| 2240 | int bFwdAdded = 0; /* True if the zBackTo node was added */ |
| 2241 | |
| 2242 | tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS; |
| 2243 | if( p_rid && d_rid ){ |
| 2244 | if( p_rid!=d_rid ) p_rid = d_rid; |
| 2245 | if( !haveParameterN ) nEntry = 10; |
| 2246 | } |
| 2247 | db_multi_exec( |
| 2248 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" |
| 2249 | ); |
| 2250 | add_extra_rids("ok", P("x")); |
| 2251 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", |
| 2252 | p_rid ? p_rid : d_rid); |
| 2253 | zCiName = zDPName; |
| 2254 | if( zCiName==0 ) zCiName = zUuid; |
| 2255 | blob_append_sql(&sql, " AND event.objid IN ok"); |
| 2256 | nd = 0; |
| 2257 | if( d_rid ){ |
| 2258 | double rStopTime = 9e99; |
| 2259 | zFwdTo = P("ft"); |
| 2260 | if( zFwdTo ){ |
| 2261 | double rStartDate = mtime_of_rid(d_rid, 0.0); |
| 2262 | ridFwdTo = first_checkin_with_tag_after_date(zFwdTo, rStartDate); |
| 2263 | if( ridFwdTo==0 ){ |
| 2264 | ridFwdTo = name_to_typed_rid(zBackTo,"ci"); |
| @@ -2265,10 +2274,13 @@ | |
| 2265 | } |
| 2266 | if( ridFwdTo ){ |
| 2267 | if( !haveParameterN ) nEntry = 0; |
| 2268 | rStopTime = mtime_of_rid(ridFwdTo, 9e99); |
| 2269 | } |
| 2270 | } |
| 2271 | if( rStopTime<9e99 ){ |
| 2272 | rStopTime += 5.8e-6; /* Round up by 1/2 second */ |
| 2273 | } |
| 2274 | db_multi_exec( |
| @@ -2285,49 +2297,85 @@ | |
| 2285 | ); |
| 2286 | if( ridFwdTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridFwdTo) ){ |
| 2287 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridFwdTo); |
| 2288 | bFwdAdded = 1; |
| 2289 | } |
| 2290 | nd = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2291 | if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); |
| 2292 | if( nd>0 || p_rid==0 ){ |
| 2293 | blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 2294 | } |
| 2295 | if( useDividers && !selectedRid ) selectedRid = d_rid; |
| 2296 | db_multi_exec("DELETE FROM ok"); |
| 2297 | } |
| 2298 | if( p_rid ){ |
| 2299 | zBackTo = P("bt"); |
| 2300 | if( zBackTo ){ |
| 2301 | double rDateLimit = mtime_of_rid(p_rid, 0.0); |
| 2302 | ridBackTo = last_checkin_with_tag_before_date(zBackTo, rDateLimit); |
| 2303 | if( ridBackTo==0 ){ |
| 2304 | ridBackTo = name_to_typed_rid(zBackTo,"ci"); |
| 2305 | } |
| 2306 | if( ridBackTo && !haveParameterN ) nEntry = 0; |
| 2307 | } |
| 2308 | compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo); |
| 2309 | if( ridBackTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridBackTo) ){ |
| 2310 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridBackTo); |
| 2311 | bBackAdded = 1; |
| 2312 | } |
| 2313 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2314 | if( np>0 || nd==0 ){ |
| 2315 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 2316 | blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s"); |
| 2317 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2318 | } |
| 2319 | if( useDividers && !selectedRid ) selectedRid = p_rid; |
| 2320 | } |
| 2321 | blob_appendf(&desc, " of %z%h</a>", |
| 2322 | href("%R/info?name=%h", zCiName), zCiName); |
| 2323 | if( ridBackTo ){ |
| 2324 | if( np==0 ){ |
| 2325 | blob_reset(&desc); |
| 2326 | blob_appendf(&desc, |
| 2327 | "Check-in %z%h</a> only (%z%h</a> does not precede it)", |
| 2328 | href("%R/info?name=%h",zCiName), zCiName, |
| 2329 | href("%R/info?name=%h",zBackTo), zBackTo); |
| 2330 | }else{ |
| 2331 | blob_appendf(&desc, " back to %z%h</a>%s", |
| 2332 | href("%R/info?name=%h",zBackTo), zBackTo, |
| 2333 | bBackAdded ? " (not a direct anscestor)" : ""); |
| @@ -2340,24 +2388,18 @@ | |
| 2340 | }else if( ridFwdTo ){ |
| 2341 | if( nd==0 ){ |
| 2342 | blob_reset(&desc); |
| 2343 | blob_appendf(&desc, |
| 2344 | "Check-in %z%h</a> only (%z%h</a> does not follow it)", |
| 2345 | href("%R/info?name=%h",zCiName), zCiName, |
| 2346 | href("%R/info?name=%h",zFwdTo), zFwdTo); |
| 2347 | }else{ |
| 2348 | blob_appendf(&desc, " up to %z%h</a>%s", |
| 2349 | href("%R/info?name=%h",zFwdTo), zFwdTo, |
| 2350 | bFwdAdded ? " (not a direct descendent)":""); |
| 2351 | } |
| 2352 | } |
| 2353 | if( d_rid ){ |
| 2354 | if( p_rid ){ |
| 2355 | /* If both p= and d= are set, we don't have the uuid of d yet. */ |
| 2356 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid); |
| 2357 | } |
| 2358 | } |
| 2359 | if( advancedMenu ){ |
| 2360 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); |
| 2361 | } |
| 2362 | style_submenu_entry("n","Max:",4,0); |
| 2363 | timeline_y_submenu(1); |
| 2364 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1703,11 +1703,11 @@ | |
| 1703 | int to_rid = name_choice("to","to2",&zTo2); /* to= for path timelines */ |
| 1704 | int bShort = P("shortest")!=0; /* shortest possible path */ |
| 1705 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 1706 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 1707 | int pd_rid; |
| 1708 | const char *zDPNameP, *zDPNameD; /* Value of p=, d=, or dp= params */ |
| 1709 | double rBefore, rAfter, rCirca; /* Boundary times */ |
| 1710 | const char *z; |
| 1711 | char *zOlderButton = 0; /* URL for Older button at the bottom */ |
| 1712 | char *zOlderButtonLabel = 0; /* Label for the Older Button */ |
| 1713 | char *zNewerButton = 0; /* URL for Newer button at the top */ |
| @@ -1770,20 +1770,20 @@ | |
| 1770 | }else{ |
| 1771 | nEntry = 50; |
| 1772 | } |
| 1773 | |
| 1774 | /* Query parameters d=, p=, and f= and variants */ |
| 1775 | p_rid = name_choice("p","p2", &zDPNameP); |
| 1776 | d_rid = name_choice("d","d2", &zDPNameD); |
| 1777 | z = P("f"); |
| 1778 | f_rid = z ? name_to_typed_rid(z,"ci") : 0; |
| 1779 | z = P("df"); |
| 1780 | if( z && (d_rid = name_to_typed_rid(z,"ci"))!=0 ){ |
| 1781 | nEntry = 0; |
| 1782 | useDividers = 0; |
| 1783 | cgi_replace_query_parameter("d",fossil_strdup(z)); |
| 1784 | zDPNameD = zDPNameP = z; |
| 1785 | } |
| 1786 | |
| 1787 | /* Undocumented query parameter to set JS mode */ |
| 1788 | builtin_set_js_delivery_mode(P("jsmode"),1); |
| 1789 | |
| @@ -1803,13 +1803,14 @@ | |
| 1803 | showCherrypicks = 0; |
| 1804 | } |
| 1805 | |
| 1806 | /* To view the timeline, must have permission to read project data. |
| 1807 | */ |
| 1808 | pd_rid = name_choice("dp","dp2",&zDPNameP); |
| 1809 | if( pd_rid ){ |
| 1810 | p_rid = d_rid = pd_rid; |
| 1811 | zDPNameD = zDPNameP; |
| 1812 | } |
| 1813 | if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum) |
| 1814 | || (bisectLocal && !g.perm.Setup) |
| 1815 | ){ |
| 1816 | login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); |
| @@ -2226,39 +2227,47 @@ | |
| 2227 | } |
| 2228 | } |
| 2229 | } |
| 2230 | addFileGlobDescription(zChng, &desc); |
| 2231 | }else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){ |
| 2232 | /* If either p= or d= or both are present, ignore all other parameters |
| 2233 | ** other than n=, ft=, and bt= */ |
| 2234 | const char *zBaseName; |
| 2235 | int np = 0, nd; |
| 2236 | const char *zBackTo = 0; |
| 2237 | const char *zFwdTo = 0; |
| 2238 | int ridBackTo = 0; |
| 2239 | int ridFwdTo = 0; |
| 2240 | int bBackAdded = 0; /* True if the zBackTo node was added */ |
| 2241 | int bFwdAdded = 0; /* True if the zBackTo node was added */ |
| 2242 | int bSeparateDandP = 0; /* p_rid & d_rid both exist and are distinct */ |
| 2243 | |
| 2244 | tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS; |
| 2245 | if( p_rid && d_rid && p_rid!=d_rid ){ |
| 2246 | bSeparateDandP = 1; |
| 2247 | db_multi_exec( |
| 2248 | "CREATE TEMP TABLE IF NOT EXISTS ok_d(rid INTEGER PRIMARY KEY)" |
| 2249 | ); |
| 2250 | }else{ |
| 2251 | zBaseName = p_rid ? zDPNameP : zDPNameD; |
| 2252 | } |
| 2253 | db_multi_exec( |
| 2254 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)" |
| 2255 | ); |
| 2256 | add_extra_rids("ok", P("x")); |
| 2257 | blob_append_sql(&sql, " AND event.objid IN ok"); |
| 2258 | nd = 0; |
| 2259 | if( d_rid ){ |
| 2260 | double rStopTime = 9e99; |
| 2261 | zFwdTo = P("ft"); |
| 2262 | if( zFwdTo && bSeparateDandP ){ |
| 2263 | if( zError==0 ){ |
| 2264 | zError = "Cannot use the ft= query parameter when both p= and d= " |
| 2265 | "are used and have distinct values."; |
| 2266 | } |
| 2267 | zFwdTo = 0; |
| 2268 | } |
| 2269 | if( zFwdTo ){ |
| 2270 | double rStartDate = mtime_of_rid(d_rid, 0.0); |
| 2271 | ridFwdTo = first_checkin_with_tag_after_date(zFwdTo, rStartDate); |
| 2272 | if( ridFwdTo==0 ){ |
| 2273 | ridFwdTo = name_to_typed_rid(zBackTo,"ci"); |
| @@ -2265,10 +2274,13 @@ | |
| 2274 | } |
| 2275 | if( ridFwdTo ){ |
| 2276 | if( !haveParameterN ) nEntry = 0; |
| 2277 | rStopTime = mtime_of_rid(ridFwdTo, 9e99); |
| 2278 | } |
| 2279 | }else if( bSeparateDandP ){ |
| 2280 | rStopTime = mtime_of_rid(p_rid, 9e99); |
| 2281 | nEntry = 0; |
| 2282 | } |
| 2283 | if( rStopTime<9e99 ){ |
| 2284 | rStopTime += 5.8e-6; /* Round up by 1/2 second */ |
| 2285 | } |
| 2286 | db_multi_exec( |
| @@ -2285,49 +2297,85 @@ | |
| 2297 | ); |
| 2298 | if( ridFwdTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridFwdTo) ){ |
| 2299 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridFwdTo); |
| 2300 | bFwdAdded = 1; |
| 2301 | } |
| 2302 | if( bSeparateDandP ){ |
| 2303 | db_multi_exec( |
| 2304 | "INSERT INTO ok_d SELECT rid FROM ok;" |
| 2305 | "DELETE FROM ok;" |
| 2306 | ); |
| 2307 | }else{ |
| 2308 | nd = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2309 | if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); |
| 2310 | if( nd>0 || p_rid==0 ){ |
| 2311 | blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 2312 | } |
| 2313 | if( useDividers && !selectedRid ) selectedRid = d_rid; |
| 2314 | db_multi_exec("DELETE FROM ok"); |
| 2315 | } |
| 2316 | } |
| 2317 | if( p_rid ){ |
| 2318 | zBackTo = P("bt"); |
| 2319 | if( zBackTo && bSeparateDandP ){ |
| 2320 | if( zError==0 ){ |
| 2321 | zError = "Cannot use the bt= query parameter when both p= and d= " |
| 2322 | "are used and have distinct values."; |
| 2323 | } |
| 2324 | zBackTo = 0; |
| 2325 | } |
| 2326 | if( zBackTo ){ |
| 2327 | double rDateLimit = mtime_of_rid(p_rid, 0.0); |
| 2328 | ridBackTo = last_checkin_with_tag_before_date(zBackTo, rDateLimit); |
| 2329 | if( ridBackTo==0 ){ |
| 2330 | ridBackTo = name_to_typed_rid(zBackTo,"ci"); |
| 2331 | } |
| 2332 | if( ridBackTo && !haveParameterN ) nEntry = 0; |
| 2333 | }else if( bSeparateDandP ){ |
| 2334 | ridBackTo = d_rid; |
| 2335 | nEntry = 0; |
| 2336 | } |
| 2337 | compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo); |
| 2338 | if( ridBackTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridBackTo) ){ |
| 2339 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridBackTo); |
| 2340 | bBackAdded = 1; |
| 2341 | } |
| 2342 | if( bSeparateDandP ){ |
| 2343 | db_multi_exec("DELETE FROM ok WHERE rid NOT IN ok_d;"); |
| 2344 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2345 | }else{ |
| 2346 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2347 | if( np>0 || nd==0 ){ |
| 2348 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 2349 | blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s"); |
| 2350 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2351 | } |
| 2352 | if( useDividers && !selectedRid ) selectedRid = p_rid; |
| 2353 | } |
| 2354 | } |
| 2355 | if( bSeparateDandP ){ |
| 2356 | int n = db_int(0, "SELECT count(*) FROM ok"); |
| 2357 | blob_reset(&desc); |
| 2358 | blob_appendf(&desc, |
| 2359 | "%d check-ins that are both ancestors of %z%h</a>" |
| 2360 | " and descendents of %z%h</a>", |
| 2361 | n, |
| 2362 | href("%R/info?name=%h",zDPNameP),zDPNameP, |
| 2363 | href("%R/info/name=%h",zDPNameD),zDPNameD |
| 2364 | ); |
| 2365 | ridBackTo = 0; |
| 2366 | ridFwdTo = 0; |
| 2367 | }else{ |
| 2368 | blob_appendf(&desc, " of %z%h</a>", |
| 2369 | href("%R/info?name=%h", zBaseName), zBaseName); |
| 2370 | } |
| 2371 | if( ridBackTo ){ |
| 2372 | if( np==0 ){ |
| 2373 | blob_reset(&desc); |
| 2374 | blob_appendf(&desc, |
| 2375 | "Check-in %z%h</a> only (%z%h</a> does not precede it)", |
| 2376 | href("%R/info?name=%h",zBaseName), zBaseName, |
| 2377 | href("%R/info?name=%h",zBackTo), zBackTo); |
| 2378 | }else{ |
| 2379 | blob_appendf(&desc, " back to %z%h</a>%s", |
| 2380 | href("%R/info?name=%h",zBackTo), zBackTo, |
| 2381 | bBackAdded ? " (not a direct anscestor)" : ""); |
| @@ -2340,24 +2388,18 @@ | |
| 2388 | }else if( ridFwdTo ){ |
| 2389 | if( nd==0 ){ |
| 2390 | blob_reset(&desc); |
| 2391 | blob_appendf(&desc, |
| 2392 | "Check-in %z%h</a> only (%z%h</a> does not follow it)", |
| 2393 | href("%R/info?name=%h",zBaseName), zBaseName, |
| 2394 | href("%R/info?name=%h",zFwdTo), zFwdTo); |
| 2395 | }else{ |
| 2396 | blob_appendf(&desc, " up to %z%h</a>%s", |
| 2397 | href("%R/info?name=%h",zFwdTo), zFwdTo, |
| 2398 | bFwdAdded ? " (not a direct descendent)":""); |
| 2399 | } |
| 2400 | } |
| 2401 | if( advancedMenu ){ |
| 2402 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); |
| 2403 | } |
| 2404 | style_submenu_entry("n","Max:",4,0); |
| 2405 | timeline_y_submenu(1); |
| 2406 |