Fossil SCM

Implement a graph of changes in the timeline to replace the older flashing asterisk mechanism. Does not work on IE6. Probably still contains bugs.

drh 2010-02-08 16:12 trunk
Commit d89fea6a1c0823aa72d8bf5042bf10b02798ad42
+4 -1
--- src/delta.c
+++ src/delta.c
@@ -30,10 +30,11 @@
3030
*/
3131
#include <stdio.h>
3232
#include <assert.h>
3333
#include <stdlib.h>
3434
#include <string.h>
35
+#include "delta.h"
3536
3637
/*
3738
** Macros for turning debugging printfs on and off
3839
*/
3940
#if 0
@@ -62,11 +63,11 @@
6263
}
6364
#else
6465
# define DEBUG2(X)
6566
#endif
6667
67
-
68
+#if INTERFACE
6869
/*
6970
** The "u32" type must be an unsigned 32-bit integer. Adjust this
7071
*/
7172
typedef unsigned int u32;
7273
@@ -73,10 +74,12 @@
7374
/*
7475
** Must be a 16-bit value
7576
*/
7677
typedef short int s16;
7778
typedef unsigned short int u16;
79
+
80
+#endif /* INTERFACE */
7881
7982
/*
8083
** The width of a hash window in bytes. The algorithm only works if this
8184
** is a power of 2.
8285
*/
8386
8487
ADDED src/graph.c
--- src/delta.c
+++ src/delta.c
@@ -30,10 +30,11 @@
30 */
31 #include <stdio.h>
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
 
35
36 /*
37 ** Macros for turning debugging printfs on and off
38 */
39 #if 0
@@ -62,11 +63,11 @@
62 }
63 #else
64 # define DEBUG2(X)
65 #endif
66
67
68 /*
69 ** The "u32" type must be an unsigned 32-bit integer. Adjust this
70 */
71 typedef unsigned int u32;
72
@@ -73,10 +74,12 @@
73 /*
74 ** Must be a 16-bit value
75 */
76 typedef short int s16;
77 typedef unsigned short int u16;
 
 
78
79 /*
80 ** The width of a hash window in bytes. The algorithm only works if this
81 ** is a power of 2.
82 */
83
84 DDED src/graph.c
--- src/delta.c
+++ src/delta.c
@@ -30,10 +30,11 @@
30 */
31 #include <stdio.h>
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "delta.h"
36
37 /*
38 ** Macros for turning debugging printfs on and off
39 */
40 #if 0
@@ -62,11 +63,11 @@
63 }
64 #else
65 # define DEBUG2(X)
66 #endif
67
68 #if INTERFACE
69 /*
70 ** The "u32" type must be an unsigned 32-bit integer. Adjust this
71 */
72 typedef unsigned int u32;
73
@@ -73,10 +74,12 @@
74 /*
75 ** Must be a 16-bit value
76 */
77 typedef short int s16;
78 typedef unsigned short int u16;
79
80 #endif /* INTERFACE */
81
82 /*
83 ** The width of a hash window in bytes. The algorithm only works if this
84 ** is a power of 2.
85 */
86
87 DDED src/graph.c
+10
--- a/src/graph.c
+++ b/src/graph.c
@@ -0,0 +1,10 @@
1
+!=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
2
+ Bag nnRowpRow->isLeaf )else!=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
3
+ Bag ntop, int btm, u32 inUseMask;
4
+ int i; return i;
5
+=isLeaf /* True if tRailrailMap tRailrailMap)!=isLeaf,!=!=isLeaf /* True if tRailrailMapassert( pDesc!=0 );){
6
+ u32 inUseMask = 0;);=isLeaf /* True !=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
7
+ Bag nnRowpRow->isLeaf )else!=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
8
+ Bag ntop, int btm, u32 inUseMask;
9
+ int i; return i;
10
+=isLeaf /* True if tRailrailMap tRailrailMap)!=isLeaf,!=!=isLeaf /* True if tRailrailMapassert( pDesc!=0 );>0 &&1
--- a/src/graph.c
+++ b/src/graph.c
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
--- a/src/graph.c
+++ b/src/graph.c
@@ -0,0 +1,10 @@
1 !=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
2 Bag nnRowpRow->isLeaf )else!=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
3 Bag ntop, int btm, u32 inUseMask;
4 int i; return i;
5 =isLeaf /* True if tRailrailMap tRailrailMap)!=isLeaf,!=!=isLeaf /* True if tRailrailMapassert( pDesc!=0 );){
6 u32 inUseMask = 0;);=isLeaf /* True !=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
7 Bag nnRowpRow->isLeaf )else!=isLeaf /* True if tRailrailMap)!=isLeaf,!=isLeaf = isLeafBag allRids;
8 Bag ntop, int btm, u32 inUseMask;
9 int i; return i;
10 =isLeaf /* True if tRailrailMap tRailrailMap)!=isLeaf,!=!=isLeaf /* True if tRailrailMapassert( pDesc!=0 );>0 &&1
+12 -2
--- src/main.mk
+++ src/main.mk
@@ -37,10 +37,11 @@
3737
$(SRCDIR)/diffcmd.c \
3838
$(SRCDIR)/doc.c \
3939
$(SRCDIR)/encode.c \
4040
$(SRCDIR)/file.c \
4141
$(SRCDIR)/finfo.c \
42
+ $(SRCDIR)/graph.c \
4243
$(SRCDIR)/http.c \
4344
$(SRCDIR)/http_socket.c \
4445
$(SRCDIR)/http_transport.c \
4546
$(SRCDIR)/info.c \
4647
$(SRCDIR)/login.c \
@@ -108,10 +109,11 @@
108109
diffcmd_.c \
109110
doc_.c \
110111
encode_.c \
111112
file_.c \
112113
finfo_.c \
114
+ graph_.c \
113115
http_.c \
114116
http_socket_.c \
115117
http_transport_.c \
116118
info_.c \
117119
login_.c \
@@ -179,10 +181,11 @@
179181
diffcmd.o \
180182
doc.o \
181183
encode.o \
182184
file.o \
183185
finfo.o \
186
+ graph.o \
184187
http.o \
185188
http_socket.o \
186189
http_transport.o \
187190
info.o \
188191
login.o \
@@ -264,16 +267,16 @@
264267
# noop
265268
266269
clean:
267270
rm -f *.o *_.c $(APPNAME) VERSION.h
268271
rm -f translate makeheaders mkindex page_index.h headers
269
- rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h http.h http_socket.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
272
+ rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h graph.h http.h http_socket.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
270273
271274
page_index.h: $(TRANS_SRC) mkindex
272275
./mkindex $(TRANS_SRC) >$@
273276
headers: page_index.h makeheaders VERSION.h
274
- ./makeheaders add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h http_.c:http.h http_socket_.c:http_socket.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
277
+ ./makeheaders add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
275278
touch headers
276279
headers: Makefile
277280
Makefile:
278281
add_.c: $(SRCDIR)/add.c translate
279282
./translate $(SRCDIR)/add.c >add_.c
@@ -455,10 +458,17 @@
455458
456459
finfo.o: finfo_.c finfo.h $(SRCDIR)/config.h
457460
$(XTCC) -o finfo.o -c finfo_.c
458461
459462
finfo.h: headers
463
+graph_.c: $(SRCDIR)/graph.c translate
464
+ ./translate $(SRCDIR)/graph.c >graph_.c
465
+
466
+graph.o: graph_.c graph.h $(SRCDIR)/config.h
467
+ $(XTCC) -o graph.o -c graph_.c
468
+
469
+graph.h: headers
460470
http_.c: $(SRCDIR)/http.c translate
461471
./translate $(SRCDIR)/http.c >http_.c
462472
463473
http.o: http_.c http.h $(SRCDIR)/config.h
464474
$(XTCC) -o http.o -c http_.c
465475
--- src/main.mk
+++ src/main.mk
@@ -37,10 +37,11 @@
37 $(SRCDIR)/diffcmd.c \
38 $(SRCDIR)/doc.c \
39 $(SRCDIR)/encode.c \
40 $(SRCDIR)/file.c \
41 $(SRCDIR)/finfo.c \
 
42 $(SRCDIR)/http.c \
43 $(SRCDIR)/http_socket.c \
44 $(SRCDIR)/http_transport.c \
45 $(SRCDIR)/info.c \
46 $(SRCDIR)/login.c \
@@ -108,10 +109,11 @@
108 diffcmd_.c \
109 doc_.c \
110 encode_.c \
111 file_.c \
112 finfo_.c \
 
113 http_.c \
114 http_socket_.c \
115 http_transport_.c \
116 info_.c \
117 login_.c \
@@ -179,10 +181,11 @@
179 diffcmd.o \
180 doc.o \
181 encode.o \
182 file.o \
183 finfo.o \
 
184 http.o \
185 http_socket.o \
186 http_transport.o \
187 info.o \
188 login.o \
@@ -264,16 +267,16 @@
264 # noop
265
266 clean:
267 rm -f *.o *_.c $(APPNAME) VERSION.h
268 rm -f translate makeheaders mkindex page_index.h headers
269 rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h http.h http_socket.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
270
271 page_index.h: $(TRANS_SRC) mkindex
272 ./mkindex $(TRANS_SRC) >$@
273 headers: page_index.h makeheaders VERSION.h
274 ./makeheaders add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h http_.c:http.h http_socket_.c:http_socket.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
275 touch headers
276 headers: Makefile
277 Makefile:
278 add_.c: $(SRCDIR)/add.c translate
279 ./translate $(SRCDIR)/add.c >add_.c
@@ -455,10 +458,17 @@
455
456 finfo.o: finfo_.c finfo.h $(SRCDIR)/config.h
457 $(XTCC) -o finfo.o -c finfo_.c
458
459 finfo.h: headers
 
 
 
 
 
 
 
460 http_.c: $(SRCDIR)/http.c translate
461 ./translate $(SRCDIR)/http.c >http_.c
462
463 http.o: http_.c http.h $(SRCDIR)/config.h
464 $(XTCC) -o http.o -c http_.c
465
--- src/main.mk
+++ src/main.mk
@@ -37,10 +37,11 @@
37 $(SRCDIR)/diffcmd.c \
38 $(SRCDIR)/doc.c \
39 $(SRCDIR)/encode.c \
40 $(SRCDIR)/file.c \
41 $(SRCDIR)/finfo.c \
42 $(SRCDIR)/graph.c \
43 $(SRCDIR)/http.c \
44 $(SRCDIR)/http_socket.c \
45 $(SRCDIR)/http_transport.c \
46 $(SRCDIR)/info.c \
47 $(SRCDIR)/login.c \
@@ -108,10 +109,11 @@
109 diffcmd_.c \
110 doc_.c \
111 encode_.c \
112 file_.c \
113 finfo_.c \
114 graph_.c \
115 http_.c \
116 http_socket_.c \
117 http_transport_.c \
118 info_.c \
119 login_.c \
@@ -179,10 +181,11 @@
181 diffcmd.o \
182 doc.o \
183 encode.o \
184 file.o \
185 finfo.o \
186 graph.o \
187 http.o \
188 http_socket.o \
189 http_transport.o \
190 info.o \
191 login.o \
@@ -264,16 +267,16 @@
267 # noop
268
269 clean:
270 rm -f *.o *_.c $(APPNAME) VERSION.h
271 rm -f translate makeheaders mkindex page_index.h headers
272 rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h graph.h http.h http_socket.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
273
274 page_index.h: $(TRANS_SRC) mkindex
275 ./mkindex $(TRANS_SRC) >$@
276 headers: page_index.h makeheaders VERSION.h
277 ./makeheaders add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
278 touch headers
279 headers: Makefile
280 Makefile:
281 add_.c: $(SRCDIR)/add.c translate
282 ./translate $(SRCDIR)/add.c >add_.c
@@ -455,10 +458,17 @@
458
459 finfo.o: finfo_.c finfo.h $(SRCDIR)/config.h
460 $(XTCC) -o finfo.o -c finfo_.c
461
462 finfo.h: headers
463 graph_.c: $(SRCDIR)/graph.c translate
464 ./translate $(SRCDIR)/graph.c >graph_.c
465
466 graph.o: graph_.c graph.h $(SRCDIR)/config.h
467 $(XTCC) -o graph.o -c graph_.c
468
469 graph.h: headers
470 http_.c: $(SRCDIR)/http.c translate
471 ./translate $(SRCDIR)/http.c >http_.c
472
473 http.o: http_.c http.h $(SRCDIR)/config.h
474 $(XTCC) -o http.o -c http_.c
475
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -31,10 +31,11 @@
3131
diffcmd
3232
doc
3333
encode
3434
file
3535
finfo
36
+ graph
3637
http
3738
http_socket
3839
http_transport
3940
info
4041
login
4142
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -31,10 +31,11 @@
31 diffcmd
32 doc
33 encode
34 file
35 finfo
 
36 http
37 http_socket
38 http_transport
39 info
40 login
41
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -31,10 +31,11 @@
31 diffcmd
32 doc
33 encode
34 file
35 finfo
36 graph
37 http
38 http_socket
39 http_transport
40 info
41 login
42
+205 -100
--- src/timeline.c
+++ src/timeline.c
@@ -153,10 +153,11 @@
153153
*/
154154
#if INTERFACE
155155
#define TIMELINE_ARTID 0x0001 /* Show artifact IDs on non-check-in lines */
156156
#define TIMELINE_LEAFONLY 0x0002 /* Show "Leaf", but not "Merge", "Fork" etc */
157157
#define TIMELINE_BRIEF 0x0004 /* Combine adjacent elements of same object */
158
+#define TIMELINE_GRAPH 0x0008 /* Compute a graph */
158159
#endif
159160
160161
/*
161162
** Output a timeline in the web format given a query. The query
162163
** should return these columns:
@@ -184,18 +185,23 @@
184185
int mxWikiLen;
185186
Blob comment;
186187
int prevTagid = 0;
187188
int suppressCnt = 0;
188189
char zPrevDate[20];
190
+ GraphContext *pGraph = 0;
189191
190192
zPrevDate[0] = 0;
191193
mxWikiLen = db_get_int("timeline-max-comment", 0);
192194
if( db_get_boolean("timeline-block-markup", 0) ){
193195
wikiFlags = WIKI_INLINE;
194196
}else{
195197
wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
196198
}
199
+ if( tmFlags & TIMELINE_GRAPH ){
200
+ pGraph = graph_init();
201
+ @ <div id="canvas" style="position:relative;width:1px;height:1px;"></div>
202
+ }
197203
198204
db_multi_exec(
199205
"CREATE TEMP TABLE IF NOT EXISTS seen(rid INTEGER PRIMARY KEY);"
200206
"DELETE FROM seen;"
201207
);
@@ -212,10 +218,11 @@
212218
const char *zType = db_column_text(pQuery, 9);
213219
const char *zUser = db_column_text(pQuery, 4);
214220
const char *zTagList = db_column_text(pQuery, 10);
215221
int tagid = db_column_int(pQuery, 11);
216222
int commentColumn = 3; /* Column containing comment text */
223
+ char zTime[8];
217224
if( tagid ){
218225
if( tagid==prevTagid ){
219226
if( tmFlags & TIMELINE_BRIEF ){
220227
suppressCnt++;
221228
continue;
@@ -236,27 +243,29 @@
236243
continue;
237244
}
238245
db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
239246
if( memcmp(zDate, zPrevDate, 10) ){
240247
sprintf(zPrevDate, "%.10s", zDate);
241
- @ <tr><td colspan=3>
242
- @ <div class="divider">%s(zPrevDate)</div>
248
+ @ <tr><td>
249
+ @ <div class="divider"><nobr>%s(zPrevDate)</nobr></div>
243250
@ </td></tr>
244251
}
252
+ memcpy(zTime, &zDate[11], 5);
253
+ zTime[5] = 0;
245254
@ <tr>
246
- @ <td valign="top">%s(&zDate[11])</td>
255
+ @ <td valign="top" align="right">%s(zTime)</td>
247256
@ <td width="20" align="center" valign="top">
248
- @ <font id="m%d(rid)" size="+1" color="white">*</font></td>
257
+ @ <div id="m%d(rid)"></div>
249258
if( zBgClr && zBgClr[0] ){
250259
@ <td valign="top" align="left" bgcolor="%h(zBgClr)">
251260
}else{
252261
@ <td valign="top" align="left">
253262
}
254263
if( zType[0]=='c' ){
255264
const char *azTag[5];
256265
int nTag = 0;
257
- hyperlink_to_uuid_with_mouseover(zUuid, "xin", "xout", rid);
266
+ hyperlink_to_uuid(zUuid);
258267
if( (tmFlags & TIMELINE_LEAFONLY)==0 ){
259268
if( nParent>1 ){
260269
azTag[nTag++] = "Merge";
261270
}
262271
if( nPChild>1 ){
@@ -280,10 +289,37 @@
280289
int i;
281290
for(i=0; i<nTag; i++){
282291
@ <b>%s(azTag[i])%s(i==nTag-1?"":",")</b>
283292
}
284293
}
294
+ if( pGraph ){
295
+ int nParent = 0;
296
+ int aParent[32];
297
+ const char *zBr;
298
+ static Stmt qparent;
299
+ static Stmt qbranch;
300
+ db_static_prepare(&qparent,
301
+ "SELECT pid FROM plink WHERE cid=:rid ORDER BY isprim DESC"
302
+ );
303
+ db_static_prepare(&qbranch,
304
+ "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
305
+ TAG_BRANCH
306
+ );
307
+ db_bind_int(&qparent, ":rid", rid);
308
+ while( db_step(&qparent)==SQLITE_ROW && nParent<32 ){
309
+ aParent[nParent++] = db_column_int(&qparent, 0);
310
+ }
311
+ db_reset(&qparent);
312
+ db_bind_int(&qbranch, ":rid", rid);
313
+ if( db_step(&qbranch)==SQLITE_ROW ){
314
+ zBr = db_column_text(&qbranch, 0);
315
+ }else{
316
+ zBr = "trunk";
317
+ }
318
+ graph_add_row(pGraph, rid, isLeaf, nParent, aParent, zBr);
319
+ db_reset(&qbranch);
320
+ }
285321
}else if( (tmFlags & TIMELINE_ARTID)!=0 ){
286322
hyperlink_to_uuid(zUuid);
287323
}
288324
db_column_blob(pQuery, commentColumn, &comment);
289325
if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
@@ -310,12 +346,173 @@
310346
if( suppressCnt ){
311347
@ <tr><td><td><td>
312348
@ <small><i>... %d(suppressCnt) similar
313349
@ event%s(suppressCnt>1?"s":"") omitted.</i></small></tr>
314350
suppressCnt = 0;
351
+ }
352
+ if( pGraph ){
353
+ graph_finish(pGraph);
354
+ if( pGraph->nErr ){
355
+ graph_free(pGraph);
356
+ pGraph = 0;
357
+ }else{
358
+ @ <tr><td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div>
359
+ }
315360
}
316361
@ </table>
362
+ if( pGraph && pGraph->nErr==0 ){
363
+ GraphRow *pRow;
364
+ int i;
365
+ char cSep;
366
+ @ <script type="text/JavaScript">
367
+ cgi_printf("var rowinfo = [\n");
368
+ for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
369
+ cgi_printf("{id:\"m%d\",r:%d,d:%d,mo:%d,mu:%d,u:%d,au:",
370
+ pRow->rid,
371
+ pRow->iRail,
372
+ pRow->bDescender,
373
+ pRow->mergeOut,
374
+ pRow->mergeUpto,
375
+ pRow->aiRaiser[pRow->iRail]
376
+ );
377
+ cSep = '[';
378
+ for(i=0; i<GR_MAX_RAIL; i++){
379
+ if( i==pRow->iRail ) continue;
380
+ if( pRow->aiRaiser[i]>0 ){
381
+ cgi_printf("%c%d,%d", cSep, pGraph->railMap[i], pRow->aiRaiser[i]);
382
+ cSep = ',';
383
+ }
384
+ }
385
+ if( cSep=='[' ) cgi_printf("[");
386
+ cgi_printf("],mi:");
387
+ cSep = '[';
388
+ for(i=0; i<GR_MAX_RAIL; i++){
389
+ if( pRow->mergeIn & (1<<i) ){
390
+ cgi_printf("%c%d", cSep, pGraph->railMap[i]);
391
+ cSep = ',';
392
+ }
393
+ }
394
+ if( cSep=='[' ) cgi_printf("[");
395
+ cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n");
396
+ }
397
+ cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
398
+ graph_free(pGraph);
399
+ @ var canvasDiv = document.getElementById("canvas");
400
+ @ function drawBox(color,x0,y0,x1,y1){
401
+ @ var n = document.createElement("div");
402
+ @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
403
+ @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
404
+ @ var w = x1-x0+1;
405
+ @ var h = y1-y0+1;
406
+ @ n.setAttribute("style",
407
+ @ "position:absolute;"+
408
+ @ "left:"+x0+"px;"+
409
+ @ "top:"+y0+"px;"+
410
+ @ "width:"+w+"px;"+
411
+ @ "height:"+h+"px;"+
412
+ @ "background-color:"+color+";"
413
+ @ );
414
+ @ canvasDiv.appendChild(n);
415
+ @ }
416
+ @ function absoluteY(id){
417
+ @ var obj = document.getElementById(id);
418
+ @ if( !obj ) return;
419
+ @ var top = 0;
420
+ @ if( obj.offsetParent ){
421
+ @ do{
422
+ @ top += obj.offsetTop;
423
+ @ }while( obj = obj.offsetParent );
424
+ @ }
425
+ @ return top;
426
+ @ }
427
+ @ function absoluteX(id){
428
+ @ var obj = document.getElementById(id);
429
+ @ if( !obj ) return;
430
+ @ var left = 0;
431
+ @ if( obj.offsetParent ){
432
+ @ do{
433
+ @ left += obj.offsetLeft;
434
+ @ }while( obj = obj.offsetParent );
435
+ @ }
436
+ @ return left;
437
+ @ }
438
+ @ function drawUpArrow(x,y0,y1){
439
+ @ drawBox("black",x,y0,x+1,y1);
440
+ @ if( y0+8>=y1 ){
441
+ @ drawBox("black",x-1,y0+1,x+2,y0+2);
442
+ @ drawBox("black",x-2,y0+3,x+3,y0+4);
443
+ @ }else{
444
+ @ drawBox("black",x-1,y0+2,x+2,y0+4);
445
+ @ drawBox("black",x-2,y0+5,x+3,y0+7);
446
+ @ }
447
+ @ }
448
+ @ function drawThinArrow(y,xFrom,xTo){
449
+ @ if( xFrom<xTo ){
450
+ @ drawBox("black",xFrom,y,xTo,y);
451
+ @ drawBox("black",xTo-4,y-1,xTo-2,y+1);
452
+ @ if( xTo>xFrom-8 ) drawBox("black",xTo-6,y-2,xTo-5,y+2);
453
+ @ }else{
454
+ @ drawBox("black",xTo,y,xFrom,y);
455
+ @ drawBox("black",xTo+2,y-1,xTo+4,y+1);
456
+ @ if( xTo+8<xFrom ) drawBox("black",xTo+5,y-2,xTo+6,y+2);
457
+ @ }
458
+ @ }
459
+ @ function drawThinLine(x0,y0,x1,y1){
460
+ @ drawBox("black",x0,y0,x1,y1);
461
+ @ }
462
+ @ function drawNode(p, left, btm){
463
+ @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
464
+ @ drawBox("white",p.x-4,p.y-4,p.x+5,p.y+5);
465
+ @ if( p.u>0 ){
466
+ @ var u = rowinfo[p.u-1];
467
+ @ drawUpArrow(p.x, u.y+6, p.y-5);
468
+ @ }
469
+ @ if( p.d ){
470
+ @ drawUpArrow(p.x, p.y+6, btm);
471
+ @ }
472
+ @ if( p.mo>=0 ){
473
+ @ var x1 = p.mo*20 + left;
474
+ @ var y1 = p.y-3;
475
+ @ var x0 = x1>p.x ? p.x+7 : p.x-6;
476
+ @ var u = rowinfo[p.mu-1];
477
+ @ var y0 = u.y+5;
478
+ @ drawThinLine(x0,y1,x1,y1);
479
+ @ drawThinLine(x1,y0,x1,y1);
480
+ @ }
481
+ @ var n = p.au.length;
482
+ @ for(var i=0; i<n; i+=2){
483
+ @ var x1 = p.au[i]*20 + left;
484
+ @ var x0 = x1>p.x ? p.x+7 : p.x-6;
485
+ @ drawBox("black",x0,p.y,x1,p.y+1);
486
+ @ var u = rowinfo[p.au[i+1]-1];
487
+ @ drawUpArrow(x1, u.y+6, p.y);
488
+ @ }
489
+ @ for(var j in p.mi){
490
+ @ var y0 = p.y+5;
491
+ @ var mx = p.mi[j]*20 + left;
492
+ @ if( mx>p.x ){
493
+ @ drawThinArrow(y0,mx,p.x+5);
494
+ @ }else{
495
+ @ drawThinArrow(y0,mx,p.x-5);
496
+ @ }
497
+ @ }
498
+ @ }
499
+ @ function renderGraph(){
500
+ @ var canvasY = absoluteY("canvas");
501
+ @ var left = absoluteX(rowinfo[0].id) - absoluteX("canvas") + 15;
502
+ @ for(var i in rowinfo){
503
+ @ rowinfo[i].y = absoluteY(rowinfo[i].id) + 10 - canvasY;
504
+ @ rowinfo[i].x = left + rowinfo[i].r*20;
505
+ @ }
506
+ @ var btm = rowinfo[rowinfo.length-1].y + 20;
507
+ @ for(var i in rowinfo){
508
+ @ drawNode(rowinfo[i], left, btm);
509
+ @ }
510
+ @ }
511
+ @ renderGraph();
512
+ @ </script>
513
+ }
317514
}
318515
319516
/*
320517
** Create a temporary table suitable for storing timeline data.
321518
*/
@@ -461,13 +658,13 @@
461658
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
462659
}else{
463660
tagid = 0;
464661
}
465662
if( zType[0]=='a' ){
466
- tmFlags = TIMELINE_BRIEF;
663
+ tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
467664
}else{
468
- tmFlags = 0;
665
+ tmFlags = TIMELINE_GRAPH;
469666
}
470667
471668
style_header("Timeline");
472669
login_anonymous_available();
473670
timeline_temp_table();
@@ -645,10 +842,11 @@
645842
if( zUser ){
646843
blob_appendf(&desc, " by user %h", zUser);
647844
}
648845
if( tagid>0 ){
649846
blob_appendf(&desc, " tagged with \"%h\"", zTagName);
847
+ tmFlags &= ~TIMELINE_GRAPH;
650848
}
651849
if( zAfter ){
652850
blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
653851
}else if( zBefore ){
654852
blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
@@ -691,103 +889,10 @@
691889
db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
692890
@ <h2>%b(&desc)</h2>
693891
blob_reset(&desc);
694892
www_print_timeline(&q, tmFlags, 0);
695893
db_finalize(&q);
696
-
697
- @ <script>
698
- @ var parentof = new Object();
699
- @ var childof = new Object();
700
- db_prepare(&q, "SELECT rid FROM seen");
701
- while( db_step(&q)==SQLITE_ROW ){
702
- int rid = db_column_int(&q, 0);
703
- Stmt q2;
704
- const char *zSep;
705
- Blob *pOut = cgi_output_blob();
706
-
707
- db_prepare(&q2, "SELECT pid FROM plink WHERE cid=%d", rid);
708
- zSep = "";
709
- blob_appendf(pOut, "parentof[\"m%d\"] = [", rid);
710
- while( db_step(&q2)==SQLITE_ROW ){
711
- int pid = db_column_int(&q2, 0);
712
- blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
713
- zSep = ",";
714
- }
715
- db_finalize(&q2);
716
- blob_appendf(pOut, "];\n");
717
- db_prepare(&q2, "SELECT cid FROM plink WHERE pid=%d", rid);
718
- zSep = "";
719
- blob_appendf(pOut, "childof[\"m%d\"] = [", rid);
720
- while( db_step(&q2)==SQLITE_ROW ){
721
- int pid = db_column_int(&q2, 0);
722
- blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
723
- zSep = ",";
724
- }
725
- db_finalize(&q2);
726
- blob_appendf(pOut, "];\n");
727
- }
728
- db_finalize(&q);
729
- @ function setall(value){
730
- @ for(var x in parentof){
731
- @ setone(x,value);
732
- @ }
733
- @ }
734
- @ setall("#ffffff");
735
- @ function setone(id, clr){
736
- @ if( parentof[id]==null ) return 0;
737
- @ var w = document.getElementById(id);
738
- @ if( w.style.color==clr ){
739
- @ return 0
740
- @ }else{
741
- @ w.style.color = clr
742
- @ return 1
743
- @ }
744
- @ }
745
- @ function xin(id) {
746
- @ setall("#ffffff");
747
- @ setone(id,"#ff0000");
748
- @ set_children(id, "#b0b0b0");
749
- @ set_parents(id, "#b0b0b0");
750
- @ for(var x in parentof[id]){
751
- @ var pid = parentof[id][x]
752
- @ var w = document.getElementById(pid);
753
- @ if( w!=null ){
754
- @ w.style.color = "#000000";
755
- @ }
756
- @ }
757
- @ for(var x in childof[id]){
758
- @ var cid = childof[id][x]
759
- @ var w = document.getElementById(cid);
760
- @ if( w!=null ){
761
- @ w.style.color = "#000000";
762
- @ }
763
- @ }
764
- @ }
765
- @ function xout(id) {
766
- @ /* setall("#000000"); */
767
- @ }
768
- @ function set_parents(id, clr){
769
- @ var plist = parentof[id];
770
- @ if( plist==null ) return;
771
- @ for(var x in plist){
772
- @ var pid = plist[x];
773
- @ if( setone(pid,clr)==1 ){
774
- @ set_parents(pid,clr);
775
- @ }
776
- @ }
777
- @ }
778
- @ function set_children(id,clr){
779
- @ var clist = childof[id];
780
- @ if( clist==null ) return;
781
- @ for(var x in clist){
782
- @ var cid = clist[x];
783
- @ if( setone(cid,clr)==1 ){
784
- @ set_children(cid,clr);
785
- @ }
786
- @ }
787
- @ }
788
- @ </script>
789894
style_footer();
790895
}
791896
792897
/*
793898
** The input query q selects various records. Print a human-readable
794899
--- src/timeline.c
+++ src/timeline.c
@@ -153,10 +153,11 @@
153 */
154 #if INTERFACE
155 #define TIMELINE_ARTID 0x0001 /* Show artifact IDs on non-check-in lines */
156 #define TIMELINE_LEAFONLY 0x0002 /* Show "Leaf", but not "Merge", "Fork" etc */
157 #define TIMELINE_BRIEF 0x0004 /* Combine adjacent elements of same object */
 
158 #endif
159
160 /*
161 ** Output a timeline in the web format given a query. The query
162 ** should return these columns:
@@ -184,18 +185,23 @@
184 int mxWikiLen;
185 Blob comment;
186 int prevTagid = 0;
187 int suppressCnt = 0;
188 char zPrevDate[20];
 
189
190 zPrevDate[0] = 0;
191 mxWikiLen = db_get_int("timeline-max-comment", 0);
192 if( db_get_boolean("timeline-block-markup", 0) ){
193 wikiFlags = WIKI_INLINE;
194 }else{
195 wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
196 }
 
 
 
 
197
198 db_multi_exec(
199 "CREATE TEMP TABLE IF NOT EXISTS seen(rid INTEGER PRIMARY KEY);"
200 "DELETE FROM seen;"
201 );
@@ -212,10 +218,11 @@
212 const char *zType = db_column_text(pQuery, 9);
213 const char *zUser = db_column_text(pQuery, 4);
214 const char *zTagList = db_column_text(pQuery, 10);
215 int tagid = db_column_int(pQuery, 11);
216 int commentColumn = 3; /* Column containing comment text */
 
217 if( tagid ){
218 if( tagid==prevTagid ){
219 if( tmFlags & TIMELINE_BRIEF ){
220 suppressCnt++;
221 continue;
@@ -236,27 +243,29 @@
236 continue;
237 }
238 db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
239 if( memcmp(zDate, zPrevDate, 10) ){
240 sprintf(zPrevDate, "%.10s", zDate);
241 @ <tr><td colspan=3>
242 @ <div class="divider">%s(zPrevDate)</div>
243 @ </td></tr>
244 }
 
 
245 @ <tr>
246 @ <td valign="top">%s(&zDate[11])</td>
247 @ <td width="20" align="center" valign="top">
248 @ <font id="m%d(rid)" size="+1" color="white">*</font></td>
249 if( zBgClr && zBgClr[0] ){
250 @ <td valign="top" align="left" bgcolor="%h(zBgClr)">
251 }else{
252 @ <td valign="top" align="left">
253 }
254 if( zType[0]=='c' ){
255 const char *azTag[5];
256 int nTag = 0;
257 hyperlink_to_uuid_with_mouseover(zUuid, "xin", "xout", rid);
258 if( (tmFlags & TIMELINE_LEAFONLY)==0 ){
259 if( nParent>1 ){
260 azTag[nTag++] = "Merge";
261 }
262 if( nPChild>1 ){
@@ -280,10 +289,37 @@
280 int i;
281 for(i=0; i<nTag; i++){
282 @ <b>%s(azTag[i])%s(i==nTag-1?"":",")</b>
283 }
284 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
286 hyperlink_to_uuid(zUuid);
287 }
288 db_column_blob(pQuery, commentColumn, &comment);
289 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
@@ -310,12 +346,173 @@
310 if( suppressCnt ){
311 @ <tr><td><td><td>
312 @ <small><i>... %d(suppressCnt) similar
313 @ event%s(suppressCnt>1?"s":"") omitted.</i></small></tr>
314 suppressCnt = 0;
 
 
 
 
 
 
 
 
 
315 }
316 @ </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317 }
318
319 /*
320 ** Create a temporary table suitable for storing timeline data.
321 */
@@ -461,13 +658,13 @@
461 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
462 }else{
463 tagid = 0;
464 }
465 if( zType[0]=='a' ){
466 tmFlags = TIMELINE_BRIEF;
467 }else{
468 tmFlags = 0;
469 }
470
471 style_header("Timeline");
472 login_anonymous_available();
473 timeline_temp_table();
@@ -645,10 +842,11 @@
645 if( zUser ){
646 blob_appendf(&desc, " by user %h", zUser);
647 }
648 if( tagid>0 ){
649 blob_appendf(&desc, " tagged with \"%h\"", zTagName);
 
650 }
651 if( zAfter ){
652 blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
653 }else if( zBefore ){
654 blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
@@ -691,103 +889,10 @@
691 db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
692 @ <h2>%b(&desc)</h2>
693 blob_reset(&desc);
694 www_print_timeline(&q, tmFlags, 0);
695 db_finalize(&q);
696
697 @ <script>
698 @ var parentof = new Object();
699 @ var childof = new Object();
700 db_prepare(&q, "SELECT rid FROM seen");
701 while( db_step(&q)==SQLITE_ROW ){
702 int rid = db_column_int(&q, 0);
703 Stmt q2;
704 const char *zSep;
705 Blob *pOut = cgi_output_blob();
706
707 db_prepare(&q2, "SELECT pid FROM plink WHERE cid=%d", rid);
708 zSep = "";
709 blob_appendf(pOut, "parentof[\"m%d\"] = [", rid);
710 while( db_step(&q2)==SQLITE_ROW ){
711 int pid = db_column_int(&q2, 0);
712 blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
713 zSep = ",";
714 }
715 db_finalize(&q2);
716 blob_appendf(pOut, "];\n");
717 db_prepare(&q2, "SELECT cid FROM plink WHERE pid=%d", rid);
718 zSep = "";
719 blob_appendf(pOut, "childof[\"m%d\"] = [", rid);
720 while( db_step(&q2)==SQLITE_ROW ){
721 int pid = db_column_int(&q2, 0);
722 blob_appendf(pOut, "%s\"m%d\"", zSep, pid);
723 zSep = ",";
724 }
725 db_finalize(&q2);
726 blob_appendf(pOut, "];\n");
727 }
728 db_finalize(&q);
729 @ function setall(value){
730 @ for(var x in parentof){
731 @ setone(x,value);
732 @ }
733 @ }
734 @ setall("#ffffff");
735 @ function setone(id, clr){
736 @ if( parentof[id]==null ) return 0;
737 @ var w = document.getElementById(id);
738 @ if( w.style.color==clr ){
739 @ return 0
740 @ }else{
741 @ w.style.color = clr
742 @ return 1
743 @ }
744 @ }
745 @ function xin(id) {
746 @ setall("#ffffff");
747 @ setone(id,"#ff0000");
748 @ set_children(id, "#b0b0b0");
749 @ set_parents(id, "#b0b0b0");
750 @ for(var x in parentof[id]){
751 @ var pid = parentof[id][x]
752 @ var w = document.getElementById(pid);
753 @ if( w!=null ){
754 @ w.style.color = "#000000";
755 @ }
756 @ }
757 @ for(var x in childof[id]){
758 @ var cid = childof[id][x]
759 @ var w = document.getElementById(cid);
760 @ if( w!=null ){
761 @ w.style.color = "#000000";
762 @ }
763 @ }
764 @ }
765 @ function xout(id) {
766 @ /* setall("#000000"); */
767 @ }
768 @ function set_parents(id, clr){
769 @ var plist = parentof[id];
770 @ if( plist==null ) return;
771 @ for(var x in plist){
772 @ var pid = plist[x];
773 @ if( setone(pid,clr)==1 ){
774 @ set_parents(pid,clr);
775 @ }
776 @ }
777 @ }
778 @ function set_children(id,clr){
779 @ var clist = childof[id];
780 @ if( clist==null ) return;
781 @ for(var x in clist){
782 @ var cid = clist[x];
783 @ if( setone(cid,clr)==1 ){
784 @ set_children(cid,clr);
785 @ }
786 @ }
787 @ }
788 @ </script>
789 style_footer();
790 }
791
792 /*
793 ** The input query q selects various records. Print a human-readable
794
--- src/timeline.c
+++ src/timeline.c
@@ -153,10 +153,11 @@
153 */
154 #if INTERFACE
155 #define TIMELINE_ARTID 0x0001 /* Show artifact IDs on non-check-in lines */
156 #define TIMELINE_LEAFONLY 0x0002 /* Show "Leaf", but not "Merge", "Fork" etc */
157 #define TIMELINE_BRIEF 0x0004 /* Combine adjacent elements of same object */
158 #define TIMELINE_GRAPH 0x0008 /* Compute a graph */
159 #endif
160
161 /*
162 ** Output a timeline in the web format given a query. The query
163 ** should return these columns:
@@ -184,18 +185,23 @@
185 int mxWikiLen;
186 Blob comment;
187 int prevTagid = 0;
188 int suppressCnt = 0;
189 char zPrevDate[20];
190 GraphContext *pGraph = 0;
191
192 zPrevDate[0] = 0;
193 mxWikiLen = db_get_int("timeline-max-comment", 0);
194 if( db_get_boolean("timeline-block-markup", 0) ){
195 wikiFlags = WIKI_INLINE;
196 }else{
197 wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
198 }
199 if( tmFlags & TIMELINE_GRAPH ){
200 pGraph = graph_init();
201 @ <div id="canvas" style="position:relative;width:1px;height:1px;"></div>
202 }
203
204 db_multi_exec(
205 "CREATE TEMP TABLE IF NOT EXISTS seen(rid INTEGER PRIMARY KEY);"
206 "DELETE FROM seen;"
207 );
@@ -212,10 +218,11 @@
218 const char *zType = db_column_text(pQuery, 9);
219 const char *zUser = db_column_text(pQuery, 4);
220 const char *zTagList = db_column_text(pQuery, 10);
221 int tagid = db_column_int(pQuery, 11);
222 int commentColumn = 3; /* Column containing comment text */
223 char zTime[8];
224 if( tagid ){
225 if( tagid==prevTagid ){
226 if( tmFlags & TIMELINE_BRIEF ){
227 suppressCnt++;
228 continue;
@@ -236,27 +243,29 @@
243 continue;
244 }
245 db_multi_exec("INSERT OR IGNORE INTO seen VALUES(%d)", rid);
246 if( memcmp(zDate, zPrevDate, 10) ){
247 sprintf(zPrevDate, "%.10s", zDate);
248 @ <tr><td>
249 @ <div class="divider"><nobr>%s(zPrevDate)</nobr></div>
250 @ </td></tr>
251 }
252 memcpy(zTime, &zDate[11], 5);
253 zTime[5] = 0;
254 @ <tr>
255 @ <td valign="top" align="right">%s(zTime)</td>
256 @ <td width="20" align="center" valign="top">
257 @ <div id="m%d(rid)"></div>
258 if( zBgClr && zBgClr[0] ){
259 @ <td valign="top" align="left" bgcolor="%h(zBgClr)">
260 }else{
261 @ <td valign="top" align="left">
262 }
263 if( zType[0]=='c' ){
264 const char *azTag[5];
265 int nTag = 0;
266 hyperlink_to_uuid(zUuid);
267 if( (tmFlags & TIMELINE_LEAFONLY)==0 ){
268 if( nParent>1 ){
269 azTag[nTag++] = "Merge";
270 }
271 if( nPChild>1 ){
@@ -280,10 +289,37 @@
289 int i;
290 for(i=0; i<nTag; i++){
291 @ <b>%s(azTag[i])%s(i==nTag-1?"":",")</b>
292 }
293 }
294 if( pGraph ){
295 int nParent = 0;
296 int aParent[32];
297 const char *zBr;
298 static Stmt qparent;
299 static Stmt qbranch;
300 db_static_prepare(&qparent,
301 "SELECT pid FROM plink WHERE cid=:rid ORDER BY isprim DESC"
302 );
303 db_static_prepare(&qbranch,
304 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
305 TAG_BRANCH
306 );
307 db_bind_int(&qparent, ":rid", rid);
308 while( db_step(&qparent)==SQLITE_ROW && nParent<32 ){
309 aParent[nParent++] = db_column_int(&qparent, 0);
310 }
311 db_reset(&qparent);
312 db_bind_int(&qbranch, ":rid", rid);
313 if( db_step(&qbranch)==SQLITE_ROW ){
314 zBr = db_column_text(&qbranch, 0);
315 }else{
316 zBr = "trunk";
317 }
318 graph_add_row(pGraph, rid, isLeaf, nParent, aParent, zBr);
319 db_reset(&qbranch);
320 }
321 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
322 hyperlink_to_uuid(zUuid);
323 }
324 db_column_blob(pQuery, commentColumn, &comment);
325 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
@@ -310,12 +346,173 @@
346 if( suppressCnt ){
347 @ <tr><td><td><td>
348 @ <small><i>... %d(suppressCnt) similar
349 @ event%s(suppressCnt>1?"s":"") omitted.</i></small></tr>
350 suppressCnt = 0;
351 }
352 if( pGraph ){
353 graph_finish(pGraph);
354 if( pGraph->nErr ){
355 graph_free(pGraph);
356 pGraph = 0;
357 }else{
358 @ <tr><td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div>
359 }
360 }
361 @ </table>
362 if( pGraph && pGraph->nErr==0 ){
363 GraphRow *pRow;
364 int i;
365 char cSep;
366 @ <script type="text/JavaScript">
367 cgi_printf("var rowinfo = [\n");
368 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
369 cgi_printf("{id:\"m%d\",r:%d,d:%d,mo:%d,mu:%d,u:%d,au:",
370 pRow->rid,
371 pRow->iRail,
372 pRow->bDescender,
373 pRow->mergeOut,
374 pRow->mergeUpto,
375 pRow->aiRaiser[pRow->iRail]
376 );
377 cSep = '[';
378 for(i=0; i<GR_MAX_RAIL; i++){
379 if( i==pRow->iRail ) continue;
380 if( pRow->aiRaiser[i]>0 ){
381 cgi_printf("%c%d,%d", cSep, pGraph->railMap[i], pRow->aiRaiser[i]);
382 cSep = ',';
383 }
384 }
385 if( cSep=='[' ) cgi_printf("[");
386 cgi_printf("],mi:");
387 cSep = '[';
388 for(i=0; i<GR_MAX_RAIL; i++){
389 if( pRow->mergeIn & (1<<i) ){
390 cgi_printf("%c%d", cSep, pGraph->railMap[i]);
391 cSep = ',';
392 }
393 }
394 if( cSep=='[' ) cgi_printf("[");
395 cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n");
396 }
397 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
398 graph_free(pGraph);
399 @ var canvasDiv = document.getElementById("canvas");
400 @ function drawBox(color,x0,y0,x1,y1){
401 @ var n = document.createElement("div");
402 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
403 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
404 @ var w = x1-x0+1;
405 @ var h = y1-y0+1;
406 @ n.setAttribute("style",
407 @ "position:absolute;"+
408 @ "left:"+x0+"px;"+
409 @ "top:"+y0+"px;"+
410 @ "width:"+w+"px;"+
411 @ "height:"+h+"px;"+
412 @ "background-color:"+color+";"
413 @ );
414 @ canvasDiv.appendChild(n);
415 @ }
416 @ function absoluteY(id){
417 @ var obj = document.getElementById(id);
418 @ if( !obj ) return;
419 @ var top = 0;
420 @ if( obj.offsetParent ){
421 @ do{
422 @ top += obj.offsetTop;
423 @ }while( obj = obj.offsetParent );
424 @ }
425 @ return top;
426 @ }
427 @ function absoluteX(id){
428 @ var obj = document.getElementById(id);
429 @ if( !obj ) return;
430 @ var left = 0;
431 @ if( obj.offsetParent ){
432 @ do{
433 @ left += obj.offsetLeft;
434 @ }while( obj = obj.offsetParent );
435 @ }
436 @ return left;
437 @ }
438 @ function drawUpArrow(x,y0,y1){
439 @ drawBox("black",x,y0,x+1,y1);
440 @ if( y0+8>=y1 ){
441 @ drawBox("black",x-1,y0+1,x+2,y0+2);
442 @ drawBox("black",x-2,y0+3,x+3,y0+4);
443 @ }else{
444 @ drawBox("black",x-1,y0+2,x+2,y0+4);
445 @ drawBox("black",x-2,y0+5,x+3,y0+7);
446 @ }
447 @ }
448 @ function drawThinArrow(y,xFrom,xTo){
449 @ if( xFrom<xTo ){
450 @ drawBox("black",xFrom,y,xTo,y);
451 @ drawBox("black",xTo-4,y-1,xTo-2,y+1);
452 @ if( xTo>xFrom-8 ) drawBox("black",xTo-6,y-2,xTo-5,y+2);
453 @ }else{
454 @ drawBox("black",xTo,y,xFrom,y);
455 @ drawBox("black",xTo+2,y-1,xTo+4,y+1);
456 @ if( xTo+8<xFrom ) drawBox("black",xTo+5,y-2,xTo+6,y+2);
457 @ }
458 @ }
459 @ function drawThinLine(x0,y0,x1,y1){
460 @ drawBox("black",x0,y0,x1,y1);
461 @ }
462 @ function drawNode(p, left, btm){
463 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
464 @ drawBox("white",p.x-4,p.y-4,p.x+5,p.y+5);
465 @ if( p.u>0 ){
466 @ var u = rowinfo[p.u-1];
467 @ drawUpArrow(p.x, u.y+6, p.y-5);
468 @ }
469 @ if( p.d ){
470 @ drawUpArrow(p.x, p.y+6, btm);
471 @ }
472 @ if( p.mo>=0 ){
473 @ var x1 = p.mo*20 + left;
474 @ var y1 = p.y-3;
475 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
476 @ var u = rowinfo[p.mu-1];
477 @ var y0 = u.y+5;
478 @ drawThinLine(x0,y1,x1,y1);
479 @ drawThinLine(x1,y0,x1,y1);
480 @ }
481 @ var n = p.au.length;
482 @ for(var i=0; i<n; i+=2){
483 @ var x1 = p.au[i]*20 + left;
484 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
485 @ drawBox("black",x0,p.y,x1,p.y+1);
486 @ var u = rowinfo[p.au[i+1]-1];
487 @ drawUpArrow(x1, u.y+6, p.y);
488 @ }
489 @ for(var j in p.mi){
490 @ var y0 = p.y+5;
491 @ var mx = p.mi[j]*20 + left;
492 @ if( mx>p.x ){
493 @ drawThinArrow(y0,mx,p.x+5);
494 @ }else{
495 @ drawThinArrow(y0,mx,p.x-5);
496 @ }
497 @ }
498 @ }
499 @ function renderGraph(){
500 @ var canvasY = absoluteY("canvas");
501 @ var left = absoluteX(rowinfo[0].id) - absoluteX("canvas") + 15;
502 @ for(var i in rowinfo){
503 @ rowinfo[i].y = absoluteY(rowinfo[i].id) + 10 - canvasY;
504 @ rowinfo[i].x = left + rowinfo[i].r*20;
505 @ }
506 @ var btm = rowinfo[rowinfo.length-1].y + 20;
507 @ for(var i in rowinfo){
508 @ drawNode(rowinfo[i], left, btm);
509 @ }
510 @ }
511 @ renderGraph();
512 @ </script>
513 }
514 }
515
516 /*
517 ** Create a temporary table suitable for storing timeline data.
518 */
@@ -461,13 +658,13 @@
658 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
659 }else{
660 tagid = 0;
661 }
662 if( zType[0]=='a' ){
663 tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
664 }else{
665 tmFlags = TIMELINE_GRAPH;
666 }
667
668 style_header("Timeline");
669 login_anonymous_available();
670 timeline_temp_table();
@@ -645,10 +842,11 @@
842 if( zUser ){
843 blob_appendf(&desc, " by user %h", zUser);
844 }
845 if( tagid>0 ){
846 blob_appendf(&desc, " tagged with \"%h\"", zTagName);
847 tmFlags &= ~TIMELINE_GRAPH;
848 }
849 if( zAfter ){
850 blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
851 }else if( zBefore ){
852 blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
@@ -691,103 +889,10 @@
889 db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC");
890 @ <h2>%b(&desc)</h2>
891 blob_reset(&desc);
892 www_print_timeline(&q, tmFlags, 0);
893 db_finalize(&q);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894 style_footer();
895 }
896
897 /*
898 ** The input query q selects various records. Print a human-readable
899

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button