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(
bbdd4f9915 2007-08-27       drh:   Stmt *pQuery,
e15fe43153 2007-08-31       drh:   int *pFirstEvent,
e15fe43153 2007-08-31       drh:   int *pLastEvent,
bbdd4f9915 2007-08-27       drh:   int (*xCallback)(int, Blob*),
bbdd4f9915 2007-08-27       drh:   Blob *pArg
bbdd4f9915 2007-08-27       drh:  ){
9a76119307 2007-09-10       drh:   int cnt = 0;
ebb2765954 2007-12-04       drh:   int wikiFlags;
ebb2765954 2007-12-04       drh:   int mxWikiLen;
6d58613757 2007-10-06       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);
e15fe43153 2007-08-31       drh:     if( cnt==0 && pFirstEvent ){
e15fe43153 2007-08-31       drh:       *pFirstEvent = rid;
e15fe43153 2007-08-31       drh:     }
20553a420c 2007-12-03       drh:     cnt++;
e15fe43153 2007-08-31       drh:     if( pLastEvent ){
e15fe43153 2007-08-31       drh:       *pLastEvent = rid;
e15fe43153 2007-08-31       drh:     }
e15fe43153 2007-08-31       drh:     db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
bbdd4f9915 2007-08-27       drh:     if( xCallback ){
bbdd4f9915 2007-08-27       drh:       xCallback(rid, pArg);
bbdd4f9915 2007-08-27       drh:     }
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: 
b846db063c 2007-08-25       drh: /*
bbdd4f9915 2007-08-27       drh: ** Generate javascript code that records the parents and children
bbdd4f9915 2007-08-27       drh: ** of the version rid.
b846db063c 2007-08-25       drh: */
bbdd4f9915 2007-08-27       drh: static int save_parentage_javascript(int rid, Blob *pOut){
bbdd4f9915 2007-08-27       drh:   const char *zSep;
b846db063c 2007-08-25       drh:   Stmt q;
bbdd4f9915 2007-08-27       drh: 
5341655085 2007-08-27       drh:   db_prepare(&q, "SELECT pid FROM plink WHERE cid=%d", rid);
bbdd4f9915 2007-08-27       drh:   zSep = "";
a028affcf2 2007-08-27       drh:   blob_appendf(pOut, "parentof[\"m%d\"] = [", rid);
bbdd4f9915 2007-08-27       drh:   while( db_step(&q)==SQLITE_ROW ){
bbdd4f9915 2007-08-27       drh:     int pid = db_column_int(&q, 0);
bbdd4f9915 2007-08-27       drh:     blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
bbdd4f9915 2007-08-27       drh:     zSep = ",";
bbdd4f9915 2007-08-27       drh:   }
bbdd4f9915 2007-08-27       drh:   db_finalize(&q);
bbdd4f9915 2007-08-27       drh:   blob_appendf(pOut, "];\n");
5341655085 2007-08-27       drh:   db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d", rid);
bbdd4f9915 2007-08-27       drh:   zSep = "";
a028affcf2 2007-08-27       drh:   blob_appendf(pOut, "childof[\"m%d\"] = [", rid);
bbdd4f9915 2007-08-27       drh:   while( db_step(&q)==SQLITE_ROW ){
bbdd4f9915 2007-08-27       drh:     int pid = db_column_int(&q, 0);
bbdd4f9915 2007-08-27       drh:     blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
bbdd4f9915 2007-08-27       drh:     zSep = ",";
bbdd4f9915 2007-08-27       drh:   }
bbdd4f9915 2007-08-27       drh:   db_finalize(&q);
bbdd4f9915 2007-08-27       drh:   blob_appendf(pOut, "];\n");
bbdd4f9915 2007-08-27       drh:   return 0;
bbdd4f9915 2007-08-27       drh: }
bbdd4f9915 2007-08-27       drh: 
bbdd4f9915 2007-08-27       drh: /*
e6aa161204 2008-02-26       drh: ** Create a temporary table suitable for storing timeline data.
e6aa161204 2008-02-26       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);
e6aa161204 2008-02-26       drh: }
e6aa161204 2008-02-26       drh: 
e6aa161204 2008-02-26       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.
9395aba4f4 2007-09-22       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;
9395aba4f4 2007-09-22       drh: }
9395aba4f4 2007-09-22       drh: 
9395aba4f4 2007-09-22       drh: /*
e6aa161204 2008-02-26       drh: ** WEBPAGE: ntimeline
e6aa161204 2008-02-26       drh: **
e6aa161204 2008-02-26       drh: ** Query parameters:
e6aa161204 2008-02-26       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
e6aa161204 2008-02-26       drh: **    d=RID          artifact RID and up to COUNT descendents
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.
bbdd4f9915 2007-08-27       drh: */
e6aa161204 2008-02-26       drh: void page_ntimeline(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 */
e6aa161204 2008-02-26       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 */
e6aa161204 2008-02-26       drh:   int d_rid = atoi(PD("d","0"));     /* artifact d and its descendents */
e6aa161204 2008-02-26       drh:   const char *zUser = P("u");        /* All entries by this user if not NULL */
e6aa161204 2008-02-26       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 */
e6aa161204 2008-02-26       drh:   Blob scriptInit;
b846db063c 2007-08-25       drh: 
b846db063c 2007-08-25       drh:   /* To view the timeline, must have permission to read project data.
b846db063c 2007-08-25       drh:   */
b846db063c 2007-08-25       drh:   login_check_credentials();
b846db063c 2007-08-25       drh:   if( !g.okRead ){ login_needed(); return; }
b846db063c 2007-08-25       drh: 
b846db063c 2007-08-25       drh:   style_header("Timeline");
b846db063c 2007-08-25       drh:   if( !g.okHistory &&
b846db063c 2007-08-25       drh:       db_exists("SELECT 1 FROM user"
b846db063c 2007-08-25       drh:                 " WHERE login='anonymous'"
b846db063c 2007-08-25       drh:                 "   AND cap LIKE '%%h%%'") ){
b846db063c 2007-08-25       drh:     @ <p><b>Note:</b> You will be able to access <u>much</u> more
e6aa161204 2008-02-26       drh:     @ historical information if you <a href="%s(g.zTop)/login">login</a>.</p>
e6aa161204 2008-02-26       drh:   }
e6aa161204 2008-02-26       drh:   timeline_temp_table();
e6aa161204 2008-02-26       drh:   blob_zero(&sql);
e6aa161204 2008-02-26       drh:   blob_zero(&desc);
e6aa161204 2008-02-26       drh:   blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
e6aa161204 2008-02-26       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= */
e6aa161204 2008-02-26       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;
e6aa161204 2008-02-26       drh:     db_multi_exec(
e6aa161204 2008-02-26       drh:        "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
e6aa161204 2008-02-26       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 ){
e6aa161204 2008-02-26       drh:       compute_descendents(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));
e6aa161204 2008-02-26       drh:         blob_appendf(&desc, "%d descendents", 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:     }
e6aa161204 2008-02-26       drh:     blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
e6aa161204 2008-02-26       drh:                  g.zBaseURL, zUuid, zUuid);
e6aa161204 2008-02-26       drh:     db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
e6aa161204 2008-02-26       drh:   }else{
e6aa161204 2008-02-26       drh:     const char *zEType = "event";
e6aa161204 2008-02-26       drh:     if( zType ){
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " AND event.type=%Q", 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:     blob_appendf(&desc, "Timeline of up to %d %s", nEntry, zEType);
e6aa161204 2008-02-26       drh:     if( zUser ){
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " AND event.user=%Q", zUser);
e6aa161204 2008-02-26       drh:       blob_appendf(&desc, " by user %h", 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:         blob_appendf(&desc, " occurring on or after %h", zAfter);
e6aa161204 2008-02-26       drh:         zBefore = 0;
5341655085 2007-08-27       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);
e6aa161204 2008-02-26       drh:         blob_appendf(&desc, " occurring on or before %h", zBefore);
b846db063c 2007-08-25       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));
e6aa161204 2008-02-26       drh:   }
e6aa161204 2008-02-26       drh:   blob_zero(&sql);
e6aa161204 2008-02-26       drh:   db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
e6aa161204 2008-02-26       drh:   @ <h2>%b(&desc)</h2>
e6aa161204 2008-02-26       drh:   blob_reset(&desc);
e6aa161204 2008-02-26       drh:   blob_zero(&scriptInit);
e6aa161204 2008-02-26       drh:   www_print_timeline(&q, 0, 0, save_parentage_javascript, &scriptInit);
e6aa161204 2008-02-26       drh:   db_finalize(&q);
e6aa161204 2008-02-26       drh:   @ <script>
e6aa161204 2008-02-26       drh:   @ var parentof = new Object();
e6aa161204 2008-02-26       drh:   @ var childof = new Object();
e6aa161204 2008-02-26       drh:   cgi_append_content(blob_buffer(&scriptInit), blob_size(&scriptInit));
e6aa161204 2008-02-26       drh:   blob_reset(&scriptInit);
e6aa161204 2008-02-26       drh:   @ function setall(value){
e6aa161204 2008-02-26       drh:   @   for(var x in parentof){
e6aa161204 2008-02-26       drh:   @     setone(x,value);
e6aa161204 2008-02-26       drh:   @   }
e6aa161204 2008-02-26       drh:   @ }
e6aa161204 2008-02-26       drh:   @ setall("#ffffff");
e6aa161204 2008-02-26       drh:   @ function setone(id, clr){
e6aa161204 2008-02-26       drh:   @   if( parentof[id]==null ) return 0;
e6aa161204 2008-02-26       drh:   @   var w = document.getElementById(id);
e6aa161204 2008-02-26       drh:   @   if( w.style.color==clr ){
e6aa161204 2008-02-26       drh:   @     return 0
e6aa161204 2008-02-26       drh:   @   }else{
e6aa161204 2008-02-26       drh:   @     w.style.color = clr
e6aa161204 2008-02-26       drh:   @     return 1
e6aa161204 2008-02-26       drh:   @   }
e6aa161204 2008-02-26       drh:   @ }
e6aa161204 2008-02-26       drh:   @ function xin(id) {
e6aa161204 2008-02-26       drh:   @   setall("#ffffff");
e6aa161204 2008-02-26       drh:   @   setone(id,"#ff0000");
e6aa161204 2008-02-26       drh:   @   set_children(id, "#b0b0b0");
e6aa161204 2008-02-26       drh:   @   set_parents(id, "#b0b0b0");
e6aa161204 2008-02-26       drh:   @   for(var x in parentof[id]){
e6aa161204 2008-02-26       drh:   @     var pid = parentof[id][x]
e6aa161204 2008-02-26       drh:   @     var w = document.getElementById(pid);
e6aa161204 2008-02-26       drh:   @     if( w!=null ){
e6aa161204 2008-02-26       drh:   @       w.style.color = "#000000";
e6aa161204 2008-02-26       drh:   @     }
e6aa161204 2008-02-26       drh:   @   }
e6aa161204 2008-02-26       drh:   @   for(var x in childof[id]){
e6aa161204 2008-02-26       drh:   @     var cid = childof[id][x]
e6aa161204 2008-02-26       drh:   @     var w = document.getElementById(cid);
e6aa161204 2008-02-26       drh:   @     if( w!=null ){
e6aa161204 2008-02-26       drh:   @       w.style.color = "#000000";
e6aa161204 2008-02-26       drh:   @     }
e6aa161204 2008-02-26       drh:   @   }
e6aa161204 2008-02-26       drh:   @ }
e6aa161204 2008-02-26       drh:   @ function xout(id) {
e6aa161204 2008-02-26       drh:   @   /* setall("#000000"); */
e6aa161204 2008-02-26       drh:   @ }
e6aa161204 2008-02-26       drh:   @ function set_parents(id, clr){
e6aa161204 2008-02-26       drh:   @   var plist = parentof[id];
e6aa161204 2008-02-26       drh:   @   if( plist==null ) return;
e6aa161204 2008-02-26       drh:   @   for(var x in plist){
e6aa161204 2008-02-26       drh:   @     var pid = plist[x];
e6aa161204 2008-02-26       drh:   @     if( setone(pid,clr)==1 ){
e6aa161204 2008-02-26       drh:   @       set_parents(pid,clr);
e6aa161204 2008-02-26       drh:   @     }
e6aa161204 2008-02-26       drh:   @   }
e6aa161204 2008-02-26       drh:   @ }
e6aa161204 2008-02-26       drh:   @ function set_children(id,clr){
e6aa161204 2008-02-26       drh:   @   var clist = childof[id];
e6aa161204 2008-02-26       drh:   @   if( clist==null ) return;
e6aa161204 2008-02-26       drh:   @   for(var x in clist){
e6aa161204 2008-02-26       drh:   @     var cid = clist[x];
e6aa161204 2008-02-26       drh:   @     if( setone(cid,clr)==1 ){
e6aa161204 2008-02-26       drh:   @       set_children(cid,clr);
e6aa161204 2008-02-26       drh:   @     }
e6aa161204 2008-02-26       drh:   @   }
e6aa161204 2008-02-26       drh:   @ }
e6aa161204 2008-02-26       drh:   @ </script>
e6aa161204 2008-02-26       drh:   style_footer();
e6aa161204 2008-02-26       drh: }
afcdc7ec97 2007-08-01       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: **
e15fe43153 2007-08-31       drh: **    d=STARTDATE    date in iso8601 notation.          dflt: newest event
e15fe43153 2007-08-31       drh: **    n=INTEGER      number of events to show.          dflt: 25
e15fe43153 2007-08-31       drh: **    e=INTEGER      starting event id.                 dflt: nil
e15fe43153 2007-08-31       drh: **    u=NAME         show only events from user.        dflt: nil
e15fe43153 2007-08-31       drh: **    a              show events after and including.   dflt: false
e15fe43153 2007-08-31       drh: **    r              show only related events.          dflt: false
50a58adb76 2007-10-10       drh: **    y=TYPE         show only TYPE ('ci' or 'w')       dflt: nil
20553a420c 2007-12-03       drh: **    s              show the SQL                       dflt: nil
afcdc7ec97 2007-08-01       drh: */
afcdc7ec97 2007-08-01       drh: void page_timeline(void){
afcdc7ec97 2007-08-01       drh:   Stmt q;
e38c89130f 2008-02-24       drh:   Blob sql;                    /* text of SQL used to generate timeline */
e38c89130f 2008-02-24       drh:   char *zSQL;                  /* Rendered copy of sql */
4d051c1eda 2007-08-29       drh:   Blob scriptInit;
3945057916 2007-08-01       drh:   char zDate[100];
e38c89130f 2008-02-24       drh:   const char *zStart = P("d");       /* Starting date */
e38c89130f 2008-02-24       drh:   int nEntry = atoi(PD("n","20"));   /* Max number of entries on timeline */
e38c89130f 2008-02-24       drh:   const char *zUser = P("u");        /* All entries by this user if not NULL */
e38c89130f 2008-02-24       drh:   int objid = atoi(PD("e","0"));     /* Entries related to this event */
e38c89130f 2008-02-24       drh:   int relatedEvents = P("r")!=0;     /* Must be directly related to of objid */
e38c89130f 2008-02-24       drh:   int afterFlag = P("a")!=0;         /* After objid if true */
e38c89130f 2008-02-24       drh:   const char *zType = P("y");        /* Type of events.  All if NULL */
e38c89130f 2008-02-24       drh:   int firstEvent;              /* First event displayed */
e38c89130f 2008-02-24       drh:   int lastEvent;               /* Last event displayed */
e38c89130f 2008-02-24       drh:   Blob desc;                   /* Human readable description of the timeline */
e38c89130f 2008-02-24       drh:   const char *zEType;          /* Human readable event type */
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");
3945057916 2007-08-01       drh:   if( !g.okHistory &&
3945057916 2007-08-01       drh:       db_exists("SELECT 1 FROM user"
3945057916 2007-08-01       drh:                 " WHERE login='anonymous'"
3945057916 2007-08-01       drh:                 "   AND cap LIKE '%%h%%'") ){
e319e8e870 2007-08-25       drh:     @ <p><b>Note:</b> You will be able to access <u>much</u> more
c1d9e0f4f8 2008-02-09       bch:     @ historical information if you <a href="%s(g.zTop)/login">login</a>.</p>
20553a420c 2007-12-03       drh:   }
20553a420c 2007-12-03       drh:   blob_zero(&sql);
e38c89130f 2008-02-24       drh:   blob_zero(&desc);
20553a420c 2007-12-03       drh:   blob_append(&sql, timeline_query_for_www(), -1);
e38c89130f 2008-02-24       drh:   zEType = "events";
50a58adb76 2007-10-10       drh:   if( zType ){
20553a420c 2007-12-03       drh:     blob_appendf(&sql, " AND event.type=%Q", zType);
e38c89130f 2008-02-24       drh:     if( zType[0]=='c' ){
e38c89130f 2008-02-24       drh:       zEType = "checkins";
e38c89130f 2008-02-24       drh:     }else if( zType[0]=='w' ){
e38c89130f 2008-02-24       drh:       zEType = "wiki edits";
e38c89130f 2008-02-24       drh:     }
e38c89130f 2008-02-24       drh:   }
e38c89130f 2008-02-24       drh:   blob_appendf(&desc, "Timeline of up to %d %s", nEntry, zEType);
e15fe43153 2007-08-31       drh:   if( zUser ){
20553a420c 2007-12-03       drh:     blob_appendf(&sql, " AND event.user=%Q", zUser);
e38c89130f 2008-02-24       drh:     blob_appendf(&desc, " by user %h", zUser);
e15fe43153 2007-08-31       drh:   }
e15fe43153 2007-08-31       drh:   if( objid ){
20553a420c 2007-12-03       drh:     char *z = db_text(0, "SELECT datetime(event.mtime, 'localtime') FROM event"
e15fe43153 2007-08-31       drh:                          " WHERE objid=%d", objid);
e15fe43153 2007-08-31       drh:     if( z ){
e15fe43153 2007-08-31       drh:       zStart = z;
e15fe43153 2007-08-31       drh:     }
e15fe43153 2007-08-31       drh:   }
3945057916 2007-08-01       drh:   if( zStart ){
3945057916 2007-08-01       drh:     while( isspace(zStart[0]) ){ zStart++; }
3945057916 2007-08-01       drh:     if( zStart[0] ){
20553a420c 2007-12-03       drh:       blob_appendf(&sql,
20553a420c 2007-12-03       drh:          " AND event.mtime %s (SELECT julianday(%Q, 'utc'))",
20553a420c 2007-12-03       drh:                           afterFlag ? ">=" : "<=", zStart);
e38c89130f 2008-02-24       drh:       blob_appendf(&desc, " occurring on or %s %h",
e38c89130f 2008-02-24       drh:           afterFlag ? "after": "before",
e38c89130f 2008-02-24       drh:           zStart);
abce5105e2 2007-09-01       drh:     }
abce5105e2 2007-09-01       drh:   }
abce5105e2 2007-09-01       drh:   if( relatedEvents && objid ){
e38c89130f 2008-02-24       drh:     char *zUuid;
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:     );
e38c89130f 2008-02-24       drh:     zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", objid);
abce5105e2 2007-09-01       drh:     if( afterFlag ){
abce5105e2 2007-09-01       drh:       compute_descendents(objid, nEntry);
e38c89130f 2008-02-24       drh:       blob_appendf(&desc,
e38c89130f 2008-02-24       drh:          " and decended from <a href='%s/vinfo/%d'>[%.10s]</a>",
e38c89130f 2008-02-24       drh:          g.zBaseURL, objid, zUuid);
abce5105e2 2007-09-01       drh:     }else{
abce5105e2 2007-09-01       drh:       compute_ancestors(objid, nEntry);
e38c89130f 2008-02-24       drh:       blob_appendf(&desc,
e38c89130f 2008-02-24       drh:          " and a ancestor of <a href='%s/vinfo/%d'>[%.10s]</a>",
e38c89130f 2008-02-24       drh:          g.zBaseURL, objid, zUuid);
3945057916 2007-08-01       drh:     }
20553a420c 2007-12-03       drh:     blob_append(&sql, " AND event.objid IN ok", -1);
20553a420c 2007-12-03       drh:   }
20553a420c 2007-12-03       drh:   if( afterFlag ){
20553a420c 2007-12-03       drh:     blob_appendf(&sql, " ORDER BY event.mtime ASC LIMIT %d",
20553a420c 2007-12-03       drh:                  nEntry);
20553a420c 2007-12-03       drh:   }else{
20553a420c 2007-12-03       drh:     blob_appendf(&sql, " ORDER BY event.mtime DESC LIMIT %d",
20553a420c 2007-12-03       drh:                  nEntry);
3945057916 2007-08-01       drh:   }
20553a420c 2007-12-03       drh:   zSQL = blob_str(&sql);
20553a420c 2007-12-03       drh:   if( afterFlag ){
20553a420c 2007-12-03       drh:     zSQL = mprintf("SELECT * FROM (%s) ORDER BY timestamp DESC", zSQL);
20553a420c 2007-12-03       drh:   }
3945057916 2007-08-01       drh:   db_prepare(&q, zSQL);
20553a420c 2007-12-03       drh:   if( P("s")!=0 ){
20553a420c 2007-12-03       drh:     @ <hr><p>%h(zSQL)</p><hr>
20553a420c 2007-12-03       drh:   }
e38c89130f 2008-02-24       drh:   @ <h2>%b(&desc)</h2>
e38c89130f 2008-02-24       drh:   blob_reset(&desc);
20553a420c 2007-12-03       drh:   blob_zero(&sql);
20553a420c 2007-12-03       drh:   if( afterFlag ){
20553a420c 2007-12-03       drh:     free(zSQL);
20553a420c 2007-12-03       drh:   }
4d051c1eda 2007-08-29       drh:   zDate[0] = 0;
4d051c1eda 2007-08-29       drh:   blob_zero(&scriptInit);
f5e8b1d736 2007-08-04       drh:   zDate[0] = 0;
e15fe43153 2007-08-31       drh:   www_print_timeline(&q, &firstEvent, &lastEvent,
e15fe43153 2007-08-31       drh:                      save_parentage_javascript, &scriptInit);
afcdc7ec97 2007-08-01       drh:   db_finalize(&q);
e487b77b1a 2008-02-04       drh:   /* @ <p>firstEvent=%d(firstEvent) lastEvent=%d(lastEvent)</p> */
3945057916 2007-08-01       drh:   if( zStart==0 ){
3945057916 2007-08-01       drh:     zStart = zDate;
3945057916 2007-08-01       drh:   }
4d051c1eda 2007-08-29       drh:   @ <script>
4d051c1eda 2007-08-29       drh:   @ var parentof = new Object();
4d051c1eda 2007-08-29       drh:   @ var childof = new Object();
4d051c1eda 2007-08-29       drh:   cgi_append_content(blob_buffer(&scriptInit), blob_size(&scriptInit));
4d051c1eda 2007-08-29       drh:   blob_reset(&scriptInit);
4d051c1eda 2007-08-29       drh:   @ function setall(value){
4d051c1eda 2007-08-29       drh:   @   for(var x in parentof){
4d051c1eda 2007-08-29       drh:   @     setone(x,value);
4d051c1eda 2007-08-29       drh:   @   }
4d051c1eda 2007-08-29       drh:   @ }
4d03017923 2007-08-30       drh:   @ setall("#ffffff");
4d051c1eda 2007-08-29       drh:   @ function setone(id, clr){
4d051c1eda 2007-08-29       drh:   @   if( parentof[id]==null ) return 0;
4d051c1eda 2007-08-29       drh:   @   var w = document.getElementById(id);
4d051c1eda 2007-08-29       drh:   @   if( w.style.color==clr ){
4d051c1eda 2007-08-29       drh:   @     return 0
4d051c1eda 2007-08-29       drh:   @   }else{
4d051c1eda 2007-08-29       drh:   @     w.style.color = clr
4d051c1eda 2007-08-29       drh:   @     return 1
4d051c1eda 2007-08-29       drh:   @   }
4d051c1eda 2007-08-29       drh:   @ }
4d051c1eda 2007-08-29       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:   @   }
4d051c1eda 2007-08-29       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ function xout(id) {
4d03017923 2007-08-30       drh:   @   /* setall("#000000"); */
4d051c1eda 2007-08-29       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ function set_parents(id, clr){
4d051c1eda 2007-08-29       drh:   @   var plist = parentof[id];
4d051c1eda 2007-08-29       drh:   @   if( plist==null ) return;
4d051c1eda 2007-08-29       drh:   @   for(var x in plist){
4d051c1eda 2007-08-29       drh:   @     var pid = plist[x];
4d051c1eda 2007-08-29       drh:   @     if( setone(pid,clr)==1 ){
4d051c1eda 2007-08-29       drh:   @       set_parents(pid,clr);
4d051c1eda 2007-08-29       drh:   @     }
4d051c1eda 2007-08-29       drh:   @   }
4d051c1eda 2007-08-29       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ function set_children(id,clr){
4d051c1eda 2007-08-29       drh:   @   var clist = childof[id];
4d051c1eda 2007-08-29       drh:   @   if( clist==null ) return;
4d051c1eda 2007-08-29       drh:   @   for(var x in clist){
4d051c1eda 2007-08-29       drh:   @     var cid = clist[x];
4d051c1eda 2007-08-29       drh:   @     if( setone(cid,clr)==1 ){
4d051c1eda 2007-08-29       drh:   @       set_children(cid,clr);
4d051c1eda 2007-08-29       drh:   @     }
4d051c1eda 2007-08-29       drh:   @   }
4d051c1eda 2007-08-29       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ </script>
3945057916 2007-08-01       drh:   @ <hr>
3945057916 2007-08-01       drh:   @ <form method="GET" action="%s(g.zBaseURL)/timeline">
3945057916 2007-08-01       drh:   @ Start Date:
3945057916 2007-08-01       drh:   @ <input type="text" size="30" value="%h(zStart)" name="d">
3945057916 2007-08-01       drh:   @ Number Of Entries:
3945057916 2007-08-01       drh:   @ <input type="text" size="4" value="%d(nEntry)" name="n">
3945057916 2007-08-01       drh:   @ <br><input type="submit" value="Submit">
3945057916 2007-08-01       drh:   @ </form>
20553a420c 2007-12-03       drh:   @ <table><tr><td>
3945057916 2007-08-01       drh:   @ <form method="GET" action="%s(g.zBaseURL)/timeline">
ff4cc5fae2 2007-09-23       drh:   @ <input type="hidden" value="%d(lastEvent)" name="e">
3945057916 2007-08-01       drh:   @ <input type="hidden" value="%d(nEntry)" name="n">
3945057916 2007-08-01       drh:   @ <input type="submit" value="Next %d(nEntry) Rows">
20553a420c 2007-12-03       drh:   @ </form></td><td>
ff4cc5fae2 2007-09-23       drh:   @ <form method="GET" action="%s(g.zBaseURL)/timeline">
ff4cc5fae2 2007-09-23       drh:   @ <input type="hidden" value="%d(firstEvent)" name="e">
ff4cc5fae2 2007-09-23       drh:   @ <input type="hidden" value="%d(nEntry)" name="n">
20553a420c 2007-12-03       drh:   @ <input type="hidden" value="1" name="a">
ff4cc5fae2 2007-09-23       drh:   @ <input type="submit" value="Previous %d(nEntry) Rows">
20553a420c 2007-12-03       drh:   @ </form></td></tr></table>
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];
e63a9fd9d0 2007-09-25       jnc:   const char *zCurrentUuid=0;
2db88ec639 2007-09-25       jnc:   Stmt currentQ;
2db88ec639 2007-09-25       jnc:   int rid = db_lget_int("checkout", 0);
dbda8d6ce9 2007-07-21       drh:   zPrevDate[0] = 0;
dbda8d6ce9 2007-07-21       drh: 
2db88ec639 2007-09-25       jnc:   db_prepare(&currentQ,
2db88ec639 2007-09-25       jnc:     "SELECT uuid"
2db88ec639 2007-09-25       jnc:     "  FROM blob WHERE rid=%d", rid
2db88ec639 2007-09-25       jnc:   );
2db88ec639 2007-09-25       jnc:   if( db_step(&currentQ)==SQLITE_ROW ){
2db88ec639 2007-09-25       jnc:     zCurrentUuid = db_column_text(&currentQ, 0);
2db88ec639 2007-09-25       jnc:   }
4d051c1eda 2007-08-29       drh: 
dbda8d6ce9 2007-07-21       drh:   while( db_step(q)==SQLITE_ROW && nLine<=mxLine ){
4d051c1eda 2007-08-29       drh:     const char *zId = db_column_text(q, 1);
4d051c1eda 2007-08-29       drh:     const char *zDate = db_column_text(q, 2);
4d051c1eda 2007-08-29       drh:     const char *zCom = db_column_text(q, 3);
4d051c1eda 2007-08-29       drh:     int nChild = db_column_int(q, 4);
4d051c1eda 2007-08-29       drh:     int nParent = db_column_int(q, 5);
4d051c1eda 2007-08-29       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:     }
097479f99a 2007-09-26       drh:     if( 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:   }
2db88ec639 2007-09-25       jnc:   db_finalize(&currentQ);
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: **
abce5105e2 2007-09-01       drh: ** Usage: %fossil timeline ?WHEN? ?UUID|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
abce5105e2 2007-09-01       drh: **     descendents | children
abce5105e2 2007-09-01       drh: **     ancestors | parents
6607844a01 2007-08-18       drh: **
abce5105e2 2007-09-01       drh: ** The UUID 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 */
6607844a01 2007-08-18       drh:   db_find_and_open_repository();
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;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"descendents",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{
abce5105e2 2007-09-01       drh:       usage("?WHEN? ?UUID|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 ){
abce5105e2 2007-09-01       drh:       fossil_fatal("cannot compute descendents 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 ){
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 ){
abce5105e2 2007-09-01       drh:       fossil_fatal("cannot compute descendents 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 ){
abce5105e2 2007-09-01       drh:       compute_descendents(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: }