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
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
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 User:</th><td>%h(db_column_text(&q, 2))</td></tr> @ <tr><th>Original 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(); } /*