Overview
SHA1 Hash: | f0c8693845d31d6592eafd35e4243f2e800cfba5 |
---|---|
Date: | 2008-10-20 06:41:12 |
User: | drh |
Comment: | More improvements to the timeline display of ticket changes. |
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/manifest.c from [053fee443e] to [3d201247f1].
@@ -892,18 +892,26 @@ TAG_COMMENT, rid ); free(zComment); } if( m.type==CFTYPE_TICKET ){ + int i; + char *zTitle; char *zTag; Blob comment; + char *zNewStatus = 0; + static char *zTitleExpr = 0; + static char *zStatusColumn = 0; + static int once = 1; + int isNew; - ticket_insert(&m, 1, 1); + isNew = ticket_insert(&m, 1, 1); zTag = mprintf("tkt-%s", m.zTicketUuid); tag_insert(zTag, 1, 0, rid, m.rDate, rid); free(zTag); blob_zero(&comment); +#if 0 if( m.nField==1 ){ if( m.aField[0].zName[0]=='+' ){ blob_appendf(&comment, "Appended to %h in ticket [%.10s]", &m.aField[0].zName[1], m.zTicketUuid @@ -918,11 +926,10 @@ "Changed %h in ticket [%.10s]", m.aField[0].zName, m.zTicketUuid ); } }else{ -#if 0 int i; const char *z; const char *zSep = " "; blob_appendf(&comment, "%d changes to ticket [%.10s]:", m.nField, m.zTicketUuid); @@ -930,13 +937,62 @@ z = m.aField[i].zName; if( z[0]=='+' ) z++; blob_appendf(&comment, "%s%h", zSep, z); zSep = ", "; } -#endif + int i; + const char *zStatus = 0; + const char *zTitle; + for(i=0; i<m.nField; i++){ + z = m.aField[i].zName; + if( strcmp(z, "status") ) zStatus = m.aField[i].zValue; + } + if( zField blob_appendf(&comment, "Edits to ticket [%.10s]", m.zTicketUuid); } +#endif + if( once ){ + once = 0; + zTitleExpr = db_get("ticket-title-expr", "title"); + zStatusColumn = db_get("ticket-status-column", "status"); + } + zTitle = db_text("unknown", + "SELECT %s FROM ticket WHERE tkt_uuid='%s'", + zTitleExpr, m.zTicketUuid + ); + if( !isNew ){ + for(i=0; i<m.nField; i++){ + if( strcmp(m.aField[i].zName, zStatusColumn)==0 ){ + zNewStatus = m.aField[i].zValue; + } + } + if( zNewStatus ){ + blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>", + zNewStatus, m.zTicketUuid, zTitle + ); + if( m.nField>1 ){ + blob_appendf(&comment, " plus %d other change%s", + m.nField-1, m.nField==2 ? "" : "s"); + } + }else{ + zNewStatus = db_text("unknown", + "SELECT %s FROM ticket WHERE tkt_uuid='%s'", + zStatusColumn, m.zTicketUuid + ); + blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with " + "%d other change%s", + m.zTicketUuid, zTitle, zNewStatus, m.nField, + m.nField==1 ? "" : "s" + ); + free(zNewStatus); + } + }else{ + blob_appendf(&comment, "New ticket [%.10s] <i>%h</i>.", + m.zTicketUuid, zTitle + ); + } + free(zTitle); db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('t',%.17g,%d,%Q,%Q)", m.rDate, rid, m.zUser, blob_str(&comment) );
Modified src/tkt.c from [e980babe0a] to [e278b1f557].
@@ -186,21 +186,26 @@ ** Update an entry of the TICKET table according to the information ** in the control file given in p. Attempt to create the appropriate ** TICKET table entry if createFlag is true. If createFlag is false, ** that means we already know the entry exists and so we can save the ** work of trying to create it. +** +** Return TRUE if a new TICKET entry was created and FALSE if an +** existing entry was revised. */ -void ticket_insert(Manifest *p, int createFlag, int checkTime){ +int ticket_insert(Manifest *p, int createFlag, int checkTime){ Blob sql; Stmt q; int i; const char *zSep; + int rc = 0; getAllTicketFields(); if( createFlag ){ db_multi_exec("INSERT OR IGNORE INTO ticket(tkt_uuid, tkt_mtime) " "VALUES(%Q, 0)", p->zTicketUuid); + rc = db_changes(); } blob_zero(&sql); blob_appendf(&sql, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); zSep = "SET"; for(i=0; i<p->nField; i++){ @@ -229,10 +234,11 @@ } db_multi_exec("INSERT OR IGNORE INTO _pending_ticket " "VALUES(%Q)", p->zTicketUuid); } blob_reset(&sql); + return rc; } /* ** Rebuild an entire entry in the TICKET table */
Modified src/tktsetup.c from [c8d31b703f] to [953c7e0a99].
@@ -642,12 +642,16 @@ login_insert_csrf_secret(); @ <hr> entry_attribute("Ticket Title", 40, "ticket-title-expr", "t", "title"); @ <p>An SQL expression in a query against the TICKET table that will - @ return the title of the ticket for display purposes after hyperlinks to - @ that ticket</p> + @ return the title of the ticket for display purposes.</p> + + @ <hr> + entry_attribute("Ticket Status", 40, "ticket-status-column", "s", "status"); + @ <p>The name of the column in the TICKET table that contains the ticket + @ status in human-readable form. Case sensitive.</p> @ <hr> entry_attribute("Ticket Closed", 40, "ticket-closed-expr", "c", "status='Closed'"); @ <p>An SQL expression that evaluates to true in a TICKET table query if
Modified src/wikiformat.c from [ef5196ba6c] to [ad6f4b4c31].
@@ -868,18 +868,16 @@ return 1; } /* ** zTarget is guaranteed to be a UUID. It might be the UUID of a ticket. -** If it is, fill zDisplay[0..nDisplay-1] with the title of the ticket -** (or a prefix if the title is too long) and return true. If zTarget +** If it is, store in *pClosed a true or false depending on whether or not +** the ticket is closed and return true. If zTarget ** is not the UUID of a ticket, return false. */ static int is_ticket( const char *zTarget, /* Ticket UUID */ - char *zDisplay, /* Space in which to write ticket title */ - int nDisplay, /* Bytes available in zDisplay[] */ int *pClosed /* True if the ticket is closed */ ){ static Stmt q; static int once = 1; int n; @@ -890,107 +888,97 @@ memcpy(zLower, zTarget, n+1); canonical16(zLower, n+1); memcpy(zUpper, zLower, n+1); zUpper[n-1]++; if( once ){ - const char *zTitleExpr = db_get("ticket-title-expr", "title"); const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'"); db_static_prepare(&q, - "SELECT %s, %s FROM ticket " + "SELECT %s FROM ticket " " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr", - zTitleExpr, zClosedExpr + zClosedExpr ); + once = 0; } db_bind_text(&q, ":lwr", zLower); db_bind_text(&q, ":upr", zUpper); if( db_step(&q)==SQLITE_ROW ){ - n = db_column_bytes(&q,0); - if( n>nDisplay-1 ) n = nDisplay - 1; - memcpy(zDisplay, db_column_text(&q, 0), n); - zDisplay[n] = 0; rc = 1; - *pClosed = db_column_int(&q, 1); + *pClosed = db_column_int(&q, 0); }else{ rc = 0; } db_reset(&q); return rc; } /* ** Resolve a hyperlink. The zTarget argument is the content of the [...] -** in the wiki. Append an <a> markup to the output of the Renderer. +** in the wiki. Append to the output string whatever text is approprate +** for opening the hyperlink. Write into zClose[0...nClose-1] text that will +** close the markup. ** ** Actually, this routine might or might not append the hyperlink, depending ** on current rendering rules: specifically does the current user have -** "History" permission. If this routine does append the <a> and thus needs -** a </a> to follow, it returns true. If the <a> is suppressed, then return -** false. -** -** If nDisplay>0 then optionally write up to nDisplay bytes of -** alternative display text into zDisplay. The text must be zero -** terminated. The final zero is included in the nDisplay byte count -** limit. +** "History" permission. */ -static int resolveHyperlink( +static void openHyperlink( Renderer *p, /* Rendering context */ const char *zTarget, /* Hyperlink traget; text within [...] */ - char *zDisplay, /* Space in which to write alternative display */ - int nDisplay /* Bytes available in zDisplay[] */ + char *zClose, /* Write hyperlink closing text here */ + int nClose /* Bytes available in zClose[] */ ){ - int rc = 0; + const char *zTerm = "</a>"; + assert( nClose>10 ); + if( strncmp(zTarget, "http:", 5)==0 || strncmp(zTarget, "https:", 6)==0 || strncmp(zTarget, "ftp:", 4)==0 || strncmp(zTarget, "mailto:", 7)==0 ){ blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); - rc = 1; }else if( zTarget[0]=='/' ){ if( g.okHistory ){ blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget); - rc = 1; + }else{ + zTerm = ""; } }else if( is_valid_uuid(zTarget) ){ int isClosed; - if( nDisplay && is_ticket(zTarget, zDisplay, nDisplay, &isClosed) ){ + if( is_ticket(zTarget, &isClosed) ){ /* Special display processing for tickets. Display the hyperlink - ** as crossed out if the ticket is closed. Add the title after the - ** hyperlink. + ** as crossed out if the ticket is closed. */ if( isClosed ){ if( g.okHistory ){ - blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[<s>%s</s>]</a>: %s", - g.zBaseURL, zTarget, zTarget, zDisplay + blob_appendf(p->pOut,"<a href=\"%s/info/%s\"><s>", + g.zBaseURL, zTarget ); + zTerm = "</s></a>"; }else{ - blob_appendf(p->pOut,"[<s>%s</s>]: %s", zTarget, zDisplay); + blob_appendf(p->pOut,"<s>"); + zTerm = "</s>"; } }else{ if( g.okHistory ){ - blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[%s]</a>: %s", - g.zBaseURL, zTarget, zTarget, zDisplay + blob_appendf(p->pOut,"<a href=\"%s/info/%s\">", + g.zBaseURL, zTarget ); }else{ - blob_appendf(p->pOut,"[%s]: %s", zTarget, zDisplay); + zTerm = ""; } } - zDisplay[0] = ' '; - zDisplay[1] = 0; - rc = 0; }else if( g.okHistory ){ blob_appendf(p->pOut, "<a href=\"%s/info/%s\">", g.zBaseURL, zTarget); - rc = 1; } }else if( wiki_name_is_wellformed(zTarget) ){ blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zBaseURL, zTarget); - rc = 1; }else{ blob_appendf(p->pOut, "[bad-link: %h]", zTarget); - rc = 0; + zTerm = ""; } - return rc; + assert( strlen(zTerm)<nClose ); + strcpy(zClose, zTerm); } /* ** Check to see if the given parsed markup is the correct ** </verbatim> tag. @@ -1111,13 +1099,11 @@ case TOKEN_LINK: { char *zTarget; char *zDisplay = 0; int i, j; int savedState; - int needCloseA; - int altSize; - char zAltDisplay[100]; + char zClose[20]; startAutoParagraph(p); zTarget = &z[1]; for(i=1; z[i] && z[i]!=']'; i++){ if( z[i]=='|' && zDisplay==0 ){ @@ -1127,27 +1113,20 @@ } } z[i] = 0; if( zDisplay==0 ){ zDisplay = zTarget; - altSize = sizeof(zAltDisplay); }else{ while( isspace(*zDisplay) ) zDisplay++; - altSize = 0; } - zAltDisplay[0] = 0; - needCloseA = resolveHyperlink(p, zTarget, zAltDisplay, altSize); + openHyperlink(p, zTarget, zClose, sizeof(zClose)); savedState = p->state; p->state &= ~ALLOW_WIKI; p->state |= FONT_MARKUP_ONLY; - if( zAltDisplay[0] ){ - wiki_render(p, zAltDisplay); - }else{ - wiki_render(p, zDisplay); - } + wiki_render(p, zDisplay); p->state = savedState; - if( needCloseA ) blob_append(p->pOut, "</a>", 4); + blob_append(p->pOut, zClose, -1); break; } case TOKEN_TEXT: { startAutoParagraph(p); blob_append(p->pOut, z, n);