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: */
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 ){
fd36718ad9 2007-07-31       drh:     @ <a href="%s(g.zBaseURL)/vinfo/%s(zUuid)">[%s(zShortUuid)]</a>
fd36718ad9 2007-07-31       drh:   }else{
fd36718ad9 2007-07-31       drh:     @ <b>[%s(zShortUuid)]</b>
fd36718ad9 2007-07-31       drh:   }
fd36718ad9 2007-07-31       drh: }
fd36718ad9 2007-07-31       drh: 
fd36718ad9 2007-07-31       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>
bbdd4f9915 2007-08-27       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
afcdc7ec97 2007-08-01       drh: ** should return 4 columns:
afcdc7ec97 2007-08-01       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
dbda8d6ce9 2007-07-21       drh: */
bbdd4f9915 2007-08-27       drh: void www_print_timeline(
bbdd4f9915 2007-08-27       drh:   Stmt *pQuery,
bbdd4f9915 2007-08-27       drh:   char *zLastDate,
bbdd4f9915 2007-08-27       drh:   int (*xCallback)(int, Blob*),
bbdd4f9915 2007-08-27       drh:   Blob *pArg
bbdd4f9915 2007-08-27       drh:  ){
dbda8d6ce9 2007-07-21       drh:   char zPrevDate[20];
5ebcedc33e 2007-07-31       dan:   zPrevDate[0] = 0;
dbda8d6ce9 2007-07-21       drh:   @ <table cellspacing=0 border=0 cellpadding=0>
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);
bbdd4f9915 2007-08-27       drh:     const char *zDate = db_column_text(pQuery, 2);
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>
dbda8d6ce9 2007-07-21       drh:       @ <table cellpadding=2 border=0>
dbda8d6ce9 2007-07-21       drh:       @ <tr><td bgcolor="#a0b5f4" class="border1">
dbda8d6ce9 2007-07-21       drh:       @ <table cellpadding=2 cellspacing=0 border=0><tr>
dbda8d6ce9 2007-07-21       drh:       @ <td bgcolor="#d0d9f4" class="bkgnd1">%s(zPrevDate)</td>
dbda8d6ce9 2007-07-21       drh:       @ </tr></table>
dbda8d6ce9 2007-07-21       drh:       @ </td></tr></table>
dbda8d6ce9 2007-07-21       drh:       @ </td></tr>
dbda8d6ce9 2007-07-21       drh:     }
4d051c1eda 2007-08-29       drh:     @ <tr id="m%d(rid)">
bbdd4f9915 2007-08-27       drh:     @ <td valign="top">%s(&zDate[11])</td>
dbda8d6ce9 2007-07-21       drh:     @ <td width="20"></td>
dbda8d6ce9 2007-07-21       drh:     @ <td valign="top" align="left">
4d051c1eda 2007-08-29       drh:     hyperlink_to_uuid_with_mouseover(zUuid, "xin", "xout", rid);
bbdd4f9915 2007-08-27       drh:     if( nParent>1 ){
4d051c1eda 2007-08-29       drh:       @ <b>Merge</b>
bbdd4f9915 2007-08-27       drh:     }
bbdd4f9915 2007-08-27       drh:     if( nPChild>1 ){
4d051c1eda 2007-08-29       drh:       @ <b>Fork</b>
bbdd4f9915 2007-08-27       drh:     }
bbdd4f9915 2007-08-27       drh:     if( isLeaf ){
bbdd4f9915 2007-08-27       drh:       @ <b>Leaf</b>
bbdd4f9915 2007-08-27       drh:     }
4d051c1eda 2007-08-29       drh:     @ %h(db_column_text(pQuery,3))
bbdd4f9915 2007-08-27       drh:     @ (by %h(db_column_text(pQuery,4)))</td></tr>
3945057916 2007-08-01       drh:     if( zLastDate ){
3945057916 2007-08-01       drh:       strcpy(zLastDate, zDate);
3945057916 2007-08-01       drh:     }
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: /*
bbdd4f9915 2007-08-27       drh: ** Generate javascript code that records the parents and children
bbdd4f9915 2007-08-27       drh: ** of the version rid.
bbdd4f9915 2007-08-27       drh: */
bbdd4f9915 2007-08-27       drh: static int save_parentage_javascript(int rid, Blob *pOut){
bbdd4f9915 2007-08-27       drh:   const char *zSep;
bbdd4f9915 2007-08-27       drh:   Stmt q;
afcdc7ec97 2007-08-01       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: }
afcdc7ec97 2007-08-01       drh: 
afcdc7ec97 2007-08-01       drh: /*
afcdc7ec97 2007-08-01       drh: ** WEBPAGE: timeline
afcdc7ec97 2007-08-01       drh: */
afcdc7ec97 2007-08-01       drh: void page_timeline(void){
afcdc7ec97 2007-08-01       drh:   Stmt q;
3945057916 2007-08-01       drh:   char *zSQL;
bbdd4f9915 2007-08-27       drh:   Blob scriptInit;
3945057916 2007-08-01       drh:   char zDate[100];
3945057916 2007-08-01       drh:   const char *zStart = P("d");
3945057916 2007-08-01       drh:   int nEntry = atoi(PD("n","25"));
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
e319e8e870 2007-08-25       drh:     @ historical information if <a href="%s(g.zBaseURL)/login">login</a>.</p>
3945057916 2007-08-01       drh:   }
3945057916 2007-08-01       drh:   zSQL = mprintf(
bbdd4f9915 2007-08-27       drh:     "SELECT blob.rid, uuid, datetime(event.mtime,'localtime'), comment, user,"
bbdd4f9915 2007-08-27       drh:     "       (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim=1),"
bbdd4f9915 2007-08-27       drh:     "       (SELECT count(*) FROM plink WHERE cid=blob.rid),"
bbdd4f9915 2007-08-27       drh:     "       NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid)"
afcdc7ec97 2007-08-01       drh:     "  FROM event, blob"
afcdc7ec97 2007-08-01       drh:     " WHERE event.type='ci' AND blob.rid=event.objid"
afcdc7ec97 2007-08-01       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] ){
3945057916 2007-08-01       drh:       zSQL = mprintf("%z AND event.mtime<=julianday(%Q, 'localtime')",
3945057916 2007-08-01       drh:                       zSQL, zStart);
3945057916 2007-08-01       drh:     }
3945057916 2007-08-01       drh:   }
3945057916 2007-08-01       drh:   zSQL = mprintf("%z ORDER BY event.mtime DESC LIMIT %d", zSQL, nEntry);
3945057916 2007-08-01       drh:   db_prepare(&q, zSQL);
3945057916 2007-08-01       drh:   free(zSQL);
f5e8b1d736 2007-08-04       drh:   zDate[0] = 0;
bbdd4f9915 2007-08-27       drh:   blob_zero(&scriptInit);
bbdd4f9915 2007-08-27       drh:   www_print_timeline(&q, zDate, save_parentage_javascript, &scriptInit);
afcdc7ec97 2007-08-01       drh:   db_finalize(&q);
3945057916 2007-08-01       drh:   if( zStart==0 ){
3945057916 2007-08-01       drh:     zStart = zDate;
3945057916 2007-08-01       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();
bbdd4f9915 2007-08-27       drh:   cgi_append_content(blob_buffer(&scriptInit), blob_size(&scriptInit));
bbdd4f9915 2007-08-27       drh:   blob_reset(&scriptInit);
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:   @ }
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");
4d051c1eda 2007-08-29       drh:   @   setone(id,"#000000");
4d051c1eda 2007-08-29       drh:   @   set_children(id, "#002000");
4d051c1eda 2007-08-29       drh:   @   set_parents(id, "#200000");
bbdd4f9915 2007-08-27       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 ){
4d051c1eda 2007-08-29       drh:   @       w.style.color = "#ff0000";
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 ){
4d051c1eda 2007-08-29       drh:   @       w.style.color = "#008000";
4d051c1eda 2007-08-29       drh:   @     }
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
5341655085 2007-08-27       drh:   @ function xout(id) {
4d051c1eda 2007-08-29       drh:   @   setall("#000000");
5341655085 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:   @     }
5341655085 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
bbdd4f9915 2007-08-27       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>
3945057916 2007-08-01       drh:   @ <form method="GET" action="%s(g.zBaseURL)/timeline">
3945057916 2007-08-01       drh:   @ <input type="hidden" value="%h(zDate)" name="d">
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">
3945057916 2007-08-01       drh:   @ </form>
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.
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];
dbda8d6ce9 2007-07-21       drh:   zPrevDate[0] = 0;
dbda8d6ce9 2007-07-21       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;
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 = "";
dbda8d6ce9 2007-07-21       drh:     printf("%.5s [%.10s] ", &zDate[11], zUuid);
b846db063c 2007-08-25       drh:     if( nChild>1 || nParent>1 ){
b846db063c 2007-08-25       drh:       int n = 0;
b846db063c 2007-08-25       drh:       char zPrefix[50];
b846db063c 2007-08-25       drh:       if( nParent>1 ){
b846db063c 2007-08-25       drh:         sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* ");
b846db063c 2007-08-25       drh:         n = strlen(zPrefix);
b846db063c 2007-08-25       drh:       }
b846db063c 2007-08-25       drh:       if( nChild>1 ){
b846db063c 2007-08-25       drh:         sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*FORK* ");
b846db063c 2007-08-25       drh:         n = strlen(zPrefix);
b846db063c 2007-08-25       drh:       }
b846db063c 2007-08-25       drh:       zCom = zFree = sqlite3_mprintf("%s%s", zPrefix, zCom);
b846db063c 2007-08-25       drh:     }
dbda8d6ce9 2007-07-21       drh:     nLine += comment_print(zCom, 19, 79);
b846db063c 2007-08-25       drh:     sqlite3_free(zFree);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: timeline
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** Usage: %fossil timeline ?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
6607844a01 2007-08-18       drh: ** are given.  Show as many as N (default 20) check-ins.
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: ** The date and time should be in the ISO8601 format.  For
6607844a01 2007-08-18       drh: ** examples: "2007-08-18 07:21:21".  The time may be omitted.
6607844a01 2007-08-18       drh: ** Times are according to the local timezone.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void timeline_cmd(void){
dbda8d6ce9 2007-07-21       drh:   Stmt q;
6607844a01 2007-08-18       drh:   int n;
b846db063c 2007-08-25       drh:   const char *zCount;
6607844a01 2007-08-18       drh:   char *zDate;
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:   }
6607844a01 2007-08-18       drh:   if( g.argc!=2 && g.argc!=3 ){
6607844a01 2007-08-18       drh:     usage("YYYY-MM-DDtHH:MM:SS");
6607844a01 2007-08-18       drh:   }
6607844a01 2007-08-18       drh:   if( g.argc==3 ){
6607844a01 2007-08-18       drh:     zDate = g.argv[2];
6607844a01 2007-08-18       drh:   }else{
6607844a01 2007-08-18       drh:     zDate = "now";
6607844a01 2007-08-18       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_prepare(&q,
b846db063c 2007-08-25       drh:     "SELECT blob.rid, uuid, datetime(event.mtime,'localtime'),"
b846db063c 2007-08-25       drh:     "       comment || ' (by ' || user || ')',"
b846db063c 2007-08-25       drh:     "       (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim),"
b846db063c 2007-08-25       drh:     "       (SELECT count(*) FROM plink WHERE cid=blob.rid)"
dbda8d6ce9 2007-07-21       drh:     "  FROM event, blob"
dbda8d6ce9 2007-07-21       drh:     " WHERE event.type='ci' AND blob.rid=event.objid"
6607844a01 2007-08-18       drh:     "   AND event.mtime<=(SELECT julianday(%Q,'utc'))"
6607844a01 2007-08-18       drh:     " ORDER BY event.mtime DESC", zDate
dbda8d6ce9 2007-07-21       drh:   );
6607844a01 2007-08-18       drh:   print_timeline(&q, n);
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh: }