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: */ bbdd4f9915 2007-08-27 drh: void hyperlink_to_uuid_with_highlight(const char *zUuid, int id){ 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 ){ bbdd4f9915 2007-08-27 drh: @ <a onmouseover='hilite("m%d(id)")' onmouseout='unhilite("m%d(id)")' bbdd4f9915 2007-08-27 drh: @ href="%s(g.zBaseURL)/vinfo/%s(zUuid)">[%s(zShortUuid)]</a> bbdd4f9915 2007-08-27 drh: }else{ bbdd4f9915 2007-08-27 drh: @ <b onmouseover='hilite("m%d(id)")' onmouseout='unhilite("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); 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: } bbdd4f9915 2007-08-27 drh: @ <tr id="m%d(rid)" onmouseover='xin("m%d(rid)")' bbdd4f9915 2007-08-27 drh: @ onmouseout='xout("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"> bbdd4f9915 2007-08-27 drh: hyperlink_to_uuid(db_column_text(pQuery,1)); bbdd4f9915 2007-08-27 drh: @ %h(db_column_text(pQuery,3)) bbdd4f9915 2007-08-27 drh: if( nParent>1 ){ bbdd4f9915 2007-08-27 drh: Stmt q; bbdd4f9915 2007-08-27 drh: @ <b>Merge</b> from bbdd4f9915 2007-08-27 drh: db_prepare(&q, bbdd4f9915 2007-08-27 drh: "SELECT rid, uuid FROM plink, blob" bbdd4f9915 2007-08-27 drh: " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim=0", bbdd4f9915 2007-08-27 drh: rid bbdd4f9915 2007-08-27 drh: ); bbdd4f9915 2007-08-27 drh: while( db_step(&q)==SQLITE_ROW ){ bbdd4f9915 2007-08-27 drh: int mrid = db_column_int(&q, 0); bbdd4f9915 2007-08-27 drh: const char *zUuid = db_column_text(&q, 1); bbdd4f9915 2007-08-27 drh: hyperlink_to_uuid_with_highlight(zUuid, mrid); bbdd4f9915 2007-08-27 drh: } bbdd4f9915 2007-08-27 drh: db_finalize(&q); bbdd4f9915 2007-08-27 drh: } bbdd4f9915 2007-08-27 drh: if( nPChild>1 ){ bbdd4f9915 2007-08-27 drh: Stmt q; bbdd4f9915 2007-08-27 drh: @ <b>Fork</b> to bbdd4f9915 2007-08-27 drh: db_prepare(&q, bbdd4f9915 2007-08-27 drh: "SELECT rid, uuid FROM plink, blob" bbdd4f9915 2007-08-27 drh: " WHERE plink.pid=%d AND blob.rid=plink.cid AND plink.isprim>0", bbdd4f9915 2007-08-27 drh: rid bbdd4f9915 2007-08-27 drh: ); bbdd4f9915 2007-08-27 drh: while( db_step(&q)==SQLITE_ROW ){ bbdd4f9915 2007-08-27 drh: int frid = db_column_int(&q, 0); bbdd4f9915 2007-08-27 drh: const char *zUuid = db_column_text(&q, 1); bbdd4f9915 2007-08-27 drh: hyperlink_to_uuid_with_highlight(zUuid, frid); bbdd4f9915 2007-08-27 drh: } bbdd4f9915 2007-08-27 drh: db_finalize(&q); 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: } 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: @ } bbdd4f9915 2007-08-27 drh: @ function setone(id, onoff){ 5341655085 2007-08-27 drh: @ if( parentof[id]==null ) return 0; bbdd4f9915 2007-08-27 drh: @ var w = document.getElementById(id); e12f2f1839 2007-08-27 aku: @ var clr = onoff==1 ? "#e0e0ff" : "#ffffff"; e12f2f1839 2007-08-27 aku: @ if( w.backgroundColor==clr ){ 5341655085 2007-08-27 drh: @ return 0 bbdd4f9915 2007-08-27 drh: @ }else{ e12f2f1839 2007-08-27 aku: @ w.style.backgroundColor = 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) { bbdd4f9915 2007-08-27 drh: @ setall(0); bbdd4f9915 2007-08-27 drh: @ setone(id,1); bbdd4f9915 2007-08-27 drh: @ set_children(id); bbdd4f9915 2007-08-27 drh: @ set_parents(id); bbdd4f9915 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ function xout(id) { e12f2f1839 2007-08-27 aku: @ setall(0); bbdd4f9915 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ function set_parents(id){ 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]; 5341655085 2007-08-27 drh: @ if( setone(pid,1)==1 ){ 5341655085 2007-08-27 drh: @ set_parents(pid); 5341655085 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ function set_children(id){ 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]; 5341655085 2007-08-27 drh: @ if( setone(cid,1)==1 ){ 5341655085 2007-08-27 drh: @ set_children(cid); 5341655085 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ function hilite(id) { bbdd4f9915 2007-08-27 drh: @ var x = document.getElementById(id); e12f2f1839 2007-08-27 aku: @ x.style.color = "#ff0000"; bbdd4f9915 2007-08-27 drh: @ } bbdd4f9915 2007-08-27 drh: @ function unhilite(id) { bbdd4f9915 2007-08-27 drh: @ var x = document.getElementById(id); e12f2f1839 2007-08-27 aku: @ x.style.color = "#000000"; 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: }