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 ){
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>
afcdc7ec97 2007-08-01       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,
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:  ){
afcdc7ec97 2007-08-01       drh:   char zPrevDate[20];
dbda8d6ce9 2007-07-21       drh:   zPrevDate[0] = 0;
e15fe43153 2007-08-31       drh:   int cnt = 0;
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>
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);
e15fe43153 2007-08-31       drh:     if( cnt==0 && pFirstEvent ){
e15fe43153 2007-08-31       drh:       *pFirstEvent = rid;
e15fe43153 2007-08-31       drh:     }
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>
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:     }
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>
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>
3945057916 2007-08-01       drh:     }
4d051c1eda 2007-08-29       drh:     @ %h(db_column_text(pQuery,3))
4d051c1eda 2007-08-29       drh:     @ (by %h(db_column_text(pQuery,4)))</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: /*
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
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
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");
e15fe43153 2007-08-31       drh:   int nEntry = atoi(PD("n","20"));
e15fe43153 2007-08-31       drh:   const char *zUser = P("u");
e15fe43153 2007-08-31       drh:   int objid = atoi(PD("e","0"));
e15fe43153 2007-08-31       drh:   int relatedEvents = P("r")!=0;
e15fe43153 2007-08-31       drh:   int afterFlag = P("a")!=0;
e15fe43153 2007-08-31       drh:   int firstEvent;
e15fe43153 2007-08-31       drh:   int lastEvent;
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:   );
e15fe43153 2007-08-31       drh:   if( zUser ){
e15fe43153 2007-08-31       drh:     zSQL = mprintf("%z AND event.user=%Q", zSQL, zUser);
e15fe43153 2007-08-31       drh:   }
e15fe43153 2007-08-31       drh:   if( objid ){
e15fe43153 2007-08-31       drh:     char *z = db_text(0, "SELECT datetime(event.mtime) 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] ){
e15fe43153 2007-08-31       drh:       zSQL = mprintf("%z AND event.mtime %s julianday(%Q, 'localtime')",
e15fe43153 2007-08-31       drh:                       zSQL, afterFlag ? ">=" : "<=", zStart);
e15fe43153 2007-08-31       drh:     }
e15fe43153 2007-08-31       drh:   }
abce5105e2 2007-09-01       drh:   if( relatedEvents && objid ){
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:     );
abce5105e2 2007-09-01       drh:     if( afterFlag ){
abce5105e2 2007-09-01       drh:       compute_descendents(objid, nEntry);
abce5105e2 2007-09-01       drh:     }else{
abce5105e2 2007-09-01       drh:       compute_ancestors(objid, nEntry);
3945057916 2007-08-01       drh:     }
abce5105e2 2007-09-01       drh:     zSQL = mprintf("%z AND event.objid IN ok", zSQL);
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);
e15fe43153 2007-08-31       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);
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:   @ }
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");
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 ){
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:   @     }
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
5341655085 2007-08-27       drh:   @ function xout(id) {
4d03017923 2007-08-30       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: **
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:     }
abce5105e2 2007-09-01       drh:     zDate = mprintf("(SELECT julianday('now','utc'))");
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:   }
abce5105e2 2007-09-01       drh:   zSQL = mprintf(
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"
abce5105e2 2007-09-01       drh:     "   AND event.mtime %s %s",
abce5105e2 2007-09-01       drh:     (mode==1 || mode==4) ? "<=" : ">=", 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: }