/* hgVisiGene - Gene Picture Browser. */ #include "common.h" #include "linefile.h" #include "hash.h" #include "options.h" #include "htmshell.h" #include "cheapcgi.h" #include "net.h" #include "portable.h" #include "cart.h" #include "hui.h" #include "hdb.h" #include "hgColors.h" #include "web.h" #include "visiGene.h" #include "hgVisiGene.h" #include "captionElement.h" #include "visiSearch.h" #include "probePage.h" #include "configPage.h" #include "printCaption.h" #include "trashDir.h" /* Globals */ struct cart *cart; /* Current CGI values */ struct hash *oldCart; /* Previous CGI values */ char *visiDb = VISIGENE; /* The visiGene database name */ struct sqlConnCache *visiConnCache; /* Cache of connections to database. */ char *hgVisiGeneShortName() /* Return short descriptive name (not cgi-executable name) * of program */ { return "VisiGene"; } char *hgVisiGeneCgiName() /* Return name of executable. */ { return "../cgi-bin/hgVisiGene"; } char *shortOrgName(char *binomial) /* Return short name for taxon - scientific or common whatever is * shorter */ { static struct hash *hash = NULL; char *name; if (hash == NULL) hash = hashNew(0); name = hashFindVal(hash, binomial); if (name == NULL) { struct sqlConnection *conn = sqlConnect("uniProt"); char query[256], **row; struct sqlResult *sr; int nameSize = strlen(binomial); name = cloneString(binomial); safef(query, sizeof(query), "select commonName.val from commonName,taxon " "where taxon.binomial = '%s' and taxon.id = commonName.taxon" , binomial); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { int len = strlen(row[0]); if (len < nameSize) { freeMem(name); name = cloneString(row[0]); nameSize = len; } } sqlFreeResult(&sr); sqlDisconnect(&conn); hashAdd(hash, binomial, name); } return name; } char *makeCommaSpacedList(struct slName *list) /* Turn linked list of strings into a single string with * elements separated by a comma and a space. You can * freeMem the result when done. */ { int totalSize = 0, elCount = 0; struct slName *el; for (el = list; el != NULL; el = el->next) { if (el->name[0] != 0) { totalSize += strlen(el->name); elCount += 1; } } if (elCount == 0) return cloneString("n/a"); else { char *pt, *result; totalSize += 2*(elCount-1); /* Space for ", " */ pt = result = needMem(totalSize+1); strcpy(pt, list->name); pt += strlen(list->name); for (el = list->next; el != NULL; el = el->next) { *pt++ = ','; *pt++ = ' '; strcpy(pt, el->name); pt += strlen(el->name); } return result; } } #ifdef UNUSED struct sqlConnection *vAllocConn() /* Get a connection from connection cache */ { return sqlAllocConnection(visiConnCache); } void vFreeConn(struct sqlConnection **pConn) /* Free up connection from connection cache. */ { sqlFreeConnection(visiConnCache, pConn); } #endif /* UNUSED */ #ifdef UNUSED int visiGeneMaxImageId(struct sqlConnection *conn) /* Get the largest image ID. Currently all images between * 1 and this exist, though I wouldn't count on this always * being true. */ { char query[256]; safef(query, sizeof(query), "select max(id) from image"); return sqlQuickNum(conn, query); } #endif /* UNUSED */ static void saveMatchFile(char *fileName, struct visiMatch *matchList) /* Save out matches to file name */ { struct visiMatch *match; FILE *f = mustOpen(fileName, "w"); for (match = matchList; match != NULL; match = match->next) fprintf(f, "%d\t%f\n", match->imageId, match->weight); carefulClose(&f); } static struct visiMatch *readMatchFile(char *fileName) /* Read in match file */ { struct visiMatch *matchList = NULL, *match; struct lineFile *lf = lineFileMayOpen(fileName, TRUE); if (lf != NULL) { char *row[2]; while (lineFileRow(lf, row)) { AllocVar(match); match->imageId = lineFileNeedNum(lf, row, 0); match->weight = lineFileNeedDouble(lf, row, 1); slAddHead(&matchList, match); } lineFileClose(&lf); slReverse(&matchList); } return matchList; } static struct visiMatch *onePerImageFile(struct sqlConnection *conn, struct visiMatch *matchList) /* Return image list that filters out second occurence of * same imageFile. */ { struct visiMatch *newList = NULL, *match, *next; struct hash *uniqHash = newHash(0); char query[256]; for (match = matchList; match != NULL; match = next) { char hashName[16]; int imageFile; next = match->next; safef(query, sizeof(query), "select imageFile from image where id=%d", match->imageId); imageFile = sqlQuickNum(conn, query); if (imageFile != 0) { safef(hashName, sizeof(hashName), "%x", imageFile); if (!hashLookup(uniqHash, hashName)) { hashAdd(uniqHash, hashName, NULL); slAddHead(&newList, match); match = NULL; } } freez(&match); } hashFree(&uniqHash); slReverse(&newList); return newList; } static void doThumbnails(struct sqlConnection *conn) /* Write out list of thumbnail images. */ { char *sidUrl = cartSidUrlString(cart); char *listSpec = cartUsualString(cart, hgpListSpec, ""); char *matchFile = cartString(cart, hgpMatchFile); struct visiMatch *matchList = NULL, *match; int maxCount = 25, count = 0; int startAt = cartUsualInt(cart, hgpStartAt, 0); int imageCount; htmlSetStyle( "\n" ); htmlSetBgColor(0xC0C0D6); htmStart(stdout, "doThumbnails"); matchList = readMatchFile(matchFile); imageCount = slCount(matchList); if (imageCount > 0) { printf( "
");
printf("%d images match \n", imageCount); printf(" |
");
printf("",
hgVisiGeneCgiName(),
sidUrl, hgpId, id, hgpDoImage);
printf(" \n", imageFile); smallCaption(conn, id); printf(" \n"); printf(" | ");
printf("
\n" "The following image collections are currently available for browsing: \n" "
\n" "Following a successful search, VisiGene displays a list of thumbnails of \n" "images matching the search criteria \n" "in the lefthand pane of the browser. By default, the image corresponding to \n" "the first thumbnail in the list is displayed in the main image pane. \n" "If more than 25 images meet the search criteria, links at the bottom of \n" "the thumbnail pane allow the user to toggle among pages of search results. \n" "To display a different image in the main browser pane, \n" "click the thumbnail of the image you wish to view.
\n" "\n" "By default, an image is displayed at a resolution that provides \n" "optimal viewing of the overall image. This size varies among images. \n" "The image may be zoomed in or out, sized to match the resolution of the \n" "original image or best fit the image display window, and moved or \n" "scrolled in any direction to focus on areas of interest. \n" "
\n" "Zooming in: To enlarge the image by 2X, click the Zoom in \n" "button above the image or click on the image using the left mouse button. \n" "Alternatively, the + key may be used to zoom in when the main image pane is \n" "the active window.
\n" "\n" "Zooming out: To reduce the image by 2X, click the Zoom out \n" "button above the image or click on the image using the right mouse button. \n" "Alternatively, the - key may be used to zoom out when the main image pane \n" "is the active window.
\n" "\n" "Sizing to full resolution: Click the Zoom full button above \n" "the image to resize the image such that each pixel on the screen \n" "corresponds to a pixel in the digitized image.
\n" "\n" "Sizing to best fit: Click the Zoom fit button above \n" "the image to zoom the image to the size that best fits the main image \n" "pane.
\n" "\n" "Moving the image: To move the image viewing area in any direction, \n" "click and drag the image using the mouse. Alternatively, the following \n" "keyboard shortcuts may be used after clicking on the image: \n" "
\n" "VisiGene was written by Jim Kent and Galt Barber. \n" "Contact Jim if you have \n" "an image set you would like to contribute for display.
\n" ); } void doInitialPage() /* Put up page with search box that explains program and * some good things to search on. */ { char *listSpec = NULL; webStartWrapperDetailedNoArgs(cart, NULL, "", "VisiGene Image Browser", FALSE, FALSE, FALSE, TRUE); printf("\n"); doHelp(); webEnd(); } void doDefault(struct sqlConnection *conn, boolean newSearch) /* Put up default page - if there is no specific do variable. */ { char *listSpec = cartUsualString(cart, hgpListSpec, ""); listSpec = skipLeadingSpaces(listSpec); if (listSpec[0] == 0) doInitialPage(); else doFrame(conn, newSearch); } void doId(struct sqlConnection *conn) /* Set up Gene Pix on given ID. */ { int id = cartInt(cart, hgpDoId); struct slName *genes = visiGeneGeneName(conn, id); if (genes == NULL) { cartRemove(cart, hgpListSpec); cartRemove(cart, hgpId); } else { cartSetInt(cart, hgpId, id); cartSetString(cart, hgpListSpec, genes->name); } slFreeList(&genes); doDefault(conn, FALSE); } static void problemPage(char *msg, char *url) /* send back a page describing problem */ { printf("Content-Type: text/html\n"); printf("\n"); htmStart(stdout, "do download"); printf("%s %s",msg,url); htmlEnd(); } static void doDownload(struct sqlConnection *conn) /* Try to force user's browser to download by giving special response headers */ { int imageId = cartUsualInt(cart, hgpId, 0); char url[1024]; char *p = NULL; char dir[256]; char name[128]; char extension[64]; int w = 0, h = 0; int sd = -1; if (!visiGeneImageSize(conn, imageId, &w, &h)) imageId = 0; if (imageId == 0) { problemPage("invalid imageId",""); } else { p=visiGeneFullSizePath(conn, imageId); splitPath(p, dir, name, extension); safef(url,sizeof(url),"%s%s%s", dir, name, extension); sd = netUrlOpen(url); if (sd < 0) { problemPage("Couldn't open", url); } else { char *newUrl = NULL; int newSd = 0; /* url needed for err msgs and redirect url*/ if (netSkipHttpHeaderLinesHandlingRedirect(sd, url, &newSd, &newUrl)) { char buf[32*1024]; int readSize; if (newUrl) { freeMem(newUrl); sd = newSd; } printf("Content-Type: application/octet-stream\n"); printf("Content-Disposition: attachment; filename=%s%s\n", name, extension); printf("\n"); while ((readSize = read(sd, buf, sizeof(buf))) > 0) fwrite(buf, 1, readSize, stdout); close(sd); sd = -1; fflush(stdout); fclose(stdout); } else { problemPage("Skip http header problem", url); } freeMem(newUrl); } } } void dispatch() /* Set up a connection to database and dispatch control * based on hgpDo type var. */ { struct sqlConnection *conn = sqlConnect(visiDb); if (cartVarExists(cart, hgpDoThumbnails)) doThumbnails(conn); else if (cartVarExists(cart, hgpDoImage)) doImage(conn); else if (cartVarExists(cart, hgpDoProbe)) doProbe(conn); else if (cartVarExists(cart, hgpDoControls)) doControls(conn); else if (cartVarExists(cart, hgpDoId)) doId(conn); #ifdef SOON else if (cartVarExists(cart, hgpDoConfig)) configPage(conn); #endif /* SOON */ else if (cartVarExists(cart, hgpDoSearch)) doDefault(conn, TRUE); else { char *oldListSpec = hashFindVal(oldCart, hgpListSpec); char *newListSpec = cartOptionalString(cart, hgpListSpec); boolean isNew = differentStringNullOk(oldListSpec, newListSpec); doDefault(conn, isNew); } cartRemovePrefix(cart, hgpDoPrefix); } void doMiddle(struct cart *theCart) /* Save cart to global, print time, call dispatch */ { cart = theCart; // visiConnCache = sqlNewConnCache(visiDb); dispatch(); // sqlFreeConnCache(&visiConnCache); } char *excludeVars[] = {"Submit", "submit", NULL}; int main(int argc, char *argv[]) /* Process command line. */ { long enteredMainTime = clock1000(); uglyTime(NULL); cgiSpoof(&argc, argv); oldCart = hashNew(0); if (cgiVarExists(hgpDoDownload)) /* use cgiVars -- do not commit to any cart method yet */ { struct sqlConnection *conn = sqlConnect(visiDb); cart = cartAndCookieNoContent(hUserCookie(), excludeVars, oldCart); doDownload(conn); cartCheckout(&cart); } else { cartEmptyShell(doMiddle, hUserCookie(), excludeVars, oldCart); } cgiExitTime("hgVisiGene", enteredMainTime); return 0; }