Diff
Not logged in

Differences From:

File src/timeline.c part of check-in [b846db063c] - Changes to the CLI version of the timeline command to show places where forks occur in the tree and where content is merged. Lots more work is needed to show the structure of a tree well. This is definitely a work in progress. by drh on 2007-08-25 18:51:54. Also file src/timeline.c part of check-in [b0ad3f90bc] - Merging aku's changes into the head. by drh on 2007-08-25 19:00:33. [view]

To:

File src/timeline.c part of check-in [e12f2f1839] - Tweaked the highlighting by aku on 2007-08-27 13:21:20. Also file src/timeline.c part of check-in [15652ff081] - Merged drh's fixes new features (xfer, timeline handling, javascript based timeline highlighting) into my branch. by aku on 2007-08-29 02:55:33. [view]

@@ -40,8 +40,24 @@
   }
 }
 
 /*
+** Generate a hyperlink that invokes javascript to highlight
+** a version on mouseover.
+*/
+void hyperlink_to_uuid_with_highlight(const char *zUuid, int id){
+  char zShortUuid[UUID_SIZE+1];
+  sprintf(zShortUuid, "%.10s", zUuid);
+  if( g.okHistory ){
+    @ <a onmouseover='hilite("m%d(id)")' onmouseout='unhilite("m%d(id)")'
+    @    href="%s(g.zBaseURL)/vinfo/%s(zUuid)">[%s(zShortUuid)]</a>
+  }else{
+    @ <b onmouseover='hilite("m%d(id)")' onmouseout='unhilite("m%d(id)")'>
+    @ [%s(zShortUuid)]</b>
+  }
+}
+
+/*
 ** Generate a hyperlink to a diff between two versions.
 */
 void hyperlink_to_diff(const char *zV1, const char *zV2){
   if( g.okHistory ){
@@ -56,19 +72,35 @@
 /*
 ** Output a timeline in the web format given a query.  The query
 ** should return 4 columns:
 **
-**    0.  UUID
-**    1.  Date/Time
-**    2.  Comment string
-**    3.  User
+**    0.  rid
+**    1.  UUID
+**    2.  Date/Time
+**    3.  Comment string
+**    4.  User
+**    5.  Number of non-merge children
+**    6.  Number of parents
+**    7.  True if is a leaf
 */
-void www_print_timeline(Stmt *pQuery, char *zLastDate){
+void www_print_timeline(
+  Stmt *pQuery,
+  char *zLastDate,
+  int (*xCallback)(int, Blob*),
+  Blob *pArg
+ ){
   char zPrevDate[20];
   zPrevDate[0] = 0;
   @ <table cellspacing=0 border=0 cellpadding=0>
   while( db_step(pQuery)==SQLITE_ROW ){
-    const char *zDate = db_column_text(pQuery, 1);
+    int rid = db_column_int(pQuery, 0);
+    int nPChild = db_column_int(pQuery, 5);
+    int nParent = db_column_int(pQuery, 6);
+    int isLeaf = db_column_int(pQuery, 7);
+    const char *zDate = db_column_text(pQuery, 2);
+    if( xCallback ){
+      xCallback(rid, pArg);
+    }
     if( memcmp(zDate, zPrevDate, 10) ){
       sprintf(zPrevDate, "%.10s", zDate);
       @ <tr><td colspan=3>
       @ <table cellpadding=2 border=0>
@@ -78,28 +110,94 @@
       @ </tr></table>
       @ </td></tr></table>
       @ </td></tr>
     }
-    @ <tr><td valign="top">%s(&zDate[11])</td>
+    @ <tr id="m%d(rid)" onmouseover='xin("m%d(rid)")'
+    @     onmouseout='xout("m%d(rid)")'>
+    @ <td valign="top">%s(&zDate[11])</td>
     @ <td width="20"></td>
     @ <td valign="top" align="left">
-    hyperlink_to_uuid(db_column_text(pQuery,0));
-    @ %h(db_column_text(pQuery,2)) (by %h(db_column_text(pQuery,3)))</td>
+    hyperlink_to_uuid(db_column_text(pQuery,1));
+    @ %h(db_column_text(pQuery,3))
+    if( nParent>1 ){
+      Stmt q;
+      @ <b>Merge</b> from
+      db_prepare(&q,
+        "SELECT rid, uuid FROM plink, blob"
+        " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim=0",
+        rid
+      );
+      while( db_step(&q)==SQLITE_ROW ){
+        int mrid = db_column_int(&q, 0);
+        const char *zUuid = db_column_text(&q, 1);
+        hyperlink_to_uuid_with_highlight(zUuid, mrid);
+      }
+      db_finalize(&q);
+    }
+    if( nPChild>1 ){
+      Stmt q;
+      @ <b>Fork</b> to
+      db_prepare(&q,
+        "SELECT rid, uuid FROM plink, blob"
+        " WHERE plink.pid=%d AND blob.rid=plink.cid AND plink.isprim>0",
+        rid
+      );
+      while( db_step(&q)==SQLITE_ROW ){
+        int frid = db_column_int(&q, 0);
+        const char *zUuid = db_column_text(&q, 1);
+        hyperlink_to_uuid_with_highlight(zUuid, frid);
+      }
+      db_finalize(&q);
+    }
+    if( isLeaf ){
+      @ <b>Leaf</b>
+    }
+    @ (by %h(db_column_text(pQuery,4)))</td></tr>
     if( zLastDate ){
       strcpy(zLastDate, zDate);
     }
   }
   @ </table>
 }
 
+/*
+** Generate javascript code that records the parents and children
+** of the version rid.
+*/
+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;
+}
 
 /*
 ** WEBPAGE: timeline
 */
 void page_timeline(void){
   Stmt q;
   char *zSQL;
+  Blob scriptInit;
   char zDate[100];
   const char *zStart = P("d");
   int nEntry = atoi(PD("n","25"));
 
@@ -116,9 +214,12 @@
     @ <p><b>Note:</b> You will be able to access <u>much</u> more
     @ historical information if <a href="%s(g.zBaseURL)/login">login</a>.</p>
   }
   zSQL = mprintf(
-    "SELECT uuid, datetime(event.mtime,'localtime'), comment, user"
+    "SELECT blob.rid, uuid, datetime(event.mtime,'localtime'), comment, user,"
+    "       (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim=1),"
+    "       (SELECT count(*) FROM plink WHERE cid=blob.rid),"
+    "       NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid)"
     "  FROM event, blob"
     " WHERE event.type='ci' AND blob.rid=event.objid"
   );
   if( zStart ){
@@ -131,13 +232,73 @@
   zSQL = mprintf("%z ORDER BY event.mtime DESC LIMIT %d", zSQL, nEntry);
   db_prepare(&q, zSQL);
   free(zSQL);
   zDate[0] = 0;
-  www_print_timeline(&q, zDate);
+  blob_zero(&scriptInit);
+  www_print_timeline(&q, zDate, save_parentage_javascript, &scriptInit);
   db_finalize(&q);
   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);
+  @ function setall(value){
+  @   for(var x in parentof){
+  @     setone(x,value);
+  @   }
+  @ }
+  @ function setone(id, onoff){
+  @   if( parentof[id]==null ) return 0;
+  @   var w = document.getElementById(id);
+  @   var clr = onoff==1 ? "#e0e0ff" : "#ffffff";
+  @   if( w.backgroundColor==clr ){
+  @     return 0
+  @   }else{
+  @     w.style.backgroundColor = clr
+  @     return 1
+  @   }
+  @ }
+  @ function xin(id) {
+  @   setall(0);
+  @   setone(id,1);
+  @   set_children(id);
+  @   set_parents(id);
+  @ }
+  @ function xout(id) {
+  @   setall(0);
+  @ }
+  @ function set_parents(id){
+  @   var plist = parentof[id];
+  @   if( plist==null ) return;
+  @   for(var x in plist){
+  @     var pid = plist[x];
+  @     if( setone(pid,1)==1 ){
+  @       set_parents(pid);
+  @     }
+  @   }
+  @ }
+  @ function set_children(id){
+  @   var clist = childof[id];
+  @   if( clist==null ) return;
+  @   for(var x in clist){
+  @     var cid = clist[x];
+  @     if( setone(cid,1)==1 ){
+  @       set_children(cid);
+  @     }
+  @   }
+  @ }
+  @ function hilite(id) {
+  @   var x = document.getElementById(id);
+  @   x.style.color = "#ff0000";
+  @ }
+  @ function unhilite(id) {
+  @   var x = document.getElementById(id);
+  @   x.style.color = "#000000";
+  @ }
+  @ </script>
   @ <hr>
   @ <form method="GET" action="%s(g.zBaseURL)/timeline">
   @ Start Date:
   @ <input type="text" size="30" value="%h(zStart)" name="d">