Check-in [5e2392307d]
Not logged in
Overview

SHA1 Hash:5e2392307d800c3fda2610e42f7b6fed545d1ff5
Date: 2007-09-22 01:40:39
User: drh
Comment:Turn tags into properties. Allow properties to control background color on timelines. Still experimental.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/descendents.c from [fc1b9b6b12] to [f44f14d0b6].

@@ -196,11 +196,11 @@
   if( !g.okRead ){ login_needed(); return; }
 
   style_header("Leaves");
   db_prepare(&q,
     "SELECT blob.rid, blob.uuid, datetime(event.mtime,'localtime'),"
-    "       event.comment, event.user, 1, 1, 0"
+    "       event.comment, event.user, 1, 1, 0, NULL"
     "  FROM blob, event"
     " WHERE blob.rid IN"
     "       (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)"
     "   AND event.objid=blob.rid"
     " ORDER BY event.mtime DESC"

Modified src/schema.c from [7e3c94d41e] to [c58feea55a].

@@ -200,20 +200,25 @@
 @ CREATE TABLE tag(
 @   tagid INTEGER PRIMARY KEY,       -- Numeric tag ID
 @   tagname TEXT UNIQUE              -- Tag name.  Prefixed by 'v' or 'b'
 @ );
 @
-@ -- Assignments of tags to baselines
+@ -- Assignments of tags to baselines.  Note that we allow tags to
+@ -- have values assigned to them.  So we are not really dealing with
+@ -- tags here.  These are really properties.  But we are going to
+@ -- keep calling them tags because in many cases the value is ignored.
 @ --
 @ CREATE TABLE tagxref(
 @   tagid INTEGER REFERENCES tag,   -- The tag that added or removed
 @   addFlag BOOLEAN,                -- True to add the tag, False to remove
 @   srcid INTEGER REFERENCES blob,  -- Origin of the tag. 0 for propagated tags
+@   value TEXT,                     -- Value of the tag.  Might be NULL.
 @   mtime TIMESTAMP,                -- Time of addition or removal
 @   rid INTEGER REFERENCE blob,     -- Baseline that tag added/removed from
 @   UNIQUE(rid, tagid)
 @ );
+@ CREATE INDEX tagxref_i1 ON tagxref(tagid);
 ;
 
 /*
 ** The schema for the locate FOSSIL database file found at the root
 ** of very check-out.  This database contains the complete state of

Modified src/tag.c from [51309dc47d] to [2d541bbe04].

@@ -35,31 +35,33 @@
 **
 ** If addFlag is true then the tag is added.  If false, then the
 ** tag is removed.
 */
 void tag_propagate(
-  int pid,         /* Propagate the tag to children of this node */
-  int tagid,       /* Tag to propagate */
-  int addFlag,     /* True to add the tag. False to delete it. */
-  double mtime     /* Timestamp on the tag */
+  int pid,             /* Propagate the tag to children of this node */
+  int tagid,           /* Tag to propagate */
+  int addFlag,         /* True to add the tag. False to delete it. */
+  const char *zValue,  /* Value of the tag.  Might be NULL */
+  double mtime         /* Timestamp on the tag */
 ){
   PQueue queue;
   Stmt s, ins;
   pqueue_init(&queue);
   pqueue_insert(&queue, pid, 0.0);
   db_prepare(&s,
-     "SELECT cid, mtime, coalesce(srcid=0 AND mtime<:mtime, %d) AS doit"
+     "SELECT cid, plink.mtime,"
+     "       coalesce(srcid=0 AND tagxref.mtime<:mtime, %d) AS doit"
      "  FROM plink LEFT JOIN tagxref ON cid=rid AND tagid=%d"
      " WHERE pid=:pid AND isprim",
      addFlag, tagid
   );
   db_bind_double(&s, ":mtime", mtime);
   if( addFlag ){
     db_prepare(&ins,
-       "REPLACE INTO tagxref(tagid, addFlag, srcid, mtime, rid)"
-       "VALUES(%d,1,0,:mtime,:rid)",
-       tagid
+       "REPLACE INTO tagxref(tagid, addFlag, srcid, value, mtime, rid)"
+       "VALUES(%d,1,0,%Q,:mtime,:rid)",
+       tagid, zValue
     );
     db_bind_double(&ins, ":mtime", mtime);
   }else{
     db_prepare(&ins,
        "DELETE FROM tagxref WHERE tagid=%d AND rid=:rid", tagid
@@ -89,18 +91,73 @@
 ** Propagate all propagatable tags in pid to its children.
 */
 void tag_propagate_all(int pid){
   Stmt q;
   db_prepare(&q,
-     "SELECT tagid, addflag, mtime FROM tagxref"
+     "SELECT tagid, addflag, mtime, value FROM tagxref"
      " WHERE rid=%d"
      "   AND (SELECT tagname FROM tag WHERE tagid=tagxref.tagid) LIKE 'br%'",
      pid
   );
   while( db_step(&q)==SQLITE_ROW ){
     int tagid = db_column_int(&q, 0);
     int addflag = db_column_int(&q, 1);
     double mtime = db_column_double(&q, 2);
-    tag_propagate(pid, tagid, addflag, mtime);
+    const char *zValue = db_column_text(&q, 3);
+    tag_propagate(pid, tagid, addflag, zValue, mtime);
   }
   db_finalize(&q);
+}
+
+/*
+** Get a tagid for the given TAG.  Create a new tag if necessary
+** if createFlag is 1.
+*/
+int tag_findid(const char *zTag, int createFlag){
+  int id;
+  id = db_int(0, "SELECT tagid FROM tag WHERE tagname=%Q", zTag);
+  if( id==0 && createFlag ){
+    db_multi_exec("INSERT INTO tag(tagname) VALUES(%Q)", zTag);
+    id = db_last_insert_rowid();
+  }
+  return id;
+}
+
+
+/*
+** COMMAND: test-addtag
+** %fossil test-addtag TAGNAME UUID ?VALUE?
+**
+** Add a tag to the rebuildable tables of the local repository.
+** No tag artifact is created so the new tag is erased the next
+** time the repository is rebuilt.  This routine is for testing
+** use only.
+*/
+void addtag_cmd(void){
+  const char *zTag;
+  const char *zValue;
+  int tagid;
+  int rid;
+  double now;
+  db_must_be_within_tree();
+  if( g.argc!=4 && g.argc!=5 ){
+    usage("TAGNAME UUID ?VALUE?");
+  }
+  zTag = g.argv[2];
+  rid = name_to_rid(g.argv[3]);
+  if( rid==0 ){
+    fossil_fatal("no such object: %s", g.argv[3]);
+  }
+  db_begin_transaction();
+  tagid = tag_findid(zTag, 1);
+  zValue = g.argc==5 ? g.argv[4] : 0;
+  db_multi_exec(
+    "REPLACE INTO tagxref(tagid,addFlag,srcId,value,mtime,rid)"
+    " VALUES(%d,1,-1,%Q,julianday('now'),%d)",
+    tagid, rid, zValue, rid
+  );
+  if( strncmp(zTag, "br", 2)==0 ){
+    now = db_double(0.0, "SELECT julianday('now')");
+    tag_propagate(rid, tagid, 1, zValue, now);
+  }
+  db_end_transaction(0);
 }

Modified src/timeline.c from [44b7795660] to [aa66611fa0].

@@ -85,10 +85,11 @@
 **    3.  Comment string
 **    4.  User
 **    5.  Number of non-merge children
 **    6.  Number of parents
 **    7.  True if is a leaf
+**    8.  background color
 */
 void www_print_timeline(
   Stmt *pQuery,
   int *pFirstEvent,
   int *pLastEvent,
@@ -96,10 +97,11 @@
   Blob *pArg
  ){
   char zPrevDate[20];
   int cnt = 0;
   zPrevDate[0] = 0;
+
   db_multi_exec(
      "CREATE TEMP TABLE IF NOT EXISTS seen(rid INTEGER PRIMARY KEY);"
      "DELETE FROM seen;"
   );
   @ <table cellspacing=0 border=0 cellpadding=0>
@@ -107,10 +109,11 @@
     int rid = db_column_int(pQuery, 0);
     const char *zUuid = db_column_text(pQuery, 1);
     int nPChild = db_column_int(pQuery, 5);
     int nParent = db_column_int(pQuery, 6);
     int isLeaf = db_column_int(pQuery, 7);
+    const char *zBgClr = db_column_text(pQuery, 8);
     const char *zDate = db_column_text(pQuery, 2);
     if( cnt==0 && pFirstEvent ){
       *pFirstEvent = rid;
     }
     if( pLastEvent ){
@@ -133,11 +136,15 @@
     }
     @ <tr>
     @ <td valign="top">%s(&zDate[11])</td>
     @ <td width="20" align="center" valign="top">
     @ <font id="m%d(rid)" size="+1" color="white">*</font></td>
-    @ <td valign="top" align="left">
+    if( zBgClr && zBgClr[0] ){
+      @ <td valign="top" align="left" bgcolor="%h(zBgClr)">
+    }else{
+      @ <td valign="top" align="left">
+    }
     hyperlink_to_uuid_with_mouseover(zUuid, "xin", "xout", rid);
     if( nParent>1 ){
       @ <b>Merge</b>
     }
     if( nPChild>1 ){
@@ -206,17 +213,20 @@
   int objid = atoi(PD("e","0"));
   int relatedEvents = P("r")!=0;
   int afterFlag = P("a")!=0;
   int firstEvent;
   int lastEvent;
+  int clr1, clr2;     /* Tag IDs for specifying background colors */
 
   /* To view the timeline, must have permission to read project data.
   */
   login_check_credentials();
   if( !g.okRead ){ login_needed(); return; }
 
   style_header("Timeline");
+  clr1 = db_int(0, "SELECT tagid FROM tag WHERE tagname='br-bg-color'");
+  clr2 = db_int(0, "SELECT tagid FROM tag WHERE tagname='bg-color'");
   if( !g.okHistory &&
       db_exists("SELECT 1 FROM user"
                 " WHERE login='anonymous'"
                 "   AND cap LIKE '%%h%%'") ){
     @ <p><b>Note:</b> You will be able to access <u>much</u> more
@@ -224,13 +234,16 @@
   }
   zSQL = mprintf(
     "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"
+    "       NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid),"
+    "       (SELECT value FROM tagxref WHERE rid=blob.rid AND tagid=%d"
+    "        UNION ALL"
+    "        SELECT value FROM tagxref WHERE rid=blob.rid AND tagid=%d)"
+    "  FROM event JOIN blob"
+    " WHERE event.type='ci' AND blob.rid=event.objid", clr2, clr1
   );
   if( zUser ){
     zSQL = mprintf("%z AND event.user=%Q", zSQL, zUser);
   }
   if( objid ){