Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| SHA1 Hash: | c19467d68ecfc90d774aad670ba46ca4d79a2d69 |
|---|---|
| Date: | 2010-03-17 00:40:25 |
| User: | drh |
| Comment: | Get the derivation graph working for individual file histories. |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
Changes to src/finfo.c
98 ** Show the complete change history for a single file. 98 ** Show the complete change history for a single file. 99 */ 99 */ 100 void finfo_page(void){ 100 void finfo_page(void){ 101 Stmt q; 101 Stmt q; 102 const char *zFilename; 102 const char *zFilename; 103 char zPrevDate[20]; 103 char zPrevDate[20]; 104 Blob title; 104 Blob title; > 105 GraphContext *pGraph; 105 106 106 login_check_credentials(); 107 login_check_credentials(); 107 if( !g.okRead ){ login_needed(); return; } 108 if( !g.okRead ){ login_needed(); return; } 108 style_header("File History"); 109 style_header("File History"); 109 login_anonymous_available(); 110 login_anonymous_available(); 110 111 111 zPrevDate[0] = 0; 112 zPrevDate[0] = 0; 112 zFilename = PD("name",""); 113 zFilename = PD("name",""); 113 db_prepare(&q, 114 db_prepare(&q, > 115 "SELECT" > 116 " substr(b.uuid,1,10)," 114 "SELECT substr(b.uuid,1,10), datetime(event.mtime,'localtime')," | 117 " datetime(event.mtime,'localtime')," 115 " coalesce(event.ecomment, event.comment)," | 118 " coalesce(event.ecomment, event.comment)," 116 " coalesce(event.euser, event.user)," | 119 " coalesce(event.euser, event.user)," 117 " mlink.pid, mlink.fid, mlink.mid, mlink.fnid, ci.uuid" < > 120 " mlink.pid," > 121 " mlink.fid," > 122 " mlink.mid," > 123 " mlink.fnid," > 124 " ci.uuid," > 125 " event.bgcolor," > 126 " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" > 127 " AND tagxref.rid=mlink.mid)" 118 " FROM mlink, blob b, event, blob ci" 128 " FROM mlink, blob b, event, blob ci" 119 " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" 129 " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" 120 " AND b.rid=mlink.fid" 130 " AND b.rid=mlink.fid" 121 " AND event.objid=mlink.mid" 131 " AND event.objid=mlink.mid" 122 " AND event.objid=ci.rid" 132 " AND event.objid=ci.rid" 123 " ORDER BY event.mtime DESC", 133 " ORDER BY event.mtime DESC", > 134 TAG_BRANCH, 124 zFilename 135 zFilename 125 ); 136 ); 126 blob_zero(&title); 137 blob_zero(&title); 127 blob_appendf(&title, "History of "); 138 blob_appendf(&title, "History of "); 128 hyperlinked_path(zFilename, &title); 139 hyperlinked_path(zFilename, &title); 129 @ <h2>%b(&title)</h2> 140 @ <h2>%b(&title)</h2> 130 blob_reset(&title); 141 blob_reset(&title); > 142 pGraph = graph_init(); > 143 @ <div id="canvas" style="position:relative;width:1px;height:1px;"></div> 131 @ <table cellspacing=0 border=0 cellpadding=0> 144 @ <table cellspacing=0 border=0 cellpadding=0> 132 while( db_step(&q)==SQLITE_ROW ){ 145 while( db_step(&q)==SQLITE_ROW ){ 133 const char *zUuid = db_column_text(&q, 0); 146 const char *zUuid = db_column_text(&q, 0); 134 const char *zDate = db_column_text(&q, 1); 147 const char *zDate = db_column_text(&q, 1); 135 const char *zCom = db_column_text(&q, 2); 148 const char *zCom = db_column_text(&q, 2); 136 const char *zUser = db_column_text(&q, 3); 149 const char *zUser = db_column_text(&q, 3); 137 int fpid = db_column_int(&q, 4); 150 int fpid = db_column_int(&q, 4); 138 int frid = db_column_int(&q, 5); 151 int frid = db_column_int(&q, 5); 139 int mid = db_column_int(&q, 6); 152 int mid = db_column_int(&q, 6); 140 int fnid = db_column_int(&q, 7); 153 int fnid = db_column_int(&q, 7); 141 const char *zCkin = db_column_text(&q,8); 154 const char *zCkin = db_column_text(&q,8); > 155 const char *zBgClr = db_column_text(&q, 9); > 156 const char *zBr = db_column_text(&q, 10); > 157 int gidx; > 158 char zTime[10]; 142 char zShort[20]; 159 char zShort[20]; 143 char zShortCkin[20]; 160 char zShortCkin[20]; > 161 if( zBr==0 ) zBr = "trunk"; > 162 gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr); 144 if( memcmp(zDate, zPrevDate, 10) ){ 163 if( memcmp(zDate, zPrevDate, 10) ){ 145 sprintf(zPrevDate, "%.10s", zDate); 164 sprintf(zPrevDate, "%.10s", zDate); 146 @ <tr><td colspan=3> | 165 @ <tr><td> 147 @ <div class="divider">%s(zPrevDate)</div> | 166 @ <div class="divider"><nobr>%s(zPrevDate)</nobr></div> 148 @ </td></tr> 167 @ </td></tr> 149 } 168 } > 169 memcpy(zTime, &zDate[11], 5); > 170 zTime[5] = 0; 150 @ <tr><td valign="top">%s(&zDate[11])</td> | 171 @ <tr><td valign="top" align="right">%s(zTime)</td> 151 @ <td width="20"></td> < > 172 @ <td width="20" align="left" valign="top"><div id="m%d(gidx)"></div></td> > 173 if( zBgClr && zBgClr[0] ){ > 174 @ <td valign="top" align="left" bgcolor="%h(zBgClr)"> > 175 }else{ 152 @ <td valign="top" align="left"> | 176 @ <td valign="top" align="left"> > 177 } 153 sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); 178 sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); 154 sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); 179 sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); 155 if( g.okHistory ){ 180 if( g.okHistory ){ 156 @ <a href="%s(g.zTop)/artifact/%s(zUuid)">[%s(zShort)]</a> 181 @ <a href="%s(g.zTop)/artifact/%s(zUuid)">[%s(zShort)]</a> 157 }else{ 182 }else{ 158 @ [%s(zShort)] 183 @ [%s(zShort)] 159 } 184 } ................................................................................................................................................................................ 168 } 193 } 169 @ <a href="%s(g.zBaseURL)/annotate?mid=%d(mid)&fnid=%d(fnid)"> 194 @ <a href="%s(g.zBaseURL)/annotate?mid=%d(mid)&fnid=%d(fnid)"> 170 @ [annotate]</a> 195 @ [annotate]</a> 171 @ </td> 196 @ </td> 172 } 197 } 173 } 198 } 174 db_finalize(&q); 199 db_finalize(&q); > 200 if( pGraph ){ > 201 graph_finish(pGraph, 1); > 202 if( pGraph->nErr ){ > 203 graph_free(pGraph); > 204 pGraph = 0; > 205 }else{ > 206 @ <tr><td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div> > 207 } > 208 } 175 @ </table> 209 @ </table> > 210 timeline_output_graph_javascript(pGraph); 176 style_footer(); 211 style_footer(); 177 } 212 }
Changes to src/graph.c
33 #define GR_MAX_RAIL 32 33 #define GR_MAX_RAIL 32 34 34 35 /* The graph appears vertically beside a timeline. Each row in the 35 /* The graph appears vertically beside a timeline. Each row in the 36 ** timeline corresponds to a row in the graph. 36 ** timeline corresponds to a row in the graph. 37 */ 37 */ 38 struct GraphRow { 38 struct GraphRow { 39 int rid; /* The rid for the check-in */ 39 int rid; /* The rid for the check-in */ 40 int isLeaf; /* True if the check-in is an open leaf */ < 41 int nParent; /* Number of parents */ 40 int nParent; /* Number of parents */ 42 int aParent[GR_MAX_PARENT]; /* Array of parents. 0 element is primary .*/ 41 int aParent[GR_MAX_PARENT]; /* Array of parents. 0 element is primary .*/ 43 char *zBranch; /* Branch name */ 42 char *zBranch; /* Branch name */ 44 43 45 GraphRow *pNext; /* Next row down in the list of all rows */ 44 GraphRow *pNext; /* Next row down in the list of all rows */ 46 GraphRow *pPrev; /* Previous row */ 45 GraphRow *pPrev; /* Previous row */ 47 46 48 int idx; /* Row index. First is 1. 0 used for "none" */ 47 int idx; /* Row index. First is 1. 0 used for "none" */ > 48 int isLeaf; /* True if no direct child nodes */ 49 int iRail; /* Which rail this check-in appears on. 0-based.*/ 49 int iRail; /* Which rail this check-in appears on. 0-based.*/ 50 int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */ 50 int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */ 51 int bDescender; /* Raiser from bottom of graph to here. */ 51 int bDescender; /* Raiser from bottom of graph to here. */ 52 u32 mergeIn; /* Merge in from other rails */ 52 u32 mergeIn; /* Merge in from other rails */ 53 int mergeOut; /* Merge out to this rail */ 53 int mergeOut; /* Merge out to this rail */ 54 int mergeUpto; /* Draw the merge rail up to this level */ 54 int mergeUpto; /* Draw the merge rail up to this level */ 55 55 ................................................................................................................................................................................ 61 struct GraphContext { 61 struct GraphContext { 62 int nErr; /* Number of errors encountered */ 62 int nErr; /* Number of errors encountered */ 63 int mxRail; /* Number of rails required to render the graph */ 63 int mxRail; /* Number of rails required to render the graph */ 64 GraphRow *pFirst; /* First row in the list */ 64 GraphRow *pFirst; /* First row in the list */ 65 GraphRow *pLast; /* Last row in the list */ 65 GraphRow *pLast; /* Last row in the list */ 66 int nBranch; /* Number of distinct branches */ 66 int nBranch; /* Number of distinct branches */ 67 char **azBranch; /* Names of the branches */ 67 char **azBranch; /* Names of the branches */ > 68 int nRow; /* Number of rows */ 68 int railMap[GR_MAX_RAIL]; /* Rail order mapping */ 69 int railMap[GR_MAX_RAIL]; /* Rail order mapping */ > 70 int nHash; /* Number of slots in apHash[] */ > 71 GraphRow **apHash; /* Hash table of rows */ 69 }; 72 }; 70 73 71 #endif 74 #endif 72 75 73 /* 76 /* 74 ** Malloc for zeroed space. Panic if unable to provide the 77 ** Malloc for zeroed space. Panic if unable to provide the 75 ** requested space. 78 ** requested space. ................................................................................................................................................................................ 97 while( p->pFirst ){ 100 while( p->pFirst ){ 98 pRow = p->pFirst; 101 pRow = p->pFirst; 99 p->pFirst = pRow->pNext; 102 p->pFirst = pRow->pNext; 100 free(pRow); 103 free(pRow); 101 } 104 } 102 for(i=0; i<p->nBranch; i++) free(p->azBranch[i]); 105 for(i=0; i<p->nBranch; i++) free(p->azBranch[i]); 103 free(p->azBranch); 106 free(p->azBranch); > 107 free(p->apHash); 104 free(p); 108 free(p); 105 } 109 } > 110 > 111 /* > 112 ** Insert a row into the hash table. If there is already another > 113 ** row with the same rid, the other row is replaced. > 114 */ > 115 static void hashInsert(GraphContext *p, GraphRow *pRow){ > 116 int h; > 117 h = pRow->rid % p->nHash; > 118 while( p->apHash[h] && p->apHash[h]->rid!=pRow->rid ){ > 119 h++; > 120 if( h>=p->nHash ) h = 0; > 121 } > 122 p->apHash[h] = pRow; > 123 } > 124 > 125 /* > 126 ** Look up the row with rid. > 127 */ > 128 static GraphRow *hashFind(GraphContext *p, int rid){ > 129 int h = rid % p->nHash; > 130 while( p->apHash[h] && p->apHash[h]->rid!=rid ){ > 131 h++; > 132 if( h>=p->nHash ) h = 0; > 133 } > 134 return p->apHash[h]; > 135 } 106 136 107 /* 137 /* 108 ** Return the canonical pointer for a given branch name. 138 ** Return the canonical pointer for a given branch name. 109 ** Multiple calls to this routine with equivalent strings 139 ** Multiple calls to this routine with equivalent strings 110 ** will return the same pointer. 140 ** will return the same pointer. 111 */ 141 */ 112 static char *persistBranchName(GraphContext *p, const char *zBranch){ 142 static char *persistBranchName(GraphContext *p, const char *zBranch){ ................................................................................................................................................................................ 120 p->azBranch[p->nBranch-1] = mprintf("%s", zBranch); 150 p->azBranch[p->nBranch-1] = mprintf("%s", zBranch); 121 return p->azBranch[p->nBranch-1]; 151 return p->azBranch[p->nBranch-1]; 122 } 152 } 123 153 124 /* 154 /* 125 ** Add a new row t the graph context. Rows are added from top to bottom. 155 ** Add a new row t the graph context. Rows are added from top to bottom. 126 */ 156 */ 127 void graph_add_row( | 157 int graph_add_row( 128 GraphContext *p, /* The context to which the row is added */ 158 GraphContext *p, /* The context to which the row is added */ 129 int rid, /* RID for the check-in */ 159 int rid, /* RID for the check-in */ 130 int isLeaf, /* True if the check-in is an leaf */ < 131 int nParent, /* Number of parents */ 160 int nParent, /* Number of parents */ 132 int *aParent, /* Array of parents */ 161 int *aParent, /* Array of parents */ 133 const char *zBranch /* Branch for this check-in */ 162 const char *zBranch /* Branch for this check-in */ 134 ){ 163 ){ 135 GraphRow *pRow; 164 GraphRow *pRow; 136 165 137 if( p->nErr ) return; | 166 if( p->nErr ) return 0; 138 if( nParent>GR_MAX_PARENT ){ p->nErr++; return; } | 167 if( nParent>GR_MAX_PARENT ){ p->nErr++; return 0; } 139 pRow = (GraphRow*)safeMalloc( sizeof(GraphRow) ); 168 pRow = (GraphRow*)safeMalloc( sizeof(GraphRow) ); 140 pRow->rid = rid; 169 pRow->rid = rid; 141 pRow->isLeaf = isLeaf; < 142 pRow->nParent = nParent; 170 pRow->nParent = nParent; 143 pRow->zBranch = persistBranchName(p, zBranch); 171 pRow->zBranch = persistBranchName(p, zBranch); 144 memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent); 172 memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent); 145 if( p->pFirst==0 ){ 173 if( p->pFirst==0 ){ 146 p->pFirst = pRow; 174 p->pFirst = pRow; 147 }else{ 175 }else{ 148 p->pLast->pNext = pRow; 176 p->pLast->pNext = pRow; 149 } 177 } 150 p->pLast = pRow; 178 p->pLast = pRow; > 179 p->nRow++; > 180 pRow->idx = p->nRow; > 181 return pRow->idx; 151 } 182 } 152 183 153 /* 184 /* 154 ** Return the index of a rail currently not in use for any row between 185 ** Return the index of a rail currently not in use for any row between 155 ** top and bottom, inclusive. 186 ** top and bottom, inclusive. 156 */ 187 */ 157 static int findFreeRail( 188 static int findFreeRail( ................................................................................................................................................................................ 186 } 217 } 187 218 188 /* 219 /* 189 ** Compute the complete graph 220 ** Compute the complete graph 190 */ 221 */ 191 void graph_finish(GraphContext *p, int omitDescenders){ 222 void graph_finish(GraphContext *p, int omitDescenders){ 192 GraphRow *pRow, *pDesc; 223 GraphRow *pRow, *pDesc; 193 Bag allRids; < 194 Bag notLeaf; < 195 int i; 224 int i; 196 int nRow; < 197 u32 mask; 225 u32 mask; 198 u32 inUse; 226 u32 inUse; 199 227 200 if( p==0 || p->pFirst==0 || p->nErr ) return; 228 if( p==0 || p->pFirst==0 || p->nErr ) return; 201 229 202 /* Initialize all rows */ 230 /* Initialize all rows */ 203 bag_init(&allRids); | 231 p->nHash = p->nRow*2 + 1; 204 bag_init(¬Leaf); | 232 p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash ); 205 nRow = 0; < 206 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 233 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 207 if( pRow->pNext ) pRow->pNext->pPrev = pRow; 234 if( pRow->pNext ) pRow->pNext->pPrev = pRow; 208 pRow->idx = ++nRow; < 209 pRow->iRail = -1; 235 pRow->iRail = -1; 210 pRow->mergeOut = -1; 236 pRow->mergeOut = -1; 211 bag_insert(&allRids, pRow->rid); | 237 hashInsert(p, pRow); 212 } 238 } 213 p->mxRail = -1; 239 p->mxRail = -1; 214 240 215 /* Purge merge-parents that are out-of-graph 241 /* Purge merge-parents that are out-of-graph 216 */ 242 */ 217 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 243 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 218 for(i=1; i<pRow->nParent; i++){ 244 for(i=1; i<pRow->nParent; i++){ 219 if( !bag_find(&allRids, pRow->aParent[i]) ){ | 245 if( hashFind(p, pRow->aParent[i])==0 ){ 220 pRow->aParent[i] = pRow->aParent[--pRow->nParent]; 246 pRow->aParent[i] = pRow->aParent[--pRow->nParent]; 221 i--; 247 i--; 222 } 248 } 223 } 249 } > 250 } > 251 > 252 /* Figure out which nodes have no direct children (children on > 253 ** the same rail). Mark such nodes is isLeaf. > 254 */ > 255 memset(p->apHash, 0, sizeof(p->apHash[0])*p->nHash); > 256 for(pRow=p->pLast; pRow; pRow=pRow->pPrev) pRow->isLeaf = 1; > 257 for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ > 258 GraphRow *pParent; > 259 hashInsert(p, pRow); 224 if( pRow->nParent>0 && bag_find(&allRids, pRow->aParent[0]) ){ | 260 if( pRow->nParent>0 225 bag_insert(¬Leaf, pRow->aParent[0]); | 261 && (pParent = hashFind(p, pRow->aParent[0]))!=0 > 262 && pRow->zBranch==pParent->zBranch > 263 ){ > 264 pParent->isLeaf = 0; 226 } 265 } 227 } 266 } 228 267 229 /* Identify rows where the primary parent is off screen. Assign 268 /* Identify rows where the primary parent is off screen. Assign 230 ** each to a rail and draw descenders to the bottom of the screen. 269 ** each to a rail and draw descenders to the bottom of the screen. 231 */ 270 */ 232 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 271 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 233 if( pRow->nParent==0 || !bag_find(&allRids,pRow->aParent[0]) ){ | 272 if( pRow->nParent==0 || hashFind(p,pRow->aParent[0])==0 ){ 234 if( omitDescenders ){ 273 if( omitDescenders ){ 235 pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, 0, 0); 274 pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, 0, 0); 236 }else{ 275 }else{ 237 pRow->iRail = ++p->mxRail; 276 pRow->iRail = ++p->mxRail; 238 } 277 } 239 mask = 1<<(pRow->iRail); 278 mask = 1<<(pRow->iRail); 240 if( omitDescenders ){ 279 if( omitDescenders ){ ................................................................................................................................................................................ 255 */ 294 */ 256 inUse = (1<<(p->mxRail+1))-1; 295 inUse = (1<<(p->mxRail+1))-1; 257 for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ 296 for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ 258 int parentRid; 297 int parentRid; 259 if( pRow->iRail>=0 ) continue; 298 if( pRow->iRail>=0 ) continue; 260 assert( pRow->nParent>0 ); 299 assert( pRow->nParent>0 ); 261 parentRid = pRow->aParent[0]; 300 parentRid = pRow->aParent[0]; 262 assert( bag_find(&allRids, parentRid) ); < 263 for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; pDesc=pDesc->pNext){} 301 for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; pDesc=pDesc->pNext){} 264 if( pDesc==0 ){ 302 if( pDesc==0 ){ 265 /* Time skew */ 303 /* Time skew */ 266 pRow->iRail = ++p->mxRail; 304 pRow->iRail = ++p->mxRail; 267 pRow->railInUse = 1<<pRow->iRail; 305 pRow->railInUse = 1<<pRow->iRail; 268 continue; 306 continue; 269 } 307 } ................................................................................................................................................................................ 270 if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ 308 if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ 271 pRow->iRail = pDesc->iRail; 309 pRow->iRail = pDesc->iRail; 272 }else{ 310 }else{ 273 pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, 0); 311 pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, 0); 274 } 312 } 275 pDesc->aiRaiser[pRow->iRail] = pRow->idx; 313 pDesc->aiRaiser[pRow->iRail] = pRow->idx; 276 mask = 1<<pRow->iRail; 314 mask = 1<<pRow->iRail; 277 if( bag_find(¬Leaf, pRow->rid) ){ | 315 if( pRow->isLeaf ){ 278 inUse |= mask; | 316 inUse &= ~mask; 279 }else{ 317 }else{ 280 inUse &= ~mask; | 318 inUse |= mask; 281 } 319 } 282 for(pDesc = pRow; ; pDesc=pDesc->pNext){ 320 for(pDesc = pRow; ; pDesc=pDesc->pNext){ 283 assert( pDesc!=0 ); 321 assert( pDesc!=0 ); 284 pDesc->railInUse |= mask; 322 pDesc->railInUse |= mask; 285 if( pDesc->rid==parentRid ) break; 323 if( pDesc->rid==parentRid ) break; 286 } 324 } 287 } 325 } ................................................................................................................................................................................ 307 } 345 } 308 } 346 } 309 pRow->mergeIn |= 1<<pDesc->mergeOut; 347 pRow->mergeIn |= 1<<pDesc->mergeOut; 310 } 348 } 311 } 349 } 312 350 313 /* 351 /* 314 ** Sort the rail numbers | 352 ** Find the maximum rail number. 315 */ 353 */ 316 #if 0 < 317 p->mxRail = -1; < 318 mask = 0; < 319 for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ < 320 if( (mask & (1<<pRow->iRail))==0 ){ < 321 p->railMap[pRow->iRail] = ++p->mxRail; < 322 mask |= 1<<pRow->iRail; < 323 } < 324 if( pRow->mergeOut>=0 && (mask & (1<<pRow->mergeOut))==0 ){ < 325 p->railMap[pRow->mergeOut] = ++p->mxRail; < 326 mask |= 1<<pRow->mergeOut; < 327 } < 328 } < 329 #else < 330 for(i=0; i<GR_MAX_RAIL; i++) p->railMap[i] = i; 354 for(i=0; i<GR_MAX_RAIL; i++) p->railMap[i] = i; 331 p->mxRail = 0; 355 p->mxRail = 0; 332 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 356 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ 333 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail; 357 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail; 334 if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut; 358 if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut; 335 } 359 } 336 #endif < 337 } 360 }
Changes to src/timeline.c
251 @ </td></tr> 251 @ </td></tr> 252 } 252 } 253 memcpy(zTime, &zDate[11], 5); 253 memcpy(zTime, &zDate[11], 5); 254 zTime[5] = 0; 254 zTime[5] = 0; 255 @ <tr> 255 @ <tr> 256 @ <td valign="top" align="right">%s(zTime)</td> 256 @ <td valign="top" align="right">%s(zTime)</td> 257 @ <td width="20" align="left" valign="top"> 257 @ <td width="20" align="left" valign="top"> > 258 if( pGraph ){ > 259 int nParent = 0; > 260 int aParent[32]; > 261 const char *zBr; > 262 int gidx; > 263 static Stmt qparent; > 264 static Stmt qbranch; > 265 db_static_prepare(&qparent, > 266 "SELECT pid FROM plink WHERE cid=:rid ORDER BY isprim DESC" > 267 ); > 268 db_static_prepare(&qbranch, > 269 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid", > 270 TAG_BRANCH > 271 ); > 272 db_bind_int(&qparent, ":rid", rid); > 273 while( db_step(&qparent)==SQLITE_ROW && nParent<32 ){ > 274 aParent[nParent++] = db_column_int(&qparent, 0); > 275 } > 276 db_reset(&qparent); > 277 db_bind_int(&qbranch, ":rid", rid); > 278 if( db_step(&qbranch)==SQLITE_ROW ){ > 279 zBr = db_column_text(&qbranch, 0); > 280 }else{ > 281 zBr = "trunk"; > 282 } > 283 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr); > 284 db_reset(&qbranch); 258 @ <div id="m%d(rid)"></div> | 285 @ <div id="m%d(gidx)"></div> > 286 } 259 if( zBgClr && zBgClr[0] ){ 287 if( zBgClr && zBgClr[0] ){ 260 @ <td valign="top" align="left" bgcolor="%h(zBgClr)"> 288 @ <td valign="top" align="left" bgcolor="%h(zBgClr)"> 261 }else{ 289 }else{ 262 @ <td valign="top" align="left"> 290 @ <td valign="top" align="left"> 263 } 291 } 264 if( zType[0]=='c' ){ 292 if( zType[0]=='c' ){ 265 const char *azTag[5]; 293 const char *azTag[5]; ................................................................................................................................................................................ 288 } 316 } 289 if( nTag>0 ){ 317 if( nTag>0 ){ 290 int i; 318 int i; 291 for(i=0; i<nTag; i++){ 319 for(i=0; i<nTag; i++){ 292 @ <b>%s(azTag[i])%s(i==nTag-1?"":",")</b> 320 @ <b>%s(azTag[i])%s(i==nTag-1?"":",")</b> 293 } 321 } 294 } 322 } 295 if( pGraph ){ < 296 int nParent = 0; < 297 int aParent[32]; < 298 const char *zBr; < 299 static Stmt qparent; < 300 static Stmt qbranch; < 301 db_static_prepare(&qparent, < 302 "SELECT pid FROM plink WHERE cid=:rid ORDER BY isprim DESC" < 303 ); < 304 db_static_prepare(&qbranch, < 305 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid", < 306 TAG_BRANCH < 307 ); < 308 db_bind_int(&qparent, ":rid", rid); < 309 while( db_step(&qparent)==SQLITE_ROW && nParent<32 ){ < 310 aParent[nParent++] = db_column_int(&qparent, 0); < 311 } < 312 db_reset(&qparent); < 313 db_bind_int(&qbranch, ":rid", rid); < 314 if( db_step(&qbranch)==SQLITE_ROW ){ < 315 zBr = db_column_text(&qbranch, 0); < 316 }else{ < 317 zBr = "trunk"; < 318 } < 319 graph_add_row(pGraph, rid, isLeaf, nParent, aParent, zBr); < 320 db_reset(&qbranch); < 321 } < 322 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){ 323 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){ 323 hyperlink_to_uuid(zUuid); 324 hyperlink_to_uuid(zUuid); 324 } 325 } 325 db_column_blob(pQuery, commentColumn, &comment); 326 db_column_blob(pQuery, commentColumn, &comment); 326 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){ 327 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){ 327 Blob truncated; 328 Blob truncated; 328 blob_zero(&truncated); 329 blob_zero(&truncated); ................................................................................................................................................................................ 356 graph_free(pGraph); 357 graph_free(pGraph); 357 pGraph = 0; 358 pGraph = 0; 358 }else{ 359 }else{ 359 @ <tr><td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div> 360 @ <tr><td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div> 360 } 361 } 361 } 362 } 362 @ </table> 363 @ </table> > 364 timeline_output_graph_javascript(pGraph); > 365 } > 366 > 367 /* > 368 ** Generate all of the necessary javascript to generate a timeline > 369 ** graph. > 370 */ > 371 void timeline_output_graph_javascript(GraphContext *pGraph){ 363 if( pGraph && pGraph->nErr==0 ){ 372 if( pGraph && pGraph->nErr==0 ){ 364 GraphRow *pRow; 373 GraphRow *pRow; 365 int i; 374 int i; 366 char cSep; 375 char cSep; 367 @ <script type="text/JavaScript"> 376 @ <script type="text/JavaScript"> 368 cgi_printf("var rowinfo = [\n"); 377 cgi_printf("var rowinfo = [\n"); 369 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){ 378 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){ 370 cgi_printf("{id:\"m%d\",r:%d,d:%d,mo:%d,mu:%d,u:%d,au:", 379 cgi_printf("{id:\"m%d\",r:%d,d:%d,mo:%d,mu:%d,u:%d,au:", 371 pRow->rid, | 380 pRow->idx, 372 pRow->iRail, 381 pRow->iRail, 373 pRow->bDescender, 382 pRow->bDescender, 374 pRow->mergeOut, 383 pRow->mergeOut, 375 pRow->mergeUpto, 384 pRow->mergeUpto, 376 pRow->aiRaiser[pRow->iRail] 385 pRow->aiRaiser[pRow->iRail] 377 ); 386 ); 378 cSep = '['; 387 cSep = '[';