Check-in [2e84fb3e54]
Not logged in
Overview

SHA1 Hash:2e84fb3e544008c383c28b49580020d608983ca8
Date: 2008-02-27 04:15:47
User: aku
Comment:Merged with 82fc5abb60.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/descendents.c from [57da1765de] to [27267403dd].

@@ -196,15 +196,15 @@
     "   AND blob.rid IN"
     "       (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)"
     " ORDER BY event.mtime DESC",
     timeline_query_for_www()
   );
-  www_print_timeline(&q, 0, 0, 0, 0);
+  www_print_timeline(&q);
   db_finalize(&q);
   @ <script>
   @ function xin(id){
   @ }
   @ function xout(id){
   @ }
   @ </script>
   style_footer();
 }

Modified src/info.c from [20d5e8730b] to [54715d1400].

@@ -332,12 +332,13 @@
     }
     @ <tr><th>Original&nbsp;User:</th><td>%h(db_column_text(&q, 2))</td></tr>
     @ <tr><th>Original&nbsp;Comment:</th><td>%w(db_column_text(&q,3))</td></tr>
     @ </td></tr>
     @ <tr><th>Timelines:</th><td>
-    @    <a href="%s(g.zBaseURL)/timeline?e=%d(rid)&r">ancestors</a>
-    @    | <a href="%s(g.zBaseURL)/timeline?e=%d(rid)&r&a">descendents</a>
+    @    <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
+    @    | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendents</a>
+    @    | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
     @ </td></tr>
     @ <tr><th>Commands:</th>
     @   <td>
     @     <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
     @     | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a>

Modified src/stat.c from [3d9d623f94] to [d6479af2a2].


Modified src/timeline.c from [d5cc80fe9b] to [dea6e9f6b0].

@@ -89,17 +89,12 @@
 **    7.  True if is a leaf
 **    8.  background color
 **    9.  type ("ci", "w")
 */
 void www_print_timeline(
-  Stmt *pQuery,
-  int *pFirstEvent,
-  int *pLastEvent,
-  int (*xCallback)(int, Blob*),
-  Blob *pArg
- ){
-  int cnt = 0;
+  Stmt *pQuery
+ ){
   int wikiFlags;
   int mxWikiLen;
   Blob comment;
   char zPrevDate[20];
   zPrevDate[0] = 0;
@@ -125,21 +120,11 @@
     int isLeaf = db_column_int(pQuery, 7);
     const char *zBgClr = db_column_text(pQuery, 8);
     const char *zDate = db_column_text(pQuery, 2);
     const char *zType = db_column_text(pQuery, 9);
     const char *zUser = db_column_text(pQuery, 4);
-    if( cnt==0 && pFirstEvent ){
-      *pFirstEvent = rid;
-    }
-    cnt++;
-    if( pLastEvent ){
-      *pLastEvent = rid;
-    }
-    db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
-    if( xCallback ){
-      xCallback(rid, pArg);
-    }
+    db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
     if( memcmp(zDate, zPrevDate, 10) ){
       sprintf(zPrevDate, "%.10s", zDate);
       @ <tr><td colspan=3>
       @   <div class="divider">%s(zPrevDate)</div>
       @ </td></tr>
@@ -183,38 +168,28 @@
   }
   @ </table>
 }
 
 /*
-** Generate javascript code that records the parents and children
-** of the version rid.
+** Create a temporary table suitable for storing timeline data.
 */
-static int save_parentage_javascript(int rid, Blob *pOut){
-  const char *zSep;
-  Stmt q;
-
-  db_prepare(&q, "SELECT pid FROM plink WHERE cid=%d", rid);
-  zSep = "";
-  blob_appendf(pOut, "parentof[\"m%d\"] = [", rid);
-  while( db_step(&q)==SQLITE_ROW ){
-    int pid = db_column_int(&q, 0);
-    blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
-    zSep = ",";
-  }
-  db_finalize(&q);
-  blob_appendf(pOut, "];\n");
-  db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d", rid);
-  zSep = "";
-  blob_appendf(pOut, "childof[\"m%d\"] = [", rid);
-  while( db_step(&q)==SQLITE_ROW ){
-    int pid = db_column_int(&q, 0);
-    blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
-    zSep = ",";
-  }
-  db_finalize(&q);
-  blob_appendf(pOut, "];\n");
-  return 0;
+static void timeline_temp_table(void){
+  static const char zSql[] =
+    @ CREATE TEMP TABLE IF NOT EXISTS timeline(
+    @   rid INTEGER PRIMARY KEY,
+    @   uuid TEXT,
+    @   timestamp TEXT,
+    @   comment TEXT,
+    @   user TEXT,
+    @   nchild INTEGER,
+    @   nparent INTEGER,
+    @   isleaf BOOLEAN,
+    @   bgcolor TEXT,
+    @   etype TEXT
+    @ )
+  ;
+  db_multi_exec(zSql);
 }
 
 /*
 ** Return a pointer to a constant string that forms the basis
 ** for a timeline query for the WWW interface.
@@ -241,36 +216,37 @@
 /*
 ** WEBPAGE: timeline
 **
 ** Query parameters:
 **
-**    d=STARTDATE    date in iso8601 notation.          dflt: newest event
-**    n=INTEGER      number of events to show.          dflt: 25
-**    e=INTEGER      starting event id.                 dflt: nil
-**    u=NAME         show only events from user.        dflt: nil
-**    a              show events after and including.   dflt: false
-**    r              show only related events.          dflt: false
-**    y=TYPE         show only TYPE ('ci' or 'w')       dflt: nil
-**    s              show the SQL                       dflt: nil
+**    a=TIMESTAMP    after this date
+**    b=TIMESTAMP    before this date.
+**    n=COUNT        number of events in output
+**    p=RID          artifact RID and up to COUNT parents and ancestors
+**    d=RID          artifact RID and up to COUNT descendents
+**    u=USER         only if belonging to this user
+**    y=TYPE         'ci', 'w', 'tkt'
+**
+** p= and d= can appear individually or together.  If either p= or d=
+** appear, then u=, y=, a=, and b= are ignored.
+**
+** If a= and b= appear, only a= is used.  If neither appear, the most
+** recent events are choosen.
+**
+** If n= is missing, the default count is 20.
 */
 void page_timeline(void){
-  Stmt q;
-  Blob sql;                    /* text of SQL used to generate timeline */
-  char *zSQL;                  /* Rendered copy of sql */
-  Blob scriptInit;
-  char zDate[100];
-  const char *zStart = P("d");       /* Starting date */
+  Stmt q;                            /* Query used to generate the timeline */
+  Blob sql;                          /* text of SQL used to generate timeline */
+  Blob desc;                         /* Description of the timeline */
   int nEntry = atoi(PD("n","20"));   /* Max number of entries on timeline */
+  int p_rid = atoi(PD("p","0"));     /* artifact p and its parents */
+  int d_rid = atoi(PD("d","0"));     /* artifact d and its descendents */
   const char *zUser = P("u");        /* All entries by this user if not NULL */
-  int objid = atoi(PD("e","0"));     /* Entries related to this event */
-  int relatedEvents = P("r")!=0;     /* Must be directly related to of objid */
-  int afterFlag = P("a")!=0;         /* After objid if true */
   const char *zType = P("y");        /* Type of events.  All if NULL */
-  int firstEvent;              /* First event displayed */
-  int lastEvent;               /* Last event displayed */
-  Blob desc;                   /* Human readable description of the timeline */
-  const char *zEType;          /* Human readable event type */
+  const char *zAfter = P("a");       /* Events after this time */
+  const char *zBefore = P("b");      /* Events before this time */
 
   /* To view the timeline, must have permission to read project data.
   */
   login_check_credentials();
   if( !g.okRead ){ login_needed(); return; }
@@ -281,100 +257,158 @@
                 " WHERE login='anonymous'"
                 "   AND cap LIKE '%%h%%'") ){
     @ <p><b>Note:</b> You will be able to access <u>much</u> more
     @ historical information if you <a href="%s(g.zTop)/login">login</a>.</p>
   }
+  timeline_temp_table();
   blob_zero(&sql);
   blob_zero(&desc);
+  blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
   blob_append(&sql, timeline_query_for_www(), -1);
-  zEType = "events";
-  if( zType ){
-    blob_appendf(&sql, " AND event.type=%Q", zType);
-    if( zType[0]=='c' ){
-      zEType = "checkins";
-    }else if( zType[0]=='w' ){
-      zEType = "wiki edits";
-    }
-  }
-  blob_appendf(&desc, "Timeline of up to %d %s", nEntry, zEType);
-  if( zUser ){
-    blob_appendf(&sql, " AND event.user=%Q", zUser);
-    blob_appendf(&desc, " by user %h", zUser);
-  }
-  if( objid ){
-    char *z = db_text(0, "SELECT datetime(event.mtime, 'localtime') FROM event"
-                         " WHERE objid=%d", objid);
-    if( z ){
-      zStart = z;
-    }
-  }
-  if( zStart ){
-    while( isspace(zStart[0]) ){ zStart++; }
-    if( zStart[0] ){
-      blob_appendf(&sql,
-         " AND event.mtime %s (SELECT julianday(%Q, 'utc'))",
-                          afterFlag ? ">=" : "<=", zStart);
-      blob_appendf(&desc, " occurring on or %s %h",
-          afterFlag ? "after": "before",
-          zStart);
-    }
-  }
-  if( relatedEvents && objid ){
+  if( p_rid || d_rid ){
+    /* If p= or d= is present, ignore all other parameters other than n= */
     char *zUuid;
+    int np, nd;
+
+    if( p_rid && d_rid && p_rid!=d_rid ) p_rid = d_rid;
     db_multi_exec(
        "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
     );
-    zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", objid);
-    if( afterFlag ){
-      compute_descendents(objid, nEntry);
-      blob_appendf(&desc,
-         " and decended from <a href='%s/vinfo/%d'>[%.10s]</a>",
-         g.zBaseURL, objid, zUuid);
-    }else{
-      compute_ancestors(objid, nEntry);
-      blob_appendf(&desc,
-         " and a ancestor of <a href='%s/vinfo/%d'>[%.10s]</a>",
-         g.zBaseURL, objid, zUuid);
-    }
-    blob_append(&sql, " AND event.objid IN ok", -1);
-  }
-  if( afterFlag ){
-    blob_appendf(&sql, " ORDER BY event.mtime ASC LIMIT %d",
-                 nEntry);
+    zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d",
+                         p_rid ? p_rid : d_rid);
+    blob_appendf(&sql, " AND event.objid IN ok");
+    nd = 0;
+    if( d_rid ){
+      compute_descendents(d_rid, nEntry);
+      nd = db_int(0, "SELECT count(*)-1 FROM ok");
+      if( nd>0 ){
+        db_multi_exec("%s", blob_str(&sql));
+        blob_appendf(&desc, "%d descendents", nd);
+      }
+      db_multi_exec("DELETE FROM ok");
+    }
+    if( p_rid ){
+      compute_ancestors(p_rid, nEntry);
+      np = db_int(0, "SELECT count(*)-1 FROM ok");
+      if( np>0 ){
+        if( nd>0 ) blob_appendf(&desc, " and ");
+        blob_appendf(&desc, "%d ancestors", np);
+        db_multi_exec("%s", blob_str(&sql));
+      }
+    }
+    blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
+                 g.zBaseURL, zUuid, zUuid);
+    db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
   }else{
-    blob_appendf(&sql, " ORDER BY event.mtime DESC LIMIT %d",
-                 nEntry);
-  }
-  zSQL = blob_str(&sql);
-  if( afterFlag ){
-    zSQL = mprintf("SELECT * FROM (%s) ORDER BY timestamp DESC", zSQL);
+    int n;
+    Blob url;
+    const char *zEType = "event";
+    const char *zDate;
+    blob_zero(&url);
+    blob_appendf(&url, "%s/timeline?n=%d", g.zBaseURL, nEntry);
+    if( zType ){
+      blob_appendf(&sql, " AND event.type=%Q", zType);
+      blob_appendf(&url, "&y=%T", zType);
+      if( zType[0]=='c' ){
+        zEType = "checkin";
+      }else if( zType[0]=='w' ){
+        zEType = "wiki edit";
+      }else if( zType[0]=='t' ){
+        zEType = "ticket change";
+      }
+    }
+    if( zUser ){
+      blob_appendf(&sql, " AND event.user=%Q", zUser);
+      blob_appendf(&url, "&u=%T", zUser);
+    }
+    if( zAfter ){
+      while( isspace(zAfter[0]) ){ zAfter++; }
+      if( zAfter[0] ){
+        blob_appendf(&sql,
+           " AND event.mtime>=(SELECT julianday(%Q, 'utc'))"
+           " ORDER BY event.mtime ASC", zAfter);
+        zBefore = 0;
+      }else{
+        zAfter = 0;
+      }
+    }else if( zBefore ){
+      while( isspace(zBefore[0]) ){ zBefore++; }
+      if( zBefore[0] ){
+        blob_appendf(&sql,
+           " AND event.mtime<=(SELECT julianday(%Q, 'utc'))"
+           " ORDER BY event.mtime DESC", zBefore);
+       }else{
+        zBefore = 0;
+      }
+    }else{
+      blob_appendf(&sql, " ORDER BY event.mtime DESC");
+    }
+    blob_appendf(&sql, " LIMIT %d", nEntry);
+    db_multi_exec("%s", blob_str(&sql));
+
+    n = db_int(0, "SELECT count(*) FROM timeline");
+    if( zAfter==0 && zBefore==0 ){
+      blob_appendf(&desc, "%d most recent %ss", n, zEType);
+    }else{
+      blob_appendf(&desc, "%d %ss", n, zEType);
+    }
+    if( zUser ){
+      blob_appendf(&desc, " by user %h", zUser);
+    }
+    if( zAfter ){
+      blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
+    }else if( zBefore ){
+      blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
+    }
+    if( zAfter || n==nEntry ){
+      zDate = db_text(0, "SELECT min(timestamp) FROM timeline");
+      blob_appendf(&desc, " <a href='%b&b=%s'>[older]</a>", &url, zDate);
+    }
+    if( zBefore || (zAfter && n==nEntry) ){
+      zDate = db_text(0, "SELECT max(timestamp) FROM timeline");
+      blob_appendf(&desc, " <a href='%b&a=%s'>[more recent]</a>", &url, zDate);
+    }
   }
-  db_prepare(&q, zSQL);
-  if( P("s")!=0 ){
-    @ <hr><p>%h(zSQL)</p><hr>
-  }
+  blob_zero(&sql);
+  db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
   @ <h2>%b(&desc)</h2>
   blob_reset(&desc);
-  blob_zero(&sql);
-  if( afterFlag ){
-    free(zSQL);
-  }
-  zDate[0] = 0;
-  blob_zero(&scriptInit);
-  zDate[0] = 0;
-  www_print_timeline(&q, &firstEvent, &lastEvent,
-                     save_parentage_javascript, &scriptInit);
+  www_print_timeline(&q);
   db_finalize(&q);
-  /* @ <p>firstEvent=%d(firstEvent) lastEvent=%d(lastEvent)</p> */
-  if( zStart==0 ){
-    zStart = zDate;
-  }
+
   @ <script>
   @ var parentof = new Object();
   @ var childof = new Object();
-  cgi_append_content(blob_buffer(&scriptInit), blob_size(&scriptInit));
-  blob_reset(&scriptInit);
+  db_prepare(&q, "SELECT rid FROM timeline");
+  while( db_step(&q)==SQLITE_ROW ){
+    int rid = db_column_int(&q, 0);
+    Stmt q2;
+    const char *zSep;
+    Blob *pOut = cgi_output_blob();
+
+    db_prepare(&q2, "SELECT pid FROM plink WHERE cid=%d", rid);
+    zSep = "";
+    blob_appendf(pOut, "parentof[\"m%d\"] = [", rid);
+    while( db_step(&q2)==SQLITE_ROW ){
+      int pid = db_column_int(&q2, 0);
+      blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
+      zSep = ",";
+    }
+    db_finalize(&q2);
+    blob_appendf(pOut, "];\n");
+    db_prepare(&q2, "SELECT cid FROM plink WHERE pid=%d", rid);
+    zSep = "";
+    blob_appendf(pOut, "childof[\"m%d\"] = [", rid);
+    while( db_step(&q2)==SQLITE_ROW ){
+      int pid = db_column_int(&q2, 0);
+      blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
+      zSep = ",";
+    }
+    db_finalize(&q2);
+    blob_appendf(pOut, "];\n");
+  }
+  db_finalize(&q);
   @ function setall(value){
   @   for(var x in parentof){
   @     setone(x,value);
   @   }
   @ }
@@ -431,30 +465,10 @@
   @       set_children(cid,clr);
   @     }
   @   }
   @ }
   @ </script>
-  @ <hr>
-  @ <form method="GET" action="%s(g.zBaseURL)/timeline">
-  @ Start Date:
-  @ <input type="text" size="30" value="%h(zStart)" name="d">
-  @ Number Of Entries:
-  @ <input type="text" size="4" value="%d(nEntry)" name="n">
-  @ <br><input type="submit" value="Submit">
-  @ </form>
-  @ <table><tr><td>
-  @ <form method="GET" action="%s(g.zBaseURL)/timeline">
-  @ <input type="hidden" value="%d(lastEvent)" name="e">
-  @ <input type="hidden" value="%d(nEntry)" name="n">
-  @ <input type="submit" value="Next %d(nEntry) Rows">
-  @ </form></td><td>
-  @ <form method="GET" action="%s(g.zBaseURL)/timeline">
-  @ <input type="hidden" value="%d(firstEvent)" name="e">
-  @ <input type="hidden" value="%d(nEntry)" name="n">
-  @ <input type="hidden" value="1" name="a">
-  @ <input type="submit" value="Previous %d(nEntry) Rows">
-  @ </form></td></tr></table>
   style_footer();
 }
 
 /*
 ** The input query q selects various records.  Print a human-readable

Modified src/wiki.c from [bddf828de5] to [4fe3239f97].

@@ -463,11 +463,11 @@
                        "(SELECT tagid FROM tag WHERE tagname='wiki-%q'))"
                  "ORDER BY mtime DESC",
                  timeline_query_for_www(), zPageName);
   db_prepare(&q, zSQL);
   free(zSQL);
-  www_print_timeline(&q, 0, 0, 0, 0);
+  www_print_timeline(&q);
   db_finalize(&q);
   style_footer();
 }
 
 /*