File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2007 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This file contains code to implement the timeline web page
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: */
abce5105e2 2007-09-01       drh: #include <string.h>
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "timeline.h"
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Generate a hyperlink to a version.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void hyperlink_to_uuid(const char *zUuid){
dbda8d6ce9 2007-07-21       drh:   char zShortUuid[UUID_SIZE+1];
dbda8d6ce9 2007-07-21       drh:   sprintf(zShortUuid, "%.10s", zUuid);
fd36718ad9 2007-07-31       drh:   if( g.okHistory ){
72b3b1ad47 2007-09-22       drh:     @ <a href="%s(g.zBaseURL)/info/%s(zUuid)">[%s(zShortUuid)]</a>
fd36718ad9 2007-07-31       drh:   }else{
fd36718ad9 2007-07-31       drh:     @ <b>[%s(zShortUuid)]</b>
bbdd4f9915 2007-08-27       drh:   }
bbdd4f9915 2007-08-27       drh: }
bbdd4f9915 2007-08-27       drh: 
bbdd4f9915 2007-08-27       drh: /*
bbdd4f9915 2007-08-27       drh: ** Generate a hyperlink that invokes javascript to highlight
bbdd4f9915 2007-08-27       drh: ** a version on mouseover.
bbdd4f9915 2007-08-27       drh: */
4d051c1eda 2007-08-29       drh: void hyperlink_to_uuid_with_mouseover(
4d051c1eda 2007-08-29       drh:   const char *zUuid,   /* The UUID to display */
4d051c1eda 2007-08-29       drh:   const char *zIn,     /* Javascript proc for mouseover */
4d051c1eda 2007-08-29       drh:   const char *zOut,    /* Javascript proc for mouseout */
4d051c1eda 2007-08-29       drh:   int id               /* Argument to javascript procs */
4d051c1eda 2007-08-29       drh: ){
bbdd4f9915 2007-08-27       drh:   char zShortUuid[UUID_SIZE+1];
bbdd4f9915 2007-08-27       drh:   sprintf(zShortUuid, "%.10s", zUuid);
bbdd4f9915 2007-08-27       drh:   if( g.okHistory ){
4d051c1eda 2007-08-29       drh:     @ <a onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")'
bbdd4f9915 2007-08-27       drh:     @    href="%s(g.zBaseURL)/vinfo/%s(zUuid)">[%s(zShortUuid)]</a>
bbdd4f9915 2007-08-27       drh:   }else{
4d051c1eda 2007-08-29       drh:     @ <b onmouseover='%s(zIn)("m%d(id)")' onmouseout='%s(zOut)("m%d(id)")'>
bbdd4f9915 2007-08-27       drh:     @ [%s(zShortUuid)]</b>
fd36718ad9 2007-07-31       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Generate a hyperlink to a diff between two versions.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void hyperlink_to_diff(const char *zV1, const char *zV2){
fd36718ad9 2007-07-31       drh:   if( g.okHistory ){
fd36718ad9 2007-07-31       drh:     if( zV2==0 ){
fd36718ad9 2007-07-31       drh:       @ <a href="%s(g.zBaseURL)/diff?v2=%s(zV1)">[diff]</a>
fd36718ad9 2007-07-31       drh:     }else{
fd36718ad9 2007-07-31       drh:       @ <a href="%s(g.zBaseURL)/diff?v1=%s(zV1)&v2=%s(zV2)">[diff]</a>
fd36718ad9 2007-07-31       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
afcdc7ec97 2007-08-01       drh: ** Output a timeline in the web format given a query.  The query
9395aba4f4 2007-09-22       drh: ** should return these columns:
bbdd4f9915 2007-08-27       drh: **
bbdd4f9915 2007-08-27       drh: **    0.  rid
bbdd4f9915 2007-08-27       drh: **    1.  UUID
bbdd4f9915 2007-08-27       drh: **    2.  Date/Time
bbdd4f9915 2007-08-27       drh: **    3.  Comment string
bbdd4f9915 2007-08-27       drh: **    4.  User
bbdd4f9915 2007-08-27       drh: **    5.  Number of non-merge children
bbdd4f9915 2007-08-27       drh: **    6.  Number of parents
bbdd4f9915 2007-08-27       drh: **    7.  True if is a leaf
5e2392307d 2007-09-22       drh: **    8.  background color
dfea940da8 2007-10-09       drh: **    9.  type ("ci", "w")
dbda8d6ce9 2007-07-21       drh: */
bbdd4f9915 2007-08-27       drh: void www_print_timeline(
82fc5abb60 2008-02-26       drh:   Stmt *pQuery
bbdd4f9915 2007-08-27       drh:  ){
ebb2765954 2007-12-04       drh:   int wikiFlags;
ebb2765954 2007-12-04       drh:   int mxWikiLen;
a84089319c 2007-10-11       drh:   Blob comment;
afcdc7ec97 2007-08-01       drh:   char zPrevDate[20];
dbda8d6ce9 2007-07-21       drh:   zPrevDate[0] = 0;
ebb2765954 2007-12-04       drh: 
ebb2765954 2007-12-04       drh:   mxWikiLen = db_get_int("timeline-max-comment", 0);
ebb2765954 2007-12-04       drh:   if( db_get_boolean("timeline-block-markup", 0) ){
ebb2765954 2007-12-04       drh:     wikiFlags = WIKI_INLINE;
ebb2765954 2007-12-04       drh:   }else{
ebb2765954 2007-12-04       drh:     wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
ebb2765954 2007-12-04       drh:   }
5e2392307d 2007-09-22       drh: 
e15fe43153 2007-08-31       drh:   db_multi_exec(
e15fe43153 2007-08-31       drh:      "CREATE TEMP TABLE IF NOT EXISTS seen(rid INTEGER PRIMARY KEY);"
e15fe43153 2007-08-31       drh:      "DELETE FROM seen;"
dbda8d6ce9 2007-07-21       drh:   );
dbda8d6ce9 2007-07-21       drh:   @ <table cellspacing=0 border=0 cellpadding=0>
6d58613757 2007-10-06       drh:   blob_zero(&comment);
afcdc7ec97 2007-08-01       drh:   while( db_step(pQuery)==SQLITE_ROW ){
bbdd4f9915 2007-08-27       drh:     int rid = db_column_int(pQuery, 0);
4d051c1eda 2007-08-29       drh:     const char *zUuid = db_column_text(pQuery, 1);
bbdd4f9915 2007-08-27       drh:     int nPChild = db_column_int(pQuery, 5);
bbdd4f9915 2007-08-27       drh:     int nParent = db_column_int(pQuery, 6);
bbdd4f9915 2007-08-27       drh:     int isLeaf = db_column_int(pQuery, 7);
5e2392307d 2007-09-22       drh:     const char *zBgClr = db_column_text(pQuery, 8);
bbdd4f9915 2007-08-27       drh:     const char *zDate = db_column_text(pQuery, 2);
dfea940da8 2007-10-09       drh:     const char *zType = db_column_text(pQuery, 9);
dfea940da8 2007-10-09       drh:     const char *zUser = db_column_text(pQuery, 4);
82fc5abb60 2008-02-26       drh:     db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
dbda8d6ce9 2007-07-21       drh:     if( memcmp(zDate, zPrevDate, 10) ){
dbda8d6ce9 2007-07-21       drh:       sprintf(zPrevDate, "%.10s", zDate);
dbda8d6ce9 2007-07-21       drh:       @ <tr><td colspan=3>
34af72801d 2007-11-23       drh:       @   <div class="divider">%s(zPrevDate)</div>
dbda8d6ce9 2007-07-21       drh:       @ </td></tr>
dbda8d6ce9 2007-07-21       drh:     }
4d03017923 2007-08-30       drh:     @ <tr>
bbdd4f9915 2007-08-27       drh:     @ <td valign="top">%s(&zDate[11])</td>
4d03017923 2007-08-30       drh:     @ <td width="20" align="center" valign="top">
4d03017923 2007-08-30       drh:     @ <font id="m%d(rid)" size="+1" color="white">*</font></td>
5e2392307d 2007-09-22       drh:     if( zBgClr && zBgClr[0] ){
5e2392307d 2007-09-22       drh:       @ <td valign="top" align="left" bgcolor="%h(zBgClr)">
5e2392307d 2007-09-22       drh:     }else{
5e2392307d 2007-09-22       drh:       @ <td valign="top" align="left">
5e2392307d 2007-09-22       drh:     }
dfea940da8 2007-10-09       drh:     if( zType[0]=='c' ){
dfea940da8 2007-10-09       drh:       hyperlink_to_uuid_with_mouseover(zUuid, "xin", "xout", rid);
dfea940da8 2007-10-09       drh:       if( nParent>1 ){
dfea940da8 2007-10-09       drh:         @ <b>Merge</b>
dfea940da8 2007-10-09       drh:       }
dfea940da8 2007-10-09       drh:       if( nPChild>1 ){
dfea940da8 2007-10-09       drh:         @ <b>Fork</b>
dfea940da8 2007-10-09       drh:       }
dfea940da8 2007-10-09       drh:       if( isLeaf ){
dfea940da8 2007-10-09       drh:         @ <b>Leaf</b>
bbdd4f9915 2007-08-27       drh:       }
dfea940da8 2007-10-09       drh:     }else{
dfea940da8 2007-10-09       drh:       hyperlink_to_uuid(zUuid);
6d58613757 2007-10-06       drh:     }
6d58613757 2007-10-06       drh:     db_column_blob(pQuery, 3, &comment);
ebb2765954 2007-12-04       drh:     if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
20553a420c 2007-12-03       drh:       Blob truncated;
20553a420c 2007-12-03       drh:       blob_zero(&truncated);
ebb2765954 2007-12-04       drh:       blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
20553a420c 2007-12-03       drh:       blob_append(&truncated, "...", 3);
ebb2765954 2007-12-04       drh:       wiki_convert(&truncated, 0, wikiFlags);
20553a420c 2007-12-03       drh:       blob_reset(&truncated);
20553a420c 2007-12-03       drh:     }else{
ebb2765954 2007-12-04       drh:       wiki_convert(&comment, 0, wikiFlags);
20553a420c 2007-12-03       drh:     }
6d58613757 2007-10-06       drh:     blob_reset(&comment);
dfea940da8 2007-10-09       drh:     @ (by %h(zUser))</td></tr>
afcdc7ec97 2007-08-01       drh:   }
dbda8d6ce9 2007-07-21       drh:   @ </table>
afcdc7ec97 2007-08-01       drh: }
afcdc7ec97 2007-08-01       drh: 
bbdd4f9915 2007-08-27       drh: /*
e6aa161204 2008-02-26       drh: ** Create a temporary table suitable for storing timeline data.
9395aba4f4 2007-09-22       drh: */
e6aa161204 2008-02-26       drh: static void timeline_temp_table(void){
e6aa161204 2008-02-26       drh:   static const char zSql[] =
e6aa161204 2008-02-26       drh:     @ CREATE TEMP TABLE IF NOT EXISTS timeline(
e6aa161204 2008-02-26       drh:     @   rid INTEGER PRIMARY KEY,
e6aa161204 2008-02-26       drh:     @   uuid TEXT,
e6aa161204 2008-02-26       drh:     @   timestamp TEXT,
e6aa161204 2008-02-26       drh:     @   comment TEXT,
e6aa161204 2008-02-26       drh:     @   user TEXT,
e6aa161204 2008-02-26       drh:     @   nchild INTEGER,
e6aa161204 2008-02-26       drh:     @   nparent INTEGER,
e6aa161204 2008-02-26       drh:     @   isleaf BOOLEAN,
e6aa161204 2008-02-26       drh:     @   bgcolor TEXT,
e6aa161204 2008-02-26       drh:     @   etype TEXT
e6aa161204 2008-02-26       drh:     @ )
e6aa161204 2008-02-26       drh:   ;
e6aa161204 2008-02-26       drh:   db_multi_exec(zSql);
9395aba4f4 2007-09-22       drh: }
9395aba4f4 2007-09-22       drh: 
9395aba4f4 2007-09-22       drh: /*
9395aba4f4 2007-09-22       drh: ** Return a pointer to a constant string that forms the basis
9395aba4f4 2007-09-22       drh: ** for a timeline query for the WWW interface.
bbdd4f9915 2007-08-27       drh: */
9395aba4f4 2007-09-22       drh: const char *timeline_query_for_www(void){
9395aba4f4 2007-09-22       drh:   static const char zBaseSql[] =
9395aba4f4 2007-09-22       drh:     @ SELECT
9395aba4f4 2007-09-22       drh:     @   blob.rid,
9395aba4f4 2007-09-22       drh:     @   uuid,
20553a420c 2007-12-03       drh:     @   datetime(event.mtime,'localtime') AS timestamp,
3b5514ed82 2007-09-22       drh:     @   coalesce(ecomment, comment),
3b5514ed82 2007-09-22       drh:     @   coalesce(euser, user),
9395aba4f4 2007-09-22       drh:     @   (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim=1),
9395aba4f4 2007-09-22       drh:     @   (SELECT count(*) FROM plink WHERE cid=blob.rid),
9395aba4f4 2007-09-22       drh:     @   NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid),
dfea940da8 2007-10-09       drh:     @   coalesce(bgcolor, brbgcolor),
dfea940da8 2007-10-09       drh:     @   event.type
9395aba4f4 2007-09-22       drh:     @  FROM event JOIN blob
9395aba4f4 2007-09-22       drh:     @ WHERE blob.rid=event.objid
9395aba4f4 2007-09-22       drh:   ;
9395aba4f4 2007-09-22       drh:   return zBaseSql;
bbdd4f9915 2007-08-27       drh: }
afcdc7ec97 2007-08-01       drh: 
afcdc7ec97 2007-08-01       drh: /*
afcdc7ec97 2007-08-01       drh: ** WEBPAGE: timeline
e15fe43153 2007-08-31       drh: **
e15fe43153 2007-08-31       drh: ** Query parameters:
e15fe43153 2007-08-31       drh: **
e6aa161204 2008-02-26       drh: **    a=TIMESTAMP    after this date
e6aa161204 2008-02-26       drh: **    b=TIMESTAMP    before this date.
e6aa161204 2008-02-26       drh: **    n=COUNT        number of events in output
e6aa161204 2008-02-26       drh: **    p=RID          artifact RID and up to COUNT parents and ancestors
6458f020fc 2008-05-14       drh: **    d=RID          artifact RID and up to COUNT descendants
e6aa161204 2008-02-26       drh: **    u=USER         only if belonging to this user
e6aa161204 2008-02-26       drh: **    y=TYPE         'ci', 'w', 'tkt'
e6aa161204 2008-02-26       drh: **
e6aa161204 2008-02-26       drh: ** p= and d= can appear individually or together.  If either p= or d=
e6aa161204 2008-02-26       drh: ** appear, then u=, y=, a=, and b= are ignored.
e6aa161204 2008-02-26       drh: **
e6aa161204 2008-02-26       drh: ** If a= and b= appear, only a= is used.  If neither appear, the most
e6aa161204 2008-02-26       drh: ** recent events are choosen.
e6aa161204 2008-02-26       drh: **
e6aa161204 2008-02-26       drh: ** If n= is missing, the default count is 20.
afcdc7ec97 2007-08-01       drh: */
afcdc7ec97 2007-08-01       drh: void page_timeline(void){
e6aa161204 2008-02-26       drh:   Stmt q;                            /* Query used to generate the timeline */
e6aa161204 2008-02-26       drh:   Blob sql;                          /* text of SQL used to generate timeline */
e6aa161204 2008-02-26       drh:   Blob desc;                         /* Description of the timeline */
e38c89130f 2008-02-24       drh:   int nEntry = atoi(PD("n","20"));   /* Max number of entries on timeline */
e6aa161204 2008-02-26       drh:   int p_rid = atoi(PD("p","0"));     /* artifact p and its parents */
6458f020fc 2008-05-14       drh:   int d_rid = atoi(PD("d","0"));     /* artifact d and its descendants */
e38c89130f 2008-02-24       drh:   const char *zUser = P("u");        /* All entries by this user if not NULL */
e38c89130f 2008-02-24       drh:   const char *zType = P("y");        /* Type of events.  All if NULL */
e6aa161204 2008-02-26       drh:   const char *zAfter = P("a");       /* Events after this time */
e6aa161204 2008-02-26       drh:   const char *zBefore = P("b");      /* Events before this time */
afcdc7ec97 2007-08-01       drh: 
afcdc7ec97 2007-08-01       drh:   /* To view the timeline, must have permission to read project data.
afcdc7ec97 2007-08-01       drh:   */
afcdc7ec97 2007-08-01       drh:   login_check_credentials();
afcdc7ec97 2007-08-01       drh:   if( !g.okRead ){ login_needed(); return; }
afcdc7ec97 2007-08-01       drh: 
afcdc7ec97 2007-08-01       drh:   style_header("Timeline");
2b0d4519dc 2008-05-05       drh:   login_anonymous_available();
e6aa161204 2008-02-26       drh:   timeline_temp_table();
20553a420c 2007-12-03       drh:   blob_zero(&sql);
e38c89130f 2008-02-24       drh:   blob_zero(&desc);
e6aa161204 2008-02-26       drh:   blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
20553a420c 2007-12-03       drh:   blob_append(&sql, timeline_query_for_www(), -1);
e6aa161204 2008-02-26       drh:   if( p_rid || d_rid ){
e6aa161204 2008-02-26       drh:     /* If p= or d= is present, ignore all other parameters other than n= */
e38c89130f 2008-02-24       drh:     char *zUuid;
e6aa161204 2008-02-26       drh:     int np, nd;
e6aa161204 2008-02-26       drh: 
e6aa161204 2008-02-26       drh:     if( p_rid && d_rid && p_rid!=d_rid ) p_rid = d_rid;
abce5105e2 2007-09-01       drh:     db_multi_exec(
abce5105e2 2007-09-01       drh:        "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
abce5105e2 2007-09-01       drh:     );
e6aa161204 2008-02-26       drh:     zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d",
e6aa161204 2008-02-26       drh:                          p_rid ? p_rid : d_rid);
e6aa161204 2008-02-26       drh:     blob_appendf(&sql, " AND event.objid IN ok");
e6aa161204 2008-02-26       drh:     nd = 0;
e6aa161204 2008-02-26       drh:     if( d_rid ){
6458f020fc 2008-05-14       drh:       compute_descendants(d_rid, nEntry);
e6aa161204 2008-02-26       drh:       nd = db_int(0, "SELECT count(*)-1 FROM ok");
e6aa161204 2008-02-26       drh:       if( nd>0 ){
e6aa161204 2008-02-26       drh:         db_multi_exec("%s", blob_str(&sql));
6458f020fc 2008-05-14       drh:         blob_appendf(&desc, "%d descendants", nd);
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:       db_multi_exec("DELETE FROM ok");
e6aa161204 2008-02-26       drh:     }
e6aa161204 2008-02-26       drh:     if( p_rid ){
e6aa161204 2008-02-26       drh:       compute_ancestors(p_rid, nEntry);
e6aa161204 2008-02-26       drh:       np = db_int(0, "SELECT count(*)-1 FROM ok");
e6aa161204 2008-02-26       drh:       if( np>0 ){
e6aa161204 2008-02-26       drh:         if( nd>0 ) blob_appendf(&desc, " and ");
e6aa161204 2008-02-26       drh:         blob_appendf(&desc, "%d ancestors", np);
e6aa161204 2008-02-26       drh:         db_multi_exec("%s", blob_str(&sql));
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:     }
2b0d4519dc 2008-05-05       drh:     if( g.okHistory ){
2b0d4519dc 2008-05-05       drh:       blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
2b0d4519dc 2008-05-05       drh:                    g.zBaseURL, zUuid, zUuid);
20553a420c 2007-12-03       drh:     }else{
2b0d4519dc 2008-05-05       drh:       blob_appendf(&desc, " of [%.10s]", zUuid);
2b0d4519dc 2008-05-05       drh:     }
e6aa161204 2008-02-26       drh:     db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
20553a420c 2007-12-03       drh:   }else{
7915bd0665 2008-02-26       drh:     int n;
7915bd0665 2008-02-26       drh:     Blob url;
e6aa161204 2008-02-26       drh:     const char *zEType = "event";
7915bd0665 2008-02-26       drh:     const char *zDate;
7915bd0665 2008-02-26       drh:     blob_zero(&url);
82fc5abb60 2008-02-26       drh:     blob_appendf(&url, "%s/timeline?n=%d", g.zBaseURL, nEntry);
e6aa161204 2008-02-26       drh:     if( zType ){
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " AND event.type=%Q", zType);
7915bd0665 2008-02-26       drh:       blob_appendf(&url, "&y=%T", zType);
e6aa161204 2008-02-26       drh:       if( zType[0]=='c' ){
e6aa161204 2008-02-26       drh:         zEType = "checkin";
e6aa161204 2008-02-26       drh:       }else if( zType[0]=='w' ){
e6aa161204 2008-02-26       drh:         zEType = "wiki edit";
e6aa161204 2008-02-26       drh:       }else if( zType[0]=='t' ){
e6aa161204 2008-02-26       drh:         zEType = "ticket change";
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:     }
e6aa161204 2008-02-26       drh:     if( zUser ){
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " AND event.user=%Q", zUser);
7915bd0665 2008-02-26       drh:       blob_appendf(&url, "&u=%T", zUser);
e6aa161204 2008-02-26       drh:     }
e6aa161204 2008-02-26       drh:     if( zAfter ){
e6aa161204 2008-02-26       drh:       while( isspace(zAfter[0]) ){ zAfter++; }
e6aa161204 2008-02-26       drh:       if( zAfter[0] ){
e6aa161204 2008-02-26       drh:         blob_appendf(&sql,
e6aa161204 2008-02-26       drh:            " AND event.mtime>=(SELECT julianday(%Q, 'utc'))"
e6aa161204 2008-02-26       drh:            " ORDER BY event.mtime ASC", zAfter);
e6aa161204 2008-02-26       drh:         zBefore = 0;
7915bd0665 2008-02-26       drh:       }else{
7915bd0665 2008-02-26       drh:         zAfter = 0;
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:     }else if( zBefore ){
e6aa161204 2008-02-26       drh:       while( isspace(zBefore[0]) ){ zBefore++; }
e6aa161204 2008-02-26       drh:       if( zBefore[0] ){
e6aa161204 2008-02-26       drh:         blob_appendf(&sql,
e6aa161204 2008-02-26       drh:            " AND event.mtime<=(SELECT julianday(%Q, 'utc'))"
e6aa161204 2008-02-26       drh:            " ORDER BY event.mtime DESC", zBefore);
7915bd0665 2008-02-26       drh:        }else{
7915bd0665 2008-02-26       drh:         zBefore = 0;
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:     }else{
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " ORDER BY event.mtime DESC");
e6aa161204 2008-02-26       drh:     }
e6aa161204 2008-02-26       drh:     blob_appendf(&sql, " LIMIT %d", nEntry);
e6aa161204 2008-02-26       drh:     db_multi_exec("%s", blob_str(&sql));
7915bd0665 2008-02-26       drh: 
7915bd0665 2008-02-26       drh:     n = db_int(0, "SELECT count(*) FROM timeline");
7915bd0665 2008-02-26       drh:     if( zAfter==0 && zBefore==0 ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, "%d most recent %ss", n, zEType);
abce5105e2 2007-09-01       drh:     }else{
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, "%d %ss", n, zEType);
7915bd0665 2008-02-26       drh:     }
7915bd0665 2008-02-26       drh:     if( zUser ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, " by user %h", zUser);
7915bd0665 2008-02-26       drh:     }
7915bd0665 2008-02-26       drh:     if( zAfter ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
7915bd0665 2008-02-26       drh:     }else if( zBefore ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
7915bd0665 2008-02-26       drh:     }
2b0d4519dc 2008-05-05       drh:     if( g.okHistory ){
2b0d4519dc 2008-05-05       drh:       if( zAfter || n==nEntry ){
2b0d4519dc 2008-05-05       drh:         zDate = db_text(0, "SELECT min(timestamp) FROM timeline");
2b0d4519dc 2008-05-05       drh:         blob_appendf(&desc, " <a href='%b&b=%s'>[older]</a>", &url, zDate);
2b0d4519dc 2008-05-05       drh:       }
2b0d4519dc 2008-05-05       drh:       if( zBefore || (zAfter && n==nEntry) ){
2b0d4519dc 2008-05-05       drh:         zDate = db_text(0, "SELECT max(timestamp) FROM timeline");
2b0d4519dc 2008-05-05       drh:         blob_appendf(&desc, " <a href='%b&a=%s'>[more recent]</a>", &url,zDate);
2b0d4519dc 2008-05-05       drh:       }
3945057916 2007-08-01       drh:     }
3945057916 2007-08-01       drh:   }
20553a420c 2007-12-03       drh:   blob_zero(&sql);
e6aa161204 2008-02-26       drh:   db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
e38c89130f 2008-02-24       drh:   @ <h2>%b(&desc)</h2>
e38c89130f 2008-02-24       drh:   blob_reset(&desc);
afcdc7ec97 2007-08-01       drh:   www_print_timeline(&q);
afcdc7ec97 2007-08-01       drh:   db_finalize(&q);
82fc5abb60 2008-02-26       drh: 
bbdd4f9915 2007-08-27       drh:   @ <script>
bbdd4f9915 2007-08-27       drh:   @ var parentof = new Object();
bbdd4f9915 2007-08-27       drh:   @ var childof = new Object();
82fc5abb60 2008-02-26       drh:   db_prepare(&q, "SELECT rid FROM timeline");
82fc5abb60 2008-02-26       drh:   while( db_step(&q)==SQLITE_ROW ){
82fc5abb60 2008-02-26       drh:     int rid = db_column_int(&q, 0);
82fc5abb60 2008-02-26       drh:     Stmt q2;
82fc5abb60 2008-02-26       drh:     const char *zSep;
82fc5abb60 2008-02-26       drh:     Blob *pOut = cgi_output_blob();
82fc5abb60 2008-02-26       drh: 
82fc5abb60 2008-02-26       drh:     db_prepare(&q2, "SELECT pid FROM plink WHERE cid=%d", rid);
82fc5abb60 2008-02-26       drh:     zSep = "";
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "parentof[\"m%d\"] = [", rid);
82fc5abb60 2008-02-26       drh:     while( db_step(&q2)==SQLITE_ROW ){
82fc5abb60 2008-02-26       drh:       int pid = db_column_int(&q2, 0);
82fc5abb60 2008-02-26       drh:       blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
82fc5abb60 2008-02-26       drh:       zSep = ",";
82fc5abb60 2008-02-26       drh:     }
82fc5abb60 2008-02-26       drh:     db_finalize(&q2);
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "];\n");
82fc5abb60 2008-02-26       drh:     db_prepare(&q2, "SELECT cid FROM plink WHERE pid=%d", rid);
82fc5abb60 2008-02-26       drh:     zSep = "";
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "childof[\"m%d\"] = [", rid);
82fc5abb60 2008-02-26       drh:     while( db_step(&q2)==SQLITE_ROW ){
82fc5abb60 2008-02-26       drh:       int pid = db_column_int(&q2, 0);
82fc5abb60 2008-02-26       drh:       blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
82fc5abb60 2008-02-26       drh:       zSep = ",";
82fc5abb60 2008-02-26       drh:     }
82fc5abb60 2008-02-26       drh:     db_finalize(&q2);
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "];\n");
3945057916 2007-08-01       drh:   }
82fc5abb60 2008-02-26       drh:   db_finalize(&q);
bbdd4f9915 2007-08-27       drh:   @ function setall(value){
bbdd4f9915 2007-08-27       drh:   @   for(var x in parentof){
bbdd4f9915 2007-08-27       drh:   @     setone(x,value);
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
4d03017923 2007-08-30       drh:   @ setall("#ffffff");
4d051c1eda 2007-08-29       drh:   @ function setone(id, clr){
5341655085 2007-08-27       drh:   @   if( parentof[id]==null ) return 0;
bbdd4f9915 2007-08-27       drh:   @   var w = document.getElementById(id);
5341655085 2007-08-27       drh:   @   if( w.style.color==clr ){
5341655085 2007-08-27       drh:   @     return 0
bbdd4f9915 2007-08-27       drh:   @   }else{
5341655085 2007-08-27       drh:   @     w.style.color = clr
5341655085 2007-08-27       drh:   @     return 1
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
bbdd4f9915 2007-08-27       drh:   @ function xin(id) {
4d051c1eda 2007-08-29       drh:   @   setall("#ffffff");
4d03017923 2007-08-30       drh:   @   setone(id,"#ff0000");
4d03017923 2007-08-30       drh:   @   set_children(id, "#b0b0b0");
4d03017923 2007-08-30       drh:   @   set_parents(id, "#b0b0b0");
4d051c1eda 2007-08-29       drh:   @   for(var x in parentof[id]){
4d051c1eda 2007-08-29       drh:   @     var pid = parentof[id][x]
4d051c1eda 2007-08-29       drh:   @     var w = document.getElementById(pid);
4d051c1eda 2007-08-29       drh:   @     if( w!=null ){
4d03017923 2007-08-30       drh:   @       w.style.color = "#000000";
4d051c1eda 2007-08-29       drh:   @     }
4d051c1eda 2007-08-29       drh:   @   }
4d051c1eda 2007-08-29       drh:   @   for(var x in childof[id]){
4d051c1eda 2007-08-29       drh:   @     var cid = childof[id][x]
4d051c1eda 2007-08-29       drh:   @     var w = document.getElementById(cid);
4d051c1eda 2007-08-29       drh:   @     if( w!=null ){
4d03017923 2007-08-30       drh:   @       w.style.color = "#000000";
4d051c1eda 2007-08-29       drh:   @     }
4d051c1eda 2007-08-29       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
bbdd4f9915 2007-08-27       drh:   @ function xout(id) {
4d03017923 2007-08-30       drh:   @   /* setall("#000000"); */
bbdd4f9915 2007-08-27       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ function set_parents(id, clr){
5341655085 2007-08-27       drh:   @   var plist = parentof[id];
5341655085 2007-08-27       drh:   @   if( plist==null ) return;
5341655085 2007-08-27       drh:   @   for(var x in plist){
5341655085 2007-08-27       drh:   @     var pid = plist[x];
4d051c1eda 2007-08-29       drh:   @     if( setone(pid,clr)==1 ){
4d051c1eda 2007-08-29       drh:   @       set_parents(pid,clr);
5341655085 2007-08-27       drh:   @     }
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ function set_children(id,clr){
5341655085 2007-08-27       drh:   @   var clist = childof[id];
5341655085 2007-08-27       drh:   @   if( clist==null ) return;
5341655085 2007-08-27       drh:   @   for(var x in clist){
5341655085 2007-08-27       drh:   @     var cid = clist[x];
4d051c1eda 2007-08-29       drh:   @     if( setone(cid,clr)==1 ){
4d051c1eda 2007-08-29       drh:   @       set_children(cid,clr);
5341655085 2007-08-27       drh:   @     }
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ </script>
dbda8d6ce9 2007-07-21       drh:   style_footer();
dbda8d6ce9 2007-07-21       drh: }
3945057916 2007-08-01       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The input query q selects various records.  Print a human-readable
dbda8d6ce9 2007-07-21       drh: ** summary of those records.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Limit the number of entries printed to nLine.
9395aba4f4 2007-09-22       drh: **
9395aba4f4 2007-09-22       drh: ** The query should return these columns:
9395aba4f4 2007-09-22       drh: **
9395aba4f4 2007-09-22       drh: **    0.  rid
9395aba4f4 2007-09-22       drh: **    1.  uuid
9395aba4f4 2007-09-22       drh: **    2.  Date/Time
9395aba4f4 2007-09-22       drh: **    3.  Comment string and user
9395aba4f4 2007-09-22       drh: **    4.  Number of non-merge children
9395aba4f4 2007-09-22       drh: **    5.  Number of parents
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void print_timeline(Stmt *q, int mxLine){
dbda8d6ce9 2007-07-21       drh:   int nLine = 0;
dbda8d6ce9 2007-07-21       drh:   char zPrevDate[20];
097479f99a 2007-09-26       drh:   const char *zCurrentUuid=0;
dbda8d6ce9 2007-07-21       drh:   zPrevDate[0] = 0;
dbda8d6ce9 2007-07-21       drh: 
c1e85e4da5 2008-07-13       drh:   if( g.localOpen ){
c1e85e4da5 2008-07-13       drh:     int rid = db_lget_int("checkout", 0);
c1e85e4da5 2008-07-13       drh:     zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
2db88ec639 2007-09-25       jnc:   }
b846db063c 2007-08-25       drh: 
dbda8d6ce9 2007-07-21       drh:   while( db_step(q)==SQLITE_ROW && nLine<=mxLine ){
b846db063c 2007-08-25       drh:     const char *zId = db_column_text(q, 1);
b846db063c 2007-08-25       drh:     const char *zDate = db_column_text(q, 2);
b846db063c 2007-08-25       drh:     const char *zCom = db_column_text(q, 3);
b846db063c 2007-08-25       drh:     int nChild = db_column_int(q, 4);
b846db063c 2007-08-25       drh:     int nParent = db_column_int(q, 5);
b846db063c 2007-08-25       drh:     char *zFree = 0;
097479f99a 2007-09-26       drh:     int n = 0;
097479f99a 2007-09-26       drh:     char zPrefix[80];
dbda8d6ce9 2007-07-21       drh:     char zUuid[UUID_SIZE+1];
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     sprintf(zUuid, "%.10s", zId);
dbda8d6ce9 2007-07-21       drh:     if( memcmp(zDate, zPrevDate, 10) ){
dbda8d6ce9 2007-07-21       drh:       printf("=== %.10s ===\n", zDate);
dbda8d6ce9 2007-07-21       drh:       memcpy(zPrevDate, zDate, 10);
dbda8d6ce9 2007-07-21       drh:       nLine++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( zCom==0 ) zCom = "";
fcabd4774c 2007-09-13       drh:     printf("%.8s ", &zDate[11]);
097479f99a 2007-09-26       drh:     zPrefix[0] = 0;
097479f99a 2007-09-26       drh:     if( nParent>1 ){
097479f99a 2007-09-26       drh:       sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* ");
097479f99a 2007-09-26       drh:       n = strlen(zPrefix);
097479f99a 2007-09-26       drh:     }
097479f99a 2007-09-26       drh:     if( nChild>1 ){
097479f99a 2007-09-26       drh:       sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*FORK* ");
097479f99a 2007-09-26       drh:       n = strlen(zPrefix);
097479f99a 2007-09-26       drh:     }
c1e85e4da5 2008-07-13       drh:     if( zCurrentUuid && strcmp(zCurrentUuid,zId)==0 ){
097479f99a 2007-09-26       drh:       sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*CURRENT* ");
097479f99a 2007-09-26       drh:       n += strlen(zPrefix);
b846db063c 2007-08-25       drh:     }
097479f99a 2007-09-26       drh:     zFree = sqlite3_mprintf("[%.10s] %s%s", zUuid, zPrefix, zCom);
fcabd4774c 2007-09-13       drh:     nLine += comment_print(zFree, 9, 79);
b846db063c 2007-08-25       drh:     sqlite3_free(zFree);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
9395aba4f4 2007-09-22       drh: /*
9395aba4f4 2007-09-22       drh: ** Return a pointer to a static string that forms the basis for
9395aba4f4 2007-09-22       drh: ** a timeline query for display on a TTY.
9395aba4f4 2007-09-22       drh: */
9395aba4f4 2007-09-22       drh: const char *timeline_query_for_tty(void){
9395aba4f4 2007-09-22       drh:   static const char zBaseSql[] =
9395aba4f4 2007-09-22       drh:     @ SELECT
9395aba4f4 2007-09-22       drh:     @   blob.rid,
9395aba4f4 2007-09-22       drh:     @   uuid,
9395aba4f4 2007-09-22       drh:     @   datetime(event.mtime,'localtime'),
6d58613757 2007-10-06       drh:     @   coalesce(ecomment,comment) || ' (by ' || coalesce(euser,user,'?') ||')',
9395aba4f4 2007-09-22       drh:     @   (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim),
9395aba4f4 2007-09-22       drh:     @   (SELECT count(*) FROM plink WHERE cid=blob.rid)
9395aba4f4 2007-09-22       drh:     @ FROM event, blob
9395aba4f4 2007-09-22       drh:     @ WHERE blob.rid=event.objid
9395aba4f4 2007-09-22       drh:   ;
9395aba4f4 2007-09-22       drh:   return zBaseSql;
9395aba4f4 2007-09-22       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: timeline
dbda8d6ce9 2007-07-21       drh: **
e8c4f69c50 2008-10-24       drh: ** Usage: %fossil timeline ?WHEN? ?BASELINE|DATETIME? ?-n|--count N?
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: ** Print a summary of activity going backwards in date and time
6607844a01 2007-08-18       drh: ** specified or from the current date and time if no arguments
abce5105e2 2007-09-01       drh: ** are given.  Show as many as N (default 20) check-ins.  The
abce5105e2 2007-09-01       drh: ** WHEN argument can be any unique abbreviation of one of these
abce5105e2 2007-09-01       drh: ** keywords:
abce5105e2 2007-09-01       drh: **
abce5105e2 2007-09-01       drh: **     before
abce5105e2 2007-09-01       drh: **     after
6458f020fc 2008-05-14       drh: **     descendants | children
abce5105e2 2007-09-01       drh: **     ancestors | parents
6607844a01 2007-08-18       drh: **
e8c4f69c50 2008-10-24       drh: ** The BASELINE can be any unique prefix of 4 characters or more.
abce5105e2 2007-09-01       drh: ** The DATETIME should be in the ISO8601 format.  For
abce5105e2 2007-09-01       drh: ** examples: "2007-08-18 07:21:21".  You can also say "current"
abce5105e2 2007-09-01       drh: ** for the current version or "now" for the current time.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void timeline_cmd(void){
dbda8d6ce9 2007-07-21       drh:   Stmt q;
abce5105e2 2007-09-01       drh:   int n, k;
b846db063c 2007-08-25       drh:   const char *zCount;
abce5105e2 2007-09-01       drh:   char *zOrigin;
6607844a01 2007-08-18       drh:   char *zDate;
abce5105e2 2007-09-01       drh:   char *zSQL;
abce5105e2 2007-09-01       drh:   int objid = 0;
abce5105e2 2007-09-01       drh:   Blob uuid;
abce5105e2 2007-09-01       drh:   int mode = 1 ;       /* 1: before  2:after  3:children  4:parents */
4e683ef07b 2008-05-05       drh:   db_find_and_open_repository(1);
6607844a01 2007-08-18       drh:   zCount = find_option("n","count",1);
6607844a01 2007-08-18       drh:   if( zCount ){
6607844a01 2007-08-18       drh:     n = atoi(zCount);
6607844a01 2007-08-18       drh:   }else{
6607844a01 2007-08-18       drh:     n = 20;
6607844a01 2007-08-18       drh:   }
abce5105e2 2007-09-01       drh:   if( g.argc==4 ){
abce5105e2 2007-09-01       drh:     k = strlen(g.argv[2]);
abce5105e2 2007-09-01       drh:     if( strncmp(g.argv[2],"before",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 1;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){
abce5105e2 2007-09-01       drh:       mode = 2;
6458f020fc 2008-05-14       drh:     }else if( strncmp(g.argv[2],"descendants",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 3;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"children",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 3;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){
abce5105e2 2007-09-01       drh:       mode = 4;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"parents",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 4;
abce5105e2 2007-09-01       drh:     }else{
e8c4f69c50 2008-10-24       drh:       usage("?WHEN? ?BASELINE|DATETIME?");
abce5105e2 2007-09-01       drh:     }
abce5105e2 2007-09-01       drh:     zOrigin = g.argv[3];
abce5105e2 2007-09-01       drh:   }else if( g.argc==3 ){
abce5105e2 2007-09-01       drh:     zOrigin = g.argv[2];
abce5105e2 2007-09-01       drh:   }else{
abce5105e2 2007-09-01       drh:     zOrigin = "now";
6607844a01 2007-08-18       drh:   }
abce5105e2 2007-09-01       drh:   k = strlen(zOrigin);
abce5105e2 2007-09-01       drh:   blob_zero(&uuid);
abce5105e2 2007-09-01       drh:   blob_append(&uuid, zOrigin, -1);
abce5105e2 2007-09-01       drh:   if( strcmp(zOrigin, "now")==0 ){
abce5105e2 2007-09-01       drh:     if( mode==3 || mode==4 ){
6458f020fc 2008-05-14       drh:       fossil_fatal("cannot compute descendants or ancestors of a date");
abce5105e2 2007-09-01       drh:     }
aad573b31c 2007-09-24  mjanssen:     zDate = mprintf("(SELECT datetime('now'))");
abce5105e2 2007-09-01       drh:   }else if( strncmp(zOrigin, "current", k)==0 ){
c1e85e4da5 2008-07-13       drh:     if( !g.localOpen ){
c1e85e4da5 2008-07-13       drh:       fossil_fatal("must be within a local checkout to use 'current'");
c1e85e4da5 2008-07-13       drh:     }
abce5105e2 2007-09-01       drh:     objid = db_lget_int("checkout",0);
abce5105e2 2007-09-01       drh:     zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid);
abce5105e2 2007-09-01       drh:   }else if( name_to_uuid(&uuid, 0)==0 ){
abce5105e2 2007-09-01       drh:     objid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid);
abce5105e2 2007-09-01       drh:     zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid);
6607844a01 2007-08-18       drh:   }else{
abce5105e2 2007-09-01       drh:     if( mode==3 || mode==4 ){
6458f020fc 2008-05-14       drh:       fossil_fatal("cannot compute descendants or ancestors of a date");
abce5105e2 2007-09-01       drh:     }
abce5105e2 2007-09-01       drh:     zDate = mprintf("(SELECT julianday(%Q, 'utc'))", zOrigin);
6607844a01 2007-08-18       drh:   }
9395aba4f4 2007-09-22       drh:   zSQL = mprintf("%s AND event.mtime %s %s",
9395aba4f4 2007-09-22       drh:      timeline_query_for_tty(),
9395aba4f4 2007-09-22       drh:      (mode==1 || mode==4) ? "<=" : ">=",
9395aba4f4 2007-09-22       drh:      zDate
dbda8d6ce9 2007-07-21       drh:   );
abce5105e2 2007-09-01       drh:   if( mode==3 || mode==4 ){
abce5105e2 2007-09-01       drh:     db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
abce5105e2 2007-09-01       drh:     if( mode==3 ){
6458f020fc 2008-05-14       drh:       compute_descendants(objid, n);
abce5105e2 2007-09-01       drh:     }else{
abce5105e2 2007-09-01       drh:       compute_ancestors(objid, n);
abce5105e2 2007-09-01       drh:     }
abce5105e2 2007-09-01       drh:     zSQL = mprintf("%z AND blob.rid IN ok", zSQL);
abce5105e2 2007-09-01       drh:   }
abce5105e2 2007-09-01       drh:   zSQL = mprintf("%z ORDER BY event.mtime DESC", zSQL);
abce5105e2 2007-09-01       drh:   db_prepare(&q, zSQL);
6607844a01 2007-08-18       drh:   print_timeline(&q, n);
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh: }