Check-in [f0c8693845]
Not logged in
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
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);