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>
d23b8ba62b 2008-11-01       drh: #include <time.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:     }
fd36718ad9 2007-07-31       drh:   }
fd36718ad9 2007-07-31       drh: }
fd36718ad9 2007-07-31       drh: 
afcdc7ec97 2007-08-01       drh: /*
b5f4f910b7 2009-08-29       drh: ** Generate a hyperlink to a date & time.
b5f4f910b7 2009-08-29       drh: */
b5f4f910b7 2009-08-29       drh: void hyperlink_to_date(const char *zDate, const char *zSuffix){
b5f4f910b7 2009-08-29       drh:   if( zSuffix==0 ) zSuffix = "";
b5f4f910b7 2009-08-29       drh:   if( g.okHistory ){
b5f4f910b7 2009-08-29       drh:     @ <a href="%s(g.zTop)/timeline?c=%T(zDate)">%s(zDate)</a>%s(zSuffix)
b5f4f910b7 2009-08-29       drh:   }else{
b5f4f910b7 2009-08-29       drh:     @ %s(zDate)%s(zSuffix)
b5f4f910b7 2009-08-29       drh:   }
b5f4f910b7 2009-08-29       drh: }
b5f4f910b7 2009-08-29       drh: 
b5f4f910b7 2009-08-29       drh: /*
b5f4f910b7 2009-08-29       drh: ** Generate a hyperlink to a user.  This will link to a timeline showing
b5f4f910b7 2009-08-29       drh: ** events by that user.  If the date+time is specified, then the timeline
b5f4f910b7 2009-08-29       drh: ** is centered on that date+time.
b5f4f910b7 2009-08-29       drh: */
b5f4f910b7 2009-08-29       drh: void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
b5f4f910b7 2009-08-29       drh:   if( zSuf==0 ) zSuf = "";
b5f4f910b7 2009-08-29       drh:   if( g.okHistory ){
b5f4f910b7 2009-08-29       drh:     if( zD && zD[0] ){
b5f4f910b7 2009-08-29       drh:       @ <a href="%s(g.zTop)/timeline?c=%T(zD)&u=%T(zU)">%h(zU)</a>%s(zSuf)
b5f4f910b7 2009-08-29       drh:     }else{
b5f4f910b7 2009-08-29       drh:       @ <a href="%s(g.zTop)/timeline?u=%T(zU)">%h(zU)</a>%s(zSuf)
b5f4f910b7 2009-08-29       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else{
b5f4f910b7 2009-08-29       drh:     @ %s(zU)
9be1b00392 2009-01-25       drh:   }
9be1b00392 2009-01-25       drh: }
9be1b00392 2009-01-25       drh: 
9be1b00392 2009-01-25       drh: /*
42c2a18e73 2009-01-22       drh: ** Count the number of primary non-branch children for the given check-in.
42c2a18e73 2009-01-22       drh: **
42c2a18e73 2009-01-22       drh: ** A primary child is one where the parent is the primary parent, not
42c2a18e73 2009-01-22       drh: ** a merge parent.
42c2a18e73 2009-01-22       drh: **
42c2a18e73 2009-01-22       drh: ** A non-branch child is one which is on the same branch as the parent.
b6e22e62cf 2009-01-20       drh: */
b6e22e62cf 2009-01-20       drh: int count_nonbranch_children(int pid){
b6e22e62cf 2009-01-20       drh:   int nNonBranch;
42c2a18e73 2009-01-22       drh:   static const char zSql[] =
42c2a18e73 2009-01-22       drh:     @ SELECT count(*) FROM plink
42c2a18e73 2009-01-22       drh:     @  WHERE pid=%d AND isprim
42c2a18e73 2009-01-22       drh:     @    AND coalesce((SELECT value FROM tagxref
42c2a18e73 2009-01-22       drh:     @                   WHERE tagid=%d AND rid=plink.pid), 'trunk')
42c2a18e73 2009-01-22       drh:     @       =coalesce((SELECT value FROM tagxref
42c2a18e73 2009-01-22       drh:     @                   WHERE tagid=%d AND rid=plink.cid), 'trunk')
42c2a18e73 2009-01-22       drh:   ;
42c2a18e73 2009-01-22       drh:   nNonBranch = db_int(0, zSql, pid, TAG_BRANCH, TAG_BRANCH);
b6e22e62cf 2009-01-20       drh:   return nNonBranch;
b6e22e62cf 2009-01-20       drh: }
580d6ad8c7 2009-01-21       drh: 
580d6ad8c7 2009-01-21       drh: /*
580d6ad8c7 2009-01-21       drh: ** Allowed flags for the tmFlags argument to www_print_timeline
580d6ad8c7 2009-01-21       drh: */
580d6ad8c7 2009-01-21       drh: #if INTERFACE
2fa4df1e47 2009-01-21       drh: #define TIMELINE_ARTID    0x0001  /* Show artifact IDs on non-check-in lines */
2fa4df1e47 2009-01-21       drh: #define TIMELINE_LEAFONLY 0x0002  /* Show "Leaf", but not "Merge", "Fork" etc */
df3e34c2e8 2009-09-14       drh: #define TIMELINE_BRIEF    0x0004  /* Combine adjacent elements of same object */
580d6ad8c7 2009-01-21       drh: #endif
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
df3e34c2e8 2009-09-14       drh: **    9.  type ("ci", "w", "t")
fbbd0318bd 2009-01-20       drh: **   10.  list of symbolic tags.
df3e34c2e8 2009-09-14       drh: **   11.  tagid for ticket or wiki
df3e34c2e8 2009-09-14       drh: **   12.  Short comment to user for repeated tickets and wiki
bbdd4f9915 2007-08-27       drh: */
bbdd4f9915 2007-08-27       drh: void www_print_timeline(
580d6ad8c7 2009-01-21       drh:   Stmt *pQuery,          /* Query to implement the timeline */
580d6ad8c7 2009-01-21       drh:   int tmFlags,           /* Flags controlling display behavior */
580d6ad8c7 2009-01-21       drh:   void (*xExtra)(int)    /* Routine to call on each line of display */
fbbd0318bd 2009-01-20       drh: ){
ebb2765954 2007-12-04       drh:   int wikiFlags;
ebb2765954 2007-12-04       drh:   int mxWikiLen;
a84089319c 2007-10-11       drh:   Blob comment;
df3e34c2e8 2009-09-14       drh:   int prevTagid = 0;
df3e34c2e8 2009-09-14       drh:   int suppressCnt = 0;
dbda8d6ce9 2007-07-21       drh:   char zPrevDate[20];
5ebcedc33e 2007-07-31       dan: 
dbda8d6ce9 2007-07-21       drh:   zPrevDate[0] = 0;
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);
fbbd0318bd 2009-01-20       drh:     const char *zTagList = db_column_text(pQuery, 10);
df3e34c2e8 2009-09-14       drh:     int tagid = db_column_int(pQuery, 11);
df3e34c2e8 2009-09-14       drh:     int commentColumn = 3;    /* Column containing comment text */
df3e34c2e8 2009-09-14       drh:     if( tagid ){
df3e34c2e8 2009-09-14       drh:       if( tagid==prevTagid ){
df3e34c2e8 2009-09-14       drh:         if( tmFlags & TIMELINE_BRIEF ){
df3e34c2e8 2009-09-14       drh:           suppressCnt++;
df3e34c2e8 2009-09-14       drh:           continue;
df3e34c2e8 2009-09-14       drh:         }else{
df3e34c2e8 2009-09-14       drh:           commentColumn = 12;
df3e34c2e8 2009-09-14       drh:         }
df3e34c2e8 2009-09-14       drh:       }
df3e34c2e8 2009-09-14       drh:     }
df3e34c2e8 2009-09-14       drh:     prevTagid = tagid;
df3e34c2e8 2009-09-14       drh:     if( suppressCnt ){
df3e34c2e8 2009-09-14       drh:       @ <tr><td><td><td>
8cf8ed785e 2009-09-14       drh:       @ <small><i>... %d(suppressCnt) similar
8cf8ed785e 2009-09-14       drh:       @ event%s(suppressCnt>1?"s":"") omitted.</i></small></tr>
df3e34c2e8 2009-09-14       drh:       suppressCnt = 0;
df3e34c2e8 2009-09-14       drh:     }
b5f4f910b7 2009-08-29       drh:     if( strcmp(zType,"div")==0 ){
b5f4f910b7 2009-08-29       drh:       @ <tr><td colspan=3><hr></td></tr>
b5f4f910b7 2009-08-29       drh:       continue;
b5f4f910b7 2009-08-29       drh:     }
82fc5abb60 2008-02-26       drh:     db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
dbda8d6ce9 2007-07-21       drh:     if( memcmp(zDate, zPrevDate, 10) ){
dbda8d6ce9 2007-07-21       drh:       sprintf(zPrevDate, "%.10s", zDate);
dbda8d6ce9 2007-07-21       drh:       @ <tr><td colspan=3>
34af72801d 2007-11-23       drh:       @   <div class="divider">%s(zPrevDate)</div>
dbda8d6ce9 2007-07-21       drh:       @ </td></tr>
dbda8d6ce9 2007-07-21       drh:     }
4d03017923 2007-08-30       drh:     @ <tr>
bbdd4f9915 2007-08-27       drh:     @ <td valign="top">%s(&zDate[11])</td>
4d03017923 2007-08-30       drh:     @ <td width="20" align="center" valign="top">
4d03017923 2007-08-30       drh:     @ <font id="m%d(rid)" size="+1" color="white">*</font></td>
5e2392307d 2007-09-22       drh:     if( zBgClr && zBgClr[0] ){
5e2392307d 2007-09-22       drh:       @ <td valign="top" align="left" bgcolor="%h(zBgClr)">
5e2392307d 2007-09-22       drh:     }else{
5e2392307d 2007-09-22       drh:       @ <td valign="top" align="left">
5e2392307d 2007-09-22       drh:     }
dfea940da8 2007-10-09       drh:     if( zType[0]=='c' ){
cb31e90868 2009-01-23       drh:       const char *azTag[5];
cb31e90868 2009-01-23       drh:       int nTag = 0;
dfea940da8 2007-10-09       drh:       hyperlink_to_uuid_with_mouseover(zUuid, "xin", "xout", rid);
2fa4df1e47 2009-01-21       drh:       if( (tmFlags & TIMELINE_LEAFONLY)==0 ){
2fa4df1e47 2009-01-21       drh:         if( nParent>1 ){
cb31e90868 2009-01-23       drh:           azTag[nTag++] = "Merge";
2fa4df1e47 2009-01-21       drh:         }
2fa4df1e47 2009-01-21       drh:         if( nPChild>1 ){
2fa4df1e47 2009-01-21       drh:           if( count_nonbranch_children(rid)>1 ){
cb31e90868 2009-01-23       drh:             azTag[nTag++] = "Fork";
2fa4df1e47 2009-01-21       drh:           }else{
cb31e90868 2009-01-23       drh:             azTag[nTag++] = "Branch-Point";
2fa4df1e47 2009-01-21       drh:           }
b6e22e62cf 2009-01-20       drh:         }
dfea940da8 2007-10-09       drh:       }
dfea940da8 2007-10-09       drh:       if( isLeaf ){
cb31e90868 2009-01-23       drh:         if( db_exists("SELECT 1 FROM tagxref"
cb31e90868 2009-01-23       drh:                       " WHERE rid=%d AND tagid=%d AND tagtype>0",
cb31e90868 2009-01-23       drh:                       rid, TAG_CLOSED) ){
cb31e90868 2009-01-23       drh:           azTag[nTag++] = "Closed-Leaf";
cb31e90868 2009-01-23       drh:         }else{
cb31e90868 2009-01-23       drh:           azTag[nTag++] = "Leaf";
cb31e90868 2009-01-23       drh:         }
cb31e90868 2009-01-23       drh:       }
cb31e90868 2009-01-23       drh:       if( nTag>0 ){
cb31e90868 2009-01-23       drh:         int i;
cb31e90868 2009-01-23       drh:         for(i=0; i<nTag; i++){
cb31e90868 2009-01-23       drh:           @ <b>%s(azTag[i])%s(i==nTag-1?"":",")</b>
cb31e90868 2009-01-23       drh:         }
580d6ad8c7 2009-01-21       drh:       }
580d6ad8c7 2009-01-21       drh:     }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
dfea940da8 2007-10-09       drh:       hyperlink_to_uuid(zUuid);
dfea940da8 2007-10-09       drh:     }
df3e34c2e8 2009-09-14       drh:     db_column_blob(pQuery, commentColumn, &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);
fbbd0318bd 2009-01-20       drh:     if( zTagList && zTagList[0] ){
bdcac62937 2009-01-21       drh:       @ (user: %h(zUser), tags: %h(zTagList))
fbbd0318bd 2009-01-20       drh:     }else{
bdcac62937 2009-01-21       drh:       @ (user: %h(zUser))
bdcac62937 2009-01-21       drh:     }
bdcac62937 2009-01-21       drh:     if( xExtra ){
bdcac62937 2009-01-21       drh:       xExtra(rid);
bdcac62937 2009-01-21       drh:     }
bdcac62937 2009-01-21       drh:     @ </td></tr>
afcdc7ec97 2007-08-01       drh:   }
dbda8d6ce9 2007-07-21       drh:   @ </table>
afcdc7ec97 2007-08-01       drh: }
afcdc7ec97 2007-08-01       drh: 
bbdd4f9915 2007-08-27       drh: /*
e6aa161204 2008-02-26       drh: ** Create a temporary table suitable for storing timeline data.
9395aba4f4 2007-09-22       drh: */
e6aa161204 2008-02-26       drh: static void timeline_temp_table(void){
e6aa161204 2008-02-26       drh:   static const char zSql[] =
e6aa161204 2008-02-26       drh:     @ CREATE TEMP TABLE IF NOT EXISTS timeline(
e6aa161204 2008-02-26       drh:     @   rid INTEGER PRIMARY KEY,
e6aa161204 2008-02-26       drh:     @   uuid TEXT,
e6aa161204 2008-02-26       drh:     @   timestamp TEXT,
e6aa161204 2008-02-26       drh:     @   comment TEXT,
e6aa161204 2008-02-26       drh:     @   user TEXT,
e6aa161204 2008-02-26       drh:     @   nchild INTEGER,
e6aa161204 2008-02-26       drh:     @   nparent INTEGER,
e6aa161204 2008-02-26       drh:     @   isleaf BOOLEAN,
e6aa161204 2008-02-26       drh:     @   bgcolor TEXT,
fbbd0318bd 2009-01-20       drh:     @   etype TEXT,
df3e34c2e8 2009-09-14       drh:     @   taglist TEXT,
df3e34c2e8 2009-09-14       drh:     @   tagid INTEGER,
df3e34c2e8 2009-09-14       drh:     @   short TEXT
e6aa161204 2008-02-26       drh:     @ )
e6aa161204 2008-02-26       drh:   ;
e6aa161204 2008-02-26       drh:   db_multi_exec(zSql);
9395aba4f4 2007-09-22       drh: }
9395aba4f4 2007-09-22       drh: 
9395aba4f4 2007-09-22       drh: /*
9395aba4f4 2007-09-22       drh: ** Return a pointer to a constant string that forms the basis
9395aba4f4 2007-09-22       drh: ** for a timeline query for the WWW interface.
9395aba4f4 2007-09-22       drh: */
9395aba4f4 2007-09-22       drh: const char *timeline_query_for_www(void){
42c2a18e73 2009-01-22       drh:   static char *zBase = 0;
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),
42c2a18e73 2009-01-22       drh:     @   NOT EXISTS(SELECT 1 FROM plink
42c2a18e73 2009-01-22       drh:     @               WHERE pid=blob.rid
42c2a18e73 2009-01-22       drh:     @                AND coalesce((SELECT value FROM tagxref
42c2a18e73 2009-01-22       drh:     @                              WHERE tagid=%d AND rid=plink.pid), 'trunk')
42c2a18e73 2009-01-22       drh:     @                  = coalesce((SELECT value FROM tagxref
42c2a18e73 2009-01-22       drh:     @                              WHERE tagid=%d AND rid=plink.cid), 'trunk')),
b7f32a71ab 2009-01-20       drh:     @   bgcolor,
fbbd0318bd 2009-01-20       drh:     @   event.type,
fbbd0318bd 2009-01-20       drh:     @   (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref
fbbd0318bd 2009-01-20       drh:     @     WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
df3e34c2e8 2009-09-14       drh:     @       AND tagxref.rid=blob.rid AND tagxref.tagtype>0),
df3e34c2e8 2009-09-14       drh:     @   tagid,
df3e34c2e8 2009-09-14       drh:     @   brief
9395aba4f4 2007-09-22       drh:     @  FROM event JOIN blob
9395aba4f4 2007-09-22       drh:     @ WHERE blob.rid=event.objid
9395aba4f4 2007-09-22       drh:   ;
42c2a18e73 2009-01-22       drh:   if( zBase==0 ){
42c2a18e73 2009-01-22       drh:     zBase = mprintf(zBaseSql, TAG_BRANCH, TAG_BRANCH);
42c2a18e73 2009-01-22       drh:   }
42c2a18e73 2009-01-22       drh:   return zBase;
c9cd128c2c 2008-11-02       drh: }
c9cd128c2c 2008-11-02       drh: 
c9cd128c2c 2008-11-02       drh: /*
c9cd128c2c 2008-11-02       drh: ** Generate a submenu element with a single parameter change.
4d051c1eda 2007-08-29       drh: */
c9cd128c2c 2008-11-02       drh: static void timeline_submenu(
c9cd128c2c 2008-11-02       drh:   HQuery *pUrl,            /* Base URL */
c9cd128c2c 2008-11-02       drh:   const char *zMenuName,   /* Submenu name */
c9cd128c2c 2008-11-02       drh:   const char *zParam,      /* Parameter value to add or change */
c9cd128c2c 2008-11-02       drh:   const char *zValue,      /* Value of the new parameter */
c9cd128c2c 2008-11-02       drh:   const char *zRemove      /* Parameter to omit */
c9cd128c2c 2008-11-02       drh: ){
c9cd128c2c 2008-11-02       drh:   style_submenu_element(zMenuName, zMenuName, "%s",
c9cd128c2c 2008-11-02       drh:                         url_render(pUrl, zParam, zValue, zRemove, 0));
4d051c1eda 2007-08-29       drh: }
c9cd128c2c 2008-11-02       drh: 
4d051c1eda 2007-08-29       drh: 
4d051c1eda 2007-08-29       drh: /*
d42adc11c8 2009-08-29       drh: ** zDate is a localtime date.  Insert records into the
d42adc11c8 2009-08-29       drh: ** "timeline" table to cause <hr> to be inserted before and after
d42adc11c8 2009-08-29       drh: ** entries of that date.
bbdd4f9915 2007-08-27       drh: */
d42adc11c8 2009-08-29       drh: static void timeline_add_dividers(const char *zDate){
d42adc11c8 2009-08-29       drh:   db_multi_exec(
d42adc11c8 2009-08-29       drh:     "INSERT INTO timeline(rid,timestamp,etype)"
d42adc11c8 2009-08-29       drh:     "VALUES(-1,datetime(%Q,'-1 second') || '.9','div')",
d42adc11c8 2009-08-29       drh:     zDate
d42adc11c8 2009-08-29       drh:   );
d42adc11c8 2009-08-29       drh:   db_multi_exec(
d42adc11c8 2009-08-29       drh:     "INSERT INTO timeline(rid,timestamp,etype)"
d42adc11c8 2009-08-29       drh:     "VALUES(-2,datetime(%Q) || '.1','div')",
d42adc11c8 2009-08-29       drh:      zDate
4d051c1eda 2007-08-29       drh:   );
bbdd4f9915 2007-08-27       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: **
e6aa161204 2008-02-26       drh: **    a=TIMESTAMP    after this date
e6aa161204 2008-02-26       drh: **    b=TIMESTAMP    before this date.
5a539f82dc 2009-08-15       drh: **    c=TIMESTAMP    "circa" this date.
e6aa161204 2008-02-26       drh: **    n=COUNT        number of events in output
e6aa161204 2008-02-26       drh: **    p=RID          artifact RID and up to COUNT parents and ancestors
6458f020fc 2008-05-14       drh: **    d=RID          artifact RID and up to COUNT descendants
fecb3e5cc9 2009-01-20       drh: **    t=TAGID        show only check-ins with the given tagid
e6aa161204 2008-02-26       drh: **    u=USER         only if belonging to this user
c9cd128c2c 2008-11-02       drh: **    y=TYPE         'ci', 'w', 't'
e6aa161204 2008-02-26       drh: **
e6aa161204 2008-02-26       drh: ** p= and d= can appear individually or together.  If either p= or d=
e6aa161204 2008-02-26       drh: ** appear, then u=, y=, a=, and b= are ignored.
e6aa161204 2008-02-26       drh: **
e6aa161204 2008-02-26       drh: ** If a= and b= appear, only a= is used.  If neither appear, the most
e6aa161204 2008-02-26       drh: ** recent events are choosen.
e6aa161204 2008-02-26       drh: **
e6aa161204 2008-02-26       drh: ** If n= is missing, the default count is 20.
afcdc7ec97 2007-08-01       drh: */
afcdc7ec97 2007-08-01       drh: void page_timeline(void){
e6aa161204 2008-02-26       drh:   Stmt q;                            /* Query used to generate the timeline */
e6aa161204 2008-02-26       drh:   Blob sql;                          /* text of SQL used to generate timeline */
e6aa161204 2008-02-26       drh:   Blob desc;                         /* Description of the timeline */
e38c89130f 2008-02-24       drh:   int nEntry = atoi(PD("n","20"));   /* Max number of entries on timeline */
e6aa161204 2008-02-26       drh:   int p_rid = atoi(PD("p","0"));     /* artifact p and its parents */
6458f020fc 2008-05-14       drh:   int d_rid = atoi(PD("d","0"));     /* artifact d and its descendants */
e38c89130f 2008-02-24       drh:   const char *zUser = P("u");        /* All entries by this user if not NULL */
c9cd128c2c 2008-11-02       drh:   const char *zType = PD("y","all"); /* 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 */
5a539f82dc 2009-08-15       drh:   const char *zCirca = P("c");       /* Events near this time */
e631d8af6d 2009-01-21       drh:   const char *zTagName = P("t");     /* Show events with this tag */
c9cd128c2c 2008-11-02       drh:   HQuery url;                        /* URL for various branch links */
e631d8af6d 2009-01-21       drh:   int tagid;                         /* Tag ID */
df3e34c2e8 2009-09-14       drh:   int tmFlags;                       /* Timeline flags */
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; }
e631d8af6d 2009-01-21       drh:   if( zTagName ){
e631d8af6d 2009-01-21       drh:     tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
e631d8af6d 2009-01-21       drh:   }else{
e631d8af6d 2009-01-21       drh:     tagid = 0;
df3e34c2e8 2009-09-14       drh:   }
df3e34c2e8 2009-09-14       drh:   if( zType[0]=='a' ){
df3e34c2e8 2009-09-14       drh:     tmFlags = TIMELINE_BRIEF;
df3e34c2e8 2009-09-14       drh:   }else{
df3e34c2e8 2009-09-14       drh:     tmFlags = 0;
e631d8af6d 2009-01-21       drh:   }
afcdc7ec97 2007-08-01       drh: 
afcdc7ec97 2007-08-01       drh:   style_header("Timeline");
2b0d4519dc 2008-05-05       drh:   login_anonymous_available();
e6aa161204 2008-02-26       drh:   timeline_temp_table();
20553a420c 2007-12-03       drh:   blob_zero(&sql);
e38c89130f 2008-02-24       drh:   blob_zero(&desc);
e6aa161204 2008-02-26       drh:   blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
20553a420c 2007-12-03       drh:   blob_append(&sql, timeline_query_for_www(), -1);
e6aa161204 2008-02-26       drh:   if( p_rid || d_rid ){
e6aa161204 2008-02-26       drh:     /* If p= or d= is present, ignore all other parameters other than n= */
e38c89130f 2008-02-24       drh:     char *zUuid;
e6aa161204 2008-02-26       drh:     int np, nd;
e6aa161204 2008-02-26       drh: 
d42adc11c8 2009-08-29       drh:     if( p_rid && d_rid ){
d42adc11c8 2009-08-29       drh:       if( p_rid!=d_rid ) p_rid = d_rid;
d42adc11c8 2009-08-29       drh:       if( P("n")==0 ) nEntry = 10;
d42adc11c8 2009-08-29       drh:     }
abce5105e2 2007-09-01       drh:     db_multi_exec(
abce5105e2 2007-09-01       drh:        "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
abce5105e2 2007-09-01       drh:     );
e6aa161204 2008-02-26       drh:     zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d",
e6aa161204 2008-02-26       drh:                          p_rid ? p_rid : d_rid);
e6aa161204 2008-02-26       drh:     blob_appendf(&sql, " AND event.objid IN ok");
e6aa161204 2008-02-26       drh:     nd = 0;
e6aa161204 2008-02-26       drh:     if( d_rid ){
d42adc11c8 2009-08-29       drh:       compute_descendants(d_rid, nEntry+1);
e6aa161204 2008-02-26       drh:       nd = db_int(0, "SELECT count(*)-1 FROM ok");
e6aa161204 2008-02-26       drh:       if( nd>0 ){
e6aa161204 2008-02-26       drh:         db_multi_exec("%s", blob_str(&sql));
6458f020fc 2008-05-14       drh:         blob_appendf(&desc, "%d descendants", nd);
e6aa161204 2008-02-26       drh:       }
d42adc11c8 2009-08-29       drh:       timeline_add_dividers(
d42adc11c8 2009-08-29       drh:         db_text("1","SELECT datetime(mtime,'localtime') FROM event"
d42adc11c8 2009-08-29       drh:                     " WHERE objid=%d", d_rid)
d42adc11c8 2009-08-29       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 ){
d42adc11c8 2009-08-29       drh:       compute_ancestors(p_rid, nEntry+1);
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:       }
d42adc11c8 2009-08-29       drh:       if( d_rid==0 ){
d42adc11c8 2009-08-29       drh:         timeline_add_dividers(
d42adc11c8 2009-08-29       drh:           db_text("1","SELECT datetime(mtime,'localtime') FROM event"
d42adc11c8 2009-08-29       drh:                       " WHERE objid=%d", p_rid)
d42adc11c8 2009-08-29       drh:         );
d42adc11c8 2009-08-29       drh:       }
2b0d4519dc 2008-05-05       drh:     }
2b0d4519dc 2008-05-05       drh:     if( g.okHistory ){
2b0d4519dc 2008-05-05       drh:       blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
2b0d4519dc 2008-05-05       drh:                    g.zBaseURL, zUuid, zUuid);
20553a420c 2007-12-03       drh:     }else{
d42adc11c8 2009-08-29       drh:       blob_appendf(&desc, " of check-in [%.10s]", zUuid);
e631d8af6d 2009-01-21       drh:     }
20553a420c 2007-12-03       drh:   }else{
7915bd0665 2008-02-26       drh:     int n;
e6aa161204 2008-02-26       drh:     const char *zEType = "event";
c9cd128c2c 2008-11-02       drh:     char *zDate;
c9cd128c2c 2008-11-02       drh:     char *zNEntry = mprintf("%d", nEntry);
c9cd128c2c 2008-11-02       drh:     url_initialize(&url, "timeline");
c9cd128c2c 2008-11-02       drh:     url_add_parameter(&url, "n", zNEntry);
e631d8af6d 2009-01-21       drh:     if( tagid>0 ){
e631d8af6d 2009-01-21       drh:       zType = "ci";
e631d8af6d 2009-01-21       drh:       url_add_parameter(&url, "t", zTagName);
e631d8af6d 2009-01-21       drh:       blob_appendf(&sql, " AND EXISTS (SELECT 1 FROM tagxref WHERE tagid=%d"
e631d8af6d 2009-01-21       drh:                                         " AND tagtype>0 AND rid=blob.rid)",
e631d8af6d 2009-01-21       drh:                    tagid);
e631d8af6d 2009-01-21       drh:     }
c9cd128c2c 2008-11-02       drh:     if( zType[0]!='a' ){
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " AND event.type=%Q", zType);
c9cd128c2c 2008-11-02       drh:       url_add_parameter(&url, "y", zType);
e6aa161204 2008-02-26       drh:       if( zType[0]=='c' ){
e6aa161204 2008-02-26       drh:         zEType = "checkin";
e6aa161204 2008-02-26       drh:       }else if( zType[0]=='w' ){
e6aa161204 2008-02-26       drh:         zEType = "wiki edit";
e6aa161204 2008-02-26       drh:       }else if( zType[0]=='t' ){
e6aa161204 2008-02-26       drh:         zEType = "ticket change";
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:     }
e6aa161204 2008-02-26       drh:     if( zUser ){
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " AND event.user=%Q", zUser);
c9cd128c2c 2008-11-02       drh:       url_add_parameter(&url, "u", 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);
c9cd128c2c 2008-11-02       drh:         url_add_parameter(&url, "a", zAfter);
e6aa161204 2008-02-26       drh:         zBefore = 0;
7915bd0665 2008-02-26       drh:       }else{
7915bd0665 2008-02-26       drh:         zAfter = 0;
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:     }else if( zBefore ){
e6aa161204 2008-02-26       drh:       while( isspace(zBefore[0]) ){ zBefore++; }
e6aa161204 2008-02-26       drh:       if( zBefore[0] ){
e6aa161204 2008-02-26       drh:         blob_appendf(&sql,
e6aa161204 2008-02-26       drh:            " AND event.mtime<=(SELECT julianday(%Q, 'utc'))"
e6aa161204 2008-02-26       drh:            " ORDER BY event.mtime DESC", zBefore);
c9cd128c2c 2008-11-02       drh:         url_add_parameter(&url, "b", zBefore);
7915bd0665 2008-02-26       drh:        }else{
7915bd0665 2008-02-26       drh:         zBefore = 0;
c9cd128c2c 2008-11-02       drh:       }
5a539f82dc 2009-08-15       drh:     }else if( zCirca ){
5a539f82dc 2009-08-15       drh:       while( isspace(zCirca[0]) ){ zCirca++; }
5a539f82dc 2009-08-15       drh:       if( zCirca[0] ){
5a539f82dc 2009-08-15       drh:         double rCirca = db_double(0.0, "SELECT julianday(%Q, 'utc')", zCirca);
5a539f82dc 2009-08-15       drh:         Blob sql2;
5a539f82dc 2009-08-15       drh:         blob_init(&sql2, blob_str(&sql), -1);
5a539f82dc 2009-08-15       drh:         blob_appendf(&sql2,
5a539f82dc 2009-08-15       drh:             " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d",
5a539f82dc 2009-08-15       drh:             rCirca, (nEntry+1)/2
5a539f82dc 2009-08-15       drh:         );
5a539f82dc 2009-08-15       drh:         db_multi_exec("%s", blob_str(&sql2));
5a539f82dc 2009-08-15       drh:         blob_reset(&sql2);
5a539f82dc 2009-08-15       drh:         blob_appendf(&sql,
5a539f82dc 2009-08-15       drh:             " AND event.mtime>=%f ORDER BY event.mtime ASC",
5a539f82dc 2009-08-15       drh:             rCirca
5a539f82dc 2009-08-15       drh:         );
5a539f82dc 2009-08-15       drh:         nEntry -= (nEntry+1)/2;
d42adc11c8 2009-08-29       drh:         timeline_add_dividers(zCirca);
5a539f82dc 2009-08-15       drh:         url_add_parameter(&url, "c", zCirca);
5a539f82dc 2009-08-15       drh:       }else{
5a539f82dc 2009-08-15       drh:         zCirca = 0;
e6aa161204 2008-02-26       drh:       }
e6aa161204 2008-02-26       drh:     }else{
e6aa161204 2008-02-26       drh:       blob_appendf(&sql, " ORDER BY event.mtime DESC");
e6aa161204 2008-02-26       drh:     }
e6aa161204 2008-02-26       drh:     blob_appendf(&sql, " LIMIT %d", nEntry);
e6aa161204 2008-02-26       drh:     db_multi_exec("%s", blob_str(&sql));
7915bd0665 2008-02-26       drh: 
7915bd0665 2008-02-26       drh:     n = db_int(0, "SELECT count(*) FROM timeline");
c9cd128c2c 2008-11-02       drh:     if( n<nEntry && zAfter ){
c9cd128c2c 2008-11-02       drh:       cgi_redirect(url_render(&url, "a", 0, "b", 0));
c9cd128c2c 2008-11-02       drh:     }
5a539f82dc 2009-08-15       drh:     if( zAfter==0 && zBefore==0 && zCirca==0 ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, "%d most recent %ss", n, zEType);
abce5105e2 2007-09-01       drh:     }else{
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, "%d %ss", n, zEType);
7915bd0665 2008-02-26       drh:     }
7915bd0665 2008-02-26       drh:     if( zUser ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, " by user %h", zUser);
7915bd0665 2008-02-26       drh:     }
e631d8af6d 2009-01-21       drh:     if( tagid>0 ){
e631d8af6d 2009-01-21       drh:       blob_appendf(&desc, " tagged with \"%h\"", zTagName);
e631d8af6d 2009-01-21       drh:     }
7915bd0665 2008-02-26       drh:     if( zAfter ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
7915bd0665 2008-02-26       drh:     }else if( zBefore ){
7915bd0665 2008-02-26       drh:       blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
5a539f82dc 2009-08-15       drh:     }else if( zCirca ){
5a539f82dc 2009-08-15       drh:       blob_appendf(&desc, " occurring around %h.<br>", zCirca);
2b0d4519dc 2008-05-05       drh:     }
2b0d4519dc 2008-05-05       drh:     if( g.okHistory ){
2b0d4519dc 2008-05-05       drh:       if( zAfter || n==nEntry ){
2b0d4519dc 2008-05-05       drh:         zDate = db_text(0, "SELECT min(timestamp) FROM timeline");
c9cd128c2c 2008-11-02       drh:         timeline_submenu(&url, "Older", "b", zDate, "a");
c9cd128c2c 2008-11-02       drh:         free(zDate);
2b0d4519dc 2008-05-05       drh:       }
2b0d4519dc 2008-05-05       drh:       if( zBefore || (zAfter && n==nEntry) ){
2b0d4519dc 2008-05-05       drh:         zDate = db_text(0, "SELECT max(timestamp) FROM timeline");
c9cd128c2c 2008-11-02       drh:         timeline_submenu(&url, "Newer", "a", zDate, "b");
c9cd128c2c 2008-11-02       drh:         free(zDate);
e631d8af6d 2009-01-21       drh:       }else if( tagid==0 ){
c9cd128c2c 2008-11-02       drh:         if( zType[0]!='a' ){
c9cd128c2c 2008-11-02       drh:           timeline_submenu(&url, "All Types", "y", "all", 0);
c9cd128c2c 2008-11-02       drh:         }
c9cd128c2c 2008-11-02       drh:         if( zType[0]!='w' ){
c9cd128c2c 2008-11-02       drh:           timeline_submenu(&url, "Wiki Only", "y", "w", 0);
c9cd128c2c 2008-11-02       drh:         }
c9cd128c2c 2008-11-02       drh:         if( zType[0]!='c' ){
c9cd128c2c 2008-11-02       drh:           timeline_submenu(&url, "Checkins Only", "y", "ci", 0);
c9cd128c2c 2008-11-02       drh:         }
c9cd128c2c 2008-11-02       drh:         if( zType[0]!='t' ){
c9cd128c2c 2008-11-02       drh:           timeline_submenu(&url, "Tickets Only", "y", "t", 0);
c9cd128c2c 2008-11-02       drh:         }
c9cd128c2c 2008-11-02       drh:       }
c9cd128c2c 2008-11-02       drh:       if( nEntry>20 ){
c9cd128c2c 2008-11-02       drh:         timeline_submenu(&url, "20 Events", "n", "20", 0);
c9cd128c2c 2008-11-02       drh:       }
c9cd128c2c 2008-11-02       drh:       if( nEntry<200 ){
c9cd128c2c 2008-11-02       drh:         timeline_submenu(&url, "200 Events", "n", "200", 0);
2b0d4519dc 2008-05-05       drh:       }
7915bd0665 2008-02-26       drh:     }
20553a420c 2007-12-03       drh:   }
20553a420c 2007-12-03       drh:   blob_zero(&sql);
e6aa161204 2008-02-26       drh:   db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
e38c89130f 2008-02-24       drh:   @ <h2>%b(&desc)</h2>
e38c89130f 2008-02-24       drh:   blob_reset(&desc);
df3e34c2e8 2009-09-14       drh:   www_print_timeline(&q, tmFlags, 0);
3945057916 2007-08-01       drh:   db_finalize(&q);
82fc5abb60 2008-02-26       drh: 
bbdd4f9915 2007-08-27       drh:   @ <script>
bbdd4f9915 2007-08-27       drh:   @ var parentof = new Object();
bbdd4f9915 2007-08-27       drh:   @ var childof = new Object();
82fc5abb60 2008-02-26       drh:   db_prepare(&q, "SELECT rid FROM timeline");
82fc5abb60 2008-02-26       drh:   while( db_step(&q)==SQLITE_ROW ){
82fc5abb60 2008-02-26       drh:     int rid = db_column_int(&q, 0);
82fc5abb60 2008-02-26       drh:     Stmt q2;
82fc5abb60 2008-02-26       drh:     const char *zSep;
82fc5abb60 2008-02-26       drh:     Blob *pOut = cgi_output_blob();
82fc5abb60 2008-02-26       drh: 
82fc5abb60 2008-02-26       drh:     db_prepare(&q2, "SELECT pid FROM plink WHERE cid=%d", rid);
82fc5abb60 2008-02-26       drh:     zSep = "";
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "parentof[\"m%d\"] = [", rid);
82fc5abb60 2008-02-26       drh:     while( db_step(&q2)==SQLITE_ROW ){
82fc5abb60 2008-02-26       drh:       int pid = db_column_int(&q2, 0);
82fc5abb60 2008-02-26       drh:       blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
82fc5abb60 2008-02-26       drh:       zSep = ",";
82fc5abb60 2008-02-26       drh:     }
82fc5abb60 2008-02-26       drh:     db_finalize(&q2);
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "];\n");
82fc5abb60 2008-02-26       drh:     db_prepare(&q2, "SELECT cid FROM plink WHERE pid=%d", rid);
82fc5abb60 2008-02-26       drh:     zSep = "";
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "childof[\"m%d\"] = [", rid);
82fc5abb60 2008-02-26       drh:     while( db_step(&q2)==SQLITE_ROW ){
82fc5abb60 2008-02-26       drh:       int pid = db_column_int(&q2, 0);
82fc5abb60 2008-02-26       drh:       blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
82fc5abb60 2008-02-26       drh:       zSep = ",";
82fc5abb60 2008-02-26       drh:     }
82fc5abb60 2008-02-26       drh:     db_finalize(&q2);
82fc5abb60 2008-02-26       drh:     blob_appendf(pOut, "];\n");
3945057916 2007-08-01       drh:   }
afcdc7ec97 2007-08-01       drh:   db_finalize(&q);
bbdd4f9915 2007-08-27       drh:   @ function setall(value){
bbdd4f9915 2007-08-27       drh:   @   for(var x in parentof){
bbdd4f9915 2007-08-27       drh:   @     setone(x,value);
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
4d03017923 2007-08-30       drh:   @ setall("#ffffff");
4d051c1eda 2007-08-29       drh:   @ function setone(id, clr){
5341655085 2007-08-27       drh:   @   if( parentof[id]==null ) return 0;
bbdd4f9915 2007-08-27       drh:   @   var w = document.getElementById(id);
5341655085 2007-08-27       drh:   @   if( w.style.color==clr ){
5341655085 2007-08-27       drh:   @     return 0
bbdd4f9915 2007-08-27       drh:   @   }else{
5341655085 2007-08-27       drh:   @     w.style.color = clr
5341655085 2007-08-27       drh:   @     return 1
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
bbdd4f9915 2007-08-27       drh:   @ function xin(id) {
4d051c1eda 2007-08-29       drh:   @   setall("#ffffff");
4d03017923 2007-08-30       drh:   @   setone(id,"#ff0000");
4d03017923 2007-08-30       drh:   @   set_children(id, "#b0b0b0");
4d03017923 2007-08-30       drh:   @   set_parents(id, "#b0b0b0");
4d051c1eda 2007-08-29       drh:   @   for(var x in parentof[id]){
4d051c1eda 2007-08-29       drh:   @     var pid = parentof[id][x]
4d051c1eda 2007-08-29       drh:   @     var w = document.getElementById(pid);
4d051c1eda 2007-08-29       drh:   @     if( w!=null ){
4d03017923 2007-08-30       drh:   @       w.style.color = "#000000";
4d051c1eda 2007-08-29       drh:   @     }
4d051c1eda 2007-08-29       drh:   @   }
4d051c1eda 2007-08-29       drh:   @   for(var x in childof[id]){
4d051c1eda 2007-08-29       drh:   @     var cid = childof[id][x]
4d051c1eda 2007-08-29       drh:   @     var w = document.getElementById(cid);
4d051c1eda 2007-08-29       drh:   @     if( w!=null ){
4d03017923 2007-08-30       drh:   @       w.style.color = "#000000";
4d051c1eda 2007-08-29       drh:   @     }
4d051c1eda 2007-08-29       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
bbdd4f9915 2007-08-27       drh:   @ function xout(id) {
4d03017923 2007-08-30       drh:   @   /* setall("#000000"); */
bbdd4f9915 2007-08-27       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ function set_parents(id, clr){
5341655085 2007-08-27       drh:   @   var plist = parentof[id];
5341655085 2007-08-27       drh:   @   if( plist==null ) return;
5341655085 2007-08-27       drh:   @   for(var x in plist){
5341655085 2007-08-27       drh:   @     var pid = plist[x];
4d051c1eda 2007-08-29       drh:   @     if( setone(pid,clr)==1 ){
4d051c1eda 2007-08-29       drh:   @       set_parents(pid,clr);
5341655085 2007-08-27       drh:   @     }
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ function set_children(id,clr){
5341655085 2007-08-27       drh:   @   var clist = childof[id];
5341655085 2007-08-27       drh:   @   if( clist==null ) return;
5341655085 2007-08-27       drh:   @   for(var x in clist){
5341655085 2007-08-27       drh:   @     var cid = clist[x];
4d051c1eda 2007-08-29       drh:   @     if( setone(cid,clr)==1 ){
4d051c1eda 2007-08-29       drh:   @       set_children(cid,clr);
5341655085 2007-08-27       drh:   @     }
bbdd4f9915 2007-08-27       drh:   @   }
bbdd4f9915 2007-08-27       drh:   @ }
4d051c1eda 2007-08-29       drh:   @ </script>
dbda8d6ce9 2007-07-21       drh:   style_footer();
dbda8d6ce9 2007-07-21       drh: }
3945057916 2007-08-01       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The input query q selects various records.  Print a human-readable
dbda8d6ce9 2007-07-21       drh: ** summary of those records.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Limit the number of entries printed to nLine.
9395aba4f4 2007-09-22       drh: **
9395aba4f4 2007-09-22       drh: ** The query should return these columns:
9395aba4f4 2007-09-22       drh: **
9395aba4f4 2007-09-22       drh: **    0.  rid
9395aba4f4 2007-09-22       drh: **    1.  uuid
9395aba4f4 2007-09-22       drh: **    2.  Date/Time
9395aba4f4 2007-09-22       drh: **    3.  Comment string and user
9395aba4f4 2007-09-22       drh: **    4.  Number of non-merge children
9395aba4f4 2007-09-22       drh: **    5.  Number of parents
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void print_timeline(Stmt *q, int mxLine){
dbda8d6ce9 2007-07-21       drh:   int nLine = 0;
dbda8d6ce9 2007-07-21       drh:   char zPrevDate[20];
097479f99a 2007-09-26       drh:   const char *zCurrentUuid=0;
dbda8d6ce9 2007-07-21       drh:   zPrevDate[0] = 0;
dbda8d6ce9 2007-07-21       drh: 
c1e85e4da5 2008-07-13       drh:   if( g.localOpen ){
c1e85e4da5 2008-07-13       drh:     int rid = db_lget_int("checkout", 0);
c1e85e4da5 2008-07-13       drh:     zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
2db88ec639 2007-09-25       jnc:   }
2db88ec639 2007-09-25       jnc: 
dbda8d6ce9 2007-07-21       drh:   while( db_step(q)==SQLITE_ROW && nLine<=mxLine ){
b6e22e62cf 2009-01-20       drh:     int rid = db_column_int(q, 0);
b846db063c 2007-08-25       drh:     const char *zId = db_column_text(q, 1);
b846db063c 2007-08-25       drh:     const char *zDate = db_column_text(q, 2);
b846db063c 2007-08-25       drh:     const char *zCom = db_column_text(q, 3);
b846db063c 2007-08-25       drh:     int nChild = db_column_int(q, 4);
b846db063c 2007-08-25       drh:     int nParent = db_column_int(q, 5);
b846db063c 2007-08-25       drh:     char *zFree = 0;
097479f99a 2007-09-26       drh:     int n = 0;
097479f99a 2007-09-26       drh:     char zPrefix[80];
dbda8d6ce9 2007-07-21       drh:     char zUuid[UUID_SIZE+1];
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     sprintf(zUuid, "%.10s", zId);
dbda8d6ce9 2007-07-21       drh:     if( memcmp(zDate, zPrevDate, 10) ){
dbda8d6ce9 2007-07-21       drh:       printf("=== %.10s ===\n", zDate);
dbda8d6ce9 2007-07-21       drh:       memcpy(zPrevDate, zDate, 10);
dbda8d6ce9 2007-07-21       drh:       nLine++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( zCom==0 ) zCom = "";
fcabd4774c 2007-09-13       drh:     printf("%.8s ", &zDate[11]);
097479f99a 2007-09-26       drh:     zPrefix[0] = 0;
097479f99a 2007-09-26       drh:     if( nParent>1 ){
097479f99a 2007-09-26       drh:       sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* ");
097479f99a 2007-09-26       drh:       n = strlen(zPrefix);
097479f99a 2007-09-26       drh:     }
097479f99a 2007-09-26       drh:     if( nChild>1 ){
b6e22e62cf 2009-01-20       drh:       const char *zBrType;
b6e22e62cf 2009-01-20       drh:       if( count_nonbranch_children(rid)>1 ){
b6e22e62cf 2009-01-20       drh:         zBrType = "*FORK* ";
b6e22e62cf 2009-01-20       drh:       }else{
b6e22e62cf 2009-01-20       drh:         zBrType = "*BRANCH* ";
b846db063c 2007-08-25       drh:       }
b6e22e62cf 2009-01-20       drh:       sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], zBrType);
097479f99a 2007-09-26       drh:       n = strlen(zPrefix);
097479f99a 2007-09-26       drh:     }
c1e85e4da5 2008-07-13       drh:     if( zCurrentUuid && strcmp(zCurrentUuid,zId)==0 ){
097479f99a 2007-09-26       drh:       sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*CURRENT* ");
097479f99a 2007-09-26       drh:       n += strlen(zPrefix);
b846db063c 2007-08-25       drh:     }
097479f99a 2007-09-26       drh:     zFree = sqlite3_mprintf("[%.10s] %s%s", zUuid, zPrefix, zCom);
fcabd4774c 2007-09-13       drh:     nLine += comment_print(zFree, 9, 79);
b846db063c 2007-08-25       drh:     sqlite3_free(zFree);
b846db063c 2007-08-25       drh:   }
b846db063c 2007-08-25       drh: }
b846db063c 2007-08-25       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'),
fbbd0318bd 2009-01-20       drh:     @   coalesce(ecomment,comment)
fbbd0318bd 2009-01-20       drh:     @     || ' (user: ' || coalesce(euser,user,'?')
fbbd0318bd 2009-01-20       drh:     @     || (SELECT case when length(x)>0 then ' tags: ' || x else '' end
fbbd0318bd 2009-01-20       drh:     @           FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
fbbd0318bd 2009-01-20       drh:     @                   FROM tag, tagxref
fbbd0318bd 2009-01-20       drh:     @                  WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
fbbd0318bd 2009-01-20       drh:     @                    AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
9395aba4f4 2007-09-22       drh:     @     || ')',
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: }
9395aba4f4 2007-09-22       drh: 
dfea940da8 2007-10-09       drh: /*
bab8363876 2008-12-12   stephan: ** Equivalent to timeline_query_for_tty(), except that:
bab8363876 2008-12-12   stephan: **
bab8363876 2008-12-12   stephan: ** a) accepts a the -type=XX flag to set the event type to filter on.
bab8363876 2008-12-12   stephan: **    The values of XX are the same as supported by the /timeline page.
bab8363876 2008-12-12   stephan: **
bab8363876 2008-12-12   stephan: ** b) The returned string must be freed using free().
bab8363876 2008-12-12   stephan: */
bab8363876 2008-12-12   stephan: char * timeline_query_for_tty_m(void){
bab8363876 2008-12-12   stephan:   Blob bl;
bab8363876 2008-12-12   stephan:   char const * zType = 0;
bab8363876 2008-12-12   stephan:   blob_zero(&bl);
bab8363876 2008-12-12   stephan:   blob_append( &bl, timeline_query_for_tty(), -1 );
bab8363876 2008-12-12   stephan:   zType = find_option( "type", "t", 1 );
bab8363876 2008-12-12   stephan:   if( zType && *zType )
bab8363876 2008-12-12   stephan:   {
bab8363876 2008-12-12   stephan:       blob_appendf( &bl, " AND event.type=%Q", zType );
dbda8d6ce9 2007-07-21       drh:   }
bab8363876 2008-12-12   stephan:   return blob_buffer(&bl);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
bab8363876 2008-12-12   stephan: /*
0239325f58 2009-11-09       drh: ** Return true if the input string is a date in the ISO 8601 format:
0239325f58 2009-11-09       drh: ** YYYY-MM-DD.
0239325f58 2009-11-09       drh: */
0239325f58 2009-11-09       drh: static int isIsoDate(const char *z){
0239325f58 2009-11-09       drh:   return strlen(z)==10
0239325f58 2009-11-09       drh:       && z[4]=='-'
0239325f58 2009-11-09       drh:       && z[7]=='-'
0239325f58 2009-11-09       drh:       && isdigit(z[0])
0239325f58 2009-11-09       drh:       && isdigit(z[5]);
0239325f58 2009-11-09       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: timeline
dbda8d6ce9 2007-07-21       drh: **
0239325f58 2009-11-09       drh: ** Usage: %fossil timeline ?WHEN? ?BASELINE|DATETIME? ?-n N? ?-t TYPE?
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: ** Print a summary of activity going backwards in date and time
6607844a01 2007-08-18       drh: ** specified or from the current date and time if no arguments
abce5105e2 2007-09-01       drh: ** are given.  Show as many as N (default 20) check-ins.  The
abce5105e2 2007-09-01       drh: ** WHEN argument can be any unique abbreviation of one of these
abce5105e2 2007-09-01       drh: ** keywords:
abce5105e2 2007-09-01       drh: **
abce5105e2 2007-09-01       drh: **     before
abce5105e2 2007-09-01       drh: **     after
6458f020fc 2008-05-14       drh: **     descendants | children
abce5105e2 2007-09-01       drh: **     ancestors | parents
abce5105e2 2007-09-01       drh: **
e8c4f69c50 2008-10-24       drh: ** The BASELINE can be any unique prefix of 4 characters or more.
abce5105e2 2007-09-01       drh: ** The DATETIME should be in the ISO8601 format.  For
abce5105e2 2007-09-01       drh: ** examples: "2007-08-18 07:21:21".  You can also say "current"
abce5105e2 2007-09-01       drh: ** for the current version or "now" for the current time.
bab8363876 2008-12-12   stephan: **
bab8363876 2008-12-12   stephan: ** The optional TYPE argument may any types supported by the /timeline
bab8363876 2008-12-12   stephan: ** page. For example:
6607844a01 2007-08-18       drh: **
bab8363876 2008-12-12   stephan: **     w  = wiki commits only
bab8363876 2008-12-12   stephan: **     ci = file commits only
bab8363876 2008-12-12   stephan: **     t  = tickets only
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;
bab8363876 2008-12-12   stephan:   const char *zType;
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;
0239325f58 2009-11-09       drh:   int mode = 0 ;       /* 0:none  1: before  2:after  3:children  4:parents */
4e683ef07b 2008-05-05       drh:   db_find_and_open_repository(1);
bab8363876 2008-12-12   stephan:   zCount = find_option("count","n",1);
bab8363876 2008-12-12   stephan:   zType = find_option("type","t",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:   }
bab8363876 2008-12-12   stephan:   if( g.argc>=4 ){
abce5105e2 2007-09-01       drh:     k = strlen(g.argv[2]);
abce5105e2 2007-09-01       drh:     if( strncmp(g.argv[2],"before",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 1;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){
abce5105e2 2007-09-01       drh:       mode = 2;
6458f020fc 2008-05-14       drh:     }else if( strncmp(g.argv[2],"descendants",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 3;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"children",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 3;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){
abce5105e2 2007-09-01       drh:       mode = 4;
abce5105e2 2007-09-01       drh:     }else if( strncmp(g.argv[2],"parents",k)==0 ){
abce5105e2 2007-09-01       drh:       mode = 4;
bab8363876 2008-12-12   stephan:     }else if(!zType && !zCount){
bab8363876 2008-12-12   stephan:       usage("?WHEN? ?BASELINE|DATETIME? ?-n|--count N? ?-t TYPE?");
abce5105e2 2007-09-01       drh:     }
bab8363876 2008-12-12   stephan:     if( '-' != *g.argv[3] ){
bab8363876 2008-12-12   stephan: 	zOrigin = g.argv[3];
bab8363876 2008-12-12   stephan:     }else{
bab8363876 2008-12-12   stephan: 	zOrigin = "now";
bab8363876 2008-12-12   stephan:     }
abce5105e2 2007-09-01       drh:   }else if( g.argc==3 ){
abce5105e2 2007-09-01       drh:     zOrigin = g.argv[2];
abce5105e2 2007-09-01       drh:   }else{
abce5105e2 2007-09-01       drh:     zOrigin = "now";
6607844a01 2007-08-18       drh:   }
abce5105e2 2007-09-01       drh:   k = strlen(zOrigin);
abce5105e2 2007-09-01       drh:   blob_zero(&uuid);
abce5105e2 2007-09-01       drh:   blob_append(&uuid, zOrigin, -1);
abce5105e2 2007-09-01       drh:   if( strcmp(zOrigin, "now")==0 ){
abce5105e2 2007-09-01       drh:     if( mode==3 || mode==4 ){
6458f020fc 2008-05-14       drh:       fossil_fatal("cannot compute descendants or ancestors of a date");
abce5105e2 2007-09-01       drh:     }
aad573b31c 2007-09-24  mjanssen:     zDate = mprintf("(SELECT datetime('now'))");
abce5105e2 2007-09-01       drh:   }else if( strncmp(zOrigin, "current", k)==0 ){
c1e85e4da5 2008-07-13       drh:     if( !g.localOpen ){
c1e85e4da5 2008-07-13       drh:       fossil_fatal("must be within a local checkout to use 'current'");
c1e85e4da5 2008-07-13       drh:     }
abce5105e2 2007-09-01       drh:     objid = db_lget_int("checkout",0);
abce5105e2 2007-09-01       drh:     zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid);
abce5105e2 2007-09-01       drh:   }else if( name_to_uuid(&uuid, 0)==0 ){
abce5105e2 2007-09-01       drh:     objid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid);
abce5105e2 2007-09-01       drh:     zDate = mprintf("(SELECT mtime FROM plink WHERE cid=%d)", objid);
6607844a01 2007-08-18       drh:   }else{
e2431b17df 2009-11-09       drh:     const char *zShift = "";
abce5105e2 2007-09-01       drh:     if( mode==3 || mode==4 ){
6458f020fc 2008-05-14       drh:       fossil_fatal("cannot compute descendants or ancestors of a date");
6458f020fc 2008-05-14       drh:     }
0239325f58 2009-11-09       drh:     if( mode==0 ){
e2431b17df 2009-11-09       drh:       if( isIsoDate(zOrigin) ) zShift = ",'+1 day'";
abce5105e2 2007-09-01       drh:     }
e2431b17df 2009-11-09       drh:     zDate = mprintf("(SELECT julianday(%Q%s, 'utc'))", zOrigin, zShift);
6607844a01 2007-08-18       drh:   }
e2431b17df 2009-11-09       drh:   if( mode==0 ) mode = 1;
bab8363876 2008-12-12   stephan:   zSQL = mprintf("%z AND event.mtime %s %s",
bab8363876 2008-12-12   stephan:      timeline_query_for_tty_m(),
9395aba4f4 2007-09-22       drh:      (mode==1 || mode==4) ? "<=" : ">=",
9395aba4f4 2007-09-22       drh:      zDate
dbda8d6ce9 2007-07-21       drh:   );
abce5105e2 2007-09-01       drh:   if( mode==3 || mode==4 ){
abce5105e2 2007-09-01       drh:     db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
abce5105e2 2007-09-01       drh:     if( mode==3 ){
6458f020fc 2008-05-14       drh:       compute_descendants(objid, n);
abce5105e2 2007-09-01       drh:     }else{
abce5105e2 2007-09-01       drh:       compute_ancestors(objid, n);
abce5105e2 2007-09-01       drh:     }
abce5105e2 2007-09-01       drh:     zSQL = mprintf("%z AND blob.rid IN ok", zSQL);
abce5105e2 2007-09-01       drh:   }
bab8363876 2008-12-12   stephan:   if( zType && (zType[0]!='a') ){
bab8363876 2008-12-12   stephan:       zSQL = mprintf( "%z AND event.type=%Q ", zSQL, zType);
bab8363876 2008-12-12   stephan:   }
bab8363876 2008-12-12   stephan: 
abce5105e2 2007-09-01       drh:   zSQL = mprintf("%z ORDER BY event.mtime DESC", zSQL);
abce5105e2 2007-09-01       drh:   db_prepare(&q, zSQL);
bab8363876 2008-12-12   stephan:   free( zSQL );
6607844a01 2007-08-18       drh:   print_timeline(&q, n);
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
d23b8ba62b 2008-11-01       drh: }
d23b8ba62b 2008-11-01       drh: 
d23b8ba62b 2008-11-01       drh: /*
d23b8ba62b 2008-11-01       drh: ** This is a version of the "localtime()" function from the standard
d23b8ba62b 2008-11-01       drh: ** C library.  It converts a unix timestamp (seconds since 1970) into
d23b8ba62b 2008-11-01       drh: ** a broken-out local time structure.
d23b8ba62b 2008-11-01       drh: **
d23b8ba62b 2008-11-01       drh: ** This modified version of localtime() works like the library localtime()
d23b8ba62b 2008-11-01       drh: ** by default.  Except if the timeline-utc property is set, this routine
d23b8ba62b 2008-11-01       drh: ** uses gmttime() instead.  Thus by setting the timeline-utc property, we
d23b8ba62b 2008-11-01       drh: ** can get all localtimes to be displayed at UTC time.
d23b8ba62b 2008-11-01       drh: */
d23b8ba62b 2008-11-01       drh: struct tm *fossil_localtime(const time_t *clock){
0b36f02f15 2008-11-01       drh:   if( g.fTimeFormat==0 ){
0b36f02f15 2008-11-01       drh:     if( db_get_int("timeline-utc", 1) ){
0b36f02f15 2008-11-01       drh:       g.fTimeFormat = 1;
0b36f02f15 2008-11-01       drh:     }else{
0b36f02f15 2008-11-01       drh:       g.fTimeFormat = 2;
0b36f02f15 2008-11-01       drh:     }
d23b8ba62b 2008-11-01       drh:   }
0b36f02f15 2008-11-01       drh:   if( g.fTimeFormat==1 ){
d23b8ba62b 2008-11-01       drh:     return gmtime(clock);
d23b8ba62b 2008-11-01       drh:   }else{
d23b8ba62b 2008-11-01       drh:     return localtime(clock);
d23b8ba62b 2008-11-01       drh:   }
dbda8d6ce9 2007-07-21       drh: }