/* File: querydisp.c * Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1991 * ------------------------------------------------------------------- * Acedb is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: ** Constructs general queries. ** *** Gary Aochi modified version of querydisp.c * Exported functions: ** queryCreate * HISTORY: * Last edited: May 6 13:55 2003 (edgrif) * * Jun 3 12:19 1996 (rd) * * Feb 09 15:30 1993 (aochi): split off qbe to qbedisp.c and query_.h * and cleaned up some code in querydisp.c * * Jun 14 10:14:40 PDT 1993 (aochi) : split querydisp.c into 2 files: * querydisp.c (ctrl), querybuild.c * * Jan 18 12:55 1993 (mieg): Changed MAGIC and added some static def * (original querydisp.c created Mon Dec 30 19:05:47 1991 (mieg)) * Created: Jun 14 10:14:40 PDT 1993 (aochi) *------------------------------------------------------------------- * gha 03/02/93 (changed selection list to keyset) * gha 03/09/93 (querpick ifs, fixed queryCommandEdit(off1.9)) * gha 04/09/93 added > to indicate last query, hit rtn to go thru queries * gha 04/28/93 jean cleaned up stuff, temporarily have hidden stuff, * changed >? to Find, > to Follow, fixed classlist * added code to unhighlight some buttons * gha 05/25/93 added jean's new Search stuff and changes he made. * gha 06/14/93 reduced new querydisp.c from querydisp.c */ /* $Id: querydisp.c,v 1.26 2003/05/06 13:13:17 edgrif Exp $ */ #include #include "acedb.h" #include "lex.h" #include "bs.h" /* used for bsTagsInClass() procedure */ #include "query_.h" #include "query.h" #include "parse.h" #include "dbpath.h" #include "display.h" #include "keysetdisp.h" typedef struct QCTRLSTUFF { int magic; /* == MAGIC*/ Graph graph ; char dirName[DIR_BUFFER_SIZE] ; char fileName[FIL_BUFFER_SIZE] ; int pgmBox ; int curr ; int last_find ; FILE *fil ; BOOL modif ; Array pgm ; /* array of Stack, each one a program line */ char flagmask; /* control mask, 8 bits of togglable settings */ } *QUER ; Graph querGraph = 0 ; KEYSET query_undo_set ; #define FILENAME_SIZE 24 static int MAGIC = 92443 ; /* also use address as graphAss handle */ #define NO_AUTOSV 0x01 #define SETFLAG(y) quer->flagmask = (quer->flagmask | y) #define TESTFLAG(y) (quer->flagmask & y) #define RMFLAG(y) quer->flagmask = (quer->flagmask & ~y) static void querDisplay(void) ; static void querPick (int k, double x_unused, double y_unused, int modifier_unused) ; void queryCreate (void) ; #define QUERGET(name) QUER quer ; \ \ if(!graphActivate(querGraph)) \ messcrash("%s can't find querGraph", name); \ if (!graphAssFind (&MAGIC, &quer)) \ messcrash ("%s can't find graph", name) ; \ if (quer->magic != MAGIC) \ messcrash ("%s received a wrong pointer", name) ; \ displayPreserve() /*********** stuff local to the quer routine and initialiser **********/ /************************************************************************/ static Array dirMarks = 0 ; static Stack dirStack = 0 ; /************************* AUTOSAVE STUFF **************************/ /* gha 11-2-92: will save to date-time-stamp file if no filename specified */ static char auto_filename[FILENAME_SIZE]; static char *autosaveCreateName(void) { char *tstamp = timeShow (time(0)) ; tstamp[13] = 0 ; /* truncate at 10's of minutes */ return tstamp ; } /* if active, save the query commands to a file when "Search" invoked */ static void autoSave(void) { int i ; FILE *fil ; QUERGET("autoSave"); if (TESTFLAG(NO_AUTOSV)) return; if (!graphExists (quer->graph) || !quer->pgm || arrayMax(quer->pgm) <= 1) /* nothing to save */ return ; strcpy (auto_filename, autosaveCreateName()) ; if (!strcmp (quer->fileName, auto_filename)) { messout ("Warning: autosave-query filename conflict: %s.\n" "Using different autosave name: %sX.", auto_filename, auto_filename) ; strcat (auto_filename, "X"); } fil = filopen (messprintf ("wquery/%s", auto_filename), "qry", "a+") ; if (!fil) return ; for(i=0; i < arrayMax(quer->pgm) ; i++) fprintf (fil,"%s\n", ARR2STRING(quer->pgm, i)); filclose(fil) ; } /*********** action routines (may be externally called) ***********/ /* external load (from file) */ static void querParseFile(void) { Array a ; int i, j, box ; Array s ; Array pgm ; char c ; FILE *fil ; QUERGET("querGetFile"); fil = filqueryopen (quer->dirName, quer->fileName, "qry", "r", "Choose a Query File") ; if (!fil || !graphExists (quer->graph)) return ; box = quer->curr; pgm = quer->pgm ; if(!pgm) pgm = quer->pgm = arrayCreate(5,Stack) ; if (arrayMax(pgm) > 0) /* gha 2-24 append, not overwrite */ i = arrayMax(pgm) - 1; else i = 0; s = 0 ; j = 0 ; while (c = fgetc(fil), c != (char)EOF) { if (c == '\n' || !s) { if (s && j) array(s,j,char) = 0 ; s = array(pgm,i,Array) ; if (s) arrayMax(s) = 0 ; else s = array(pgm,i,Array) = arrayCreate(QBUFF_MULT*BUFFER_SIZE, char) ; j = 0 ; i++ ; } if(isspace((int)c)) { if(j) array(s,j++,char) = ' ' ; } else if (c!='\n' && isprint((int)c)) array(s,j++,char) = c ; } if (s) { if (j) array(s,j,char) = 0 ; else { arrayDestroy(s) ; array(pgm,--i,Array) = 0 ; arrayMax(pgm) = i ; } } filclose(fil) ; /* One empty entry for a new instruction */ array (pgm,i,Array) = a = arrayCreate(QBUFF_MULT*BUFFER_SIZE, char) ; array(a,0,char) = 0 ; quer->last_find = -1 ; querDisplay () ; querPick(box, 0, 0, 0); } /* external save (to file) */ static void querSaveFile(void) { int i ; Array s ; Array pgm ; FILE *fil ; QUERGET("querSaveFile"); pgm = quer->pgm ; if(!pgm || arrayMax(pgm) <= 1) { messout("No program to save") ; return ; } fil = filqueryopen (quer->dirName, quer->fileName, "qry", "w","Choose a Query File") ; if (!fil || !graphExists (quer->graph)) return ; pgm = quer->pgm ; for(i=0; i < arrayMax(pgm) - 1; i++) { s = array(pgm,i,Array) ; if (s) fprintf (fil,"%s\n", arrp(s,0,char)) ; } filclose(fil) ; } /**********************************************************/ /* Called by QUIT */ static void querDestroy (void) { Array pgm ; int i ; char * cp ; QUER quer ; if ( graphAssFind (&MAGIC, &quer) && (quer->magic == MAGIC)) { cp = quer->fileName ; if( quer->pgm && quer->modif && *quer->fileName && strlen(quer->fileName) && messQuery (messprintf("%s not saved, Save ?", cp)) ) querSaveFile() ; quer->magic = 0 ; if ((pgm = quer->pgm)) { i = arrayMax(pgm) ; while(i--) arrayDestroy(arr(pgm,i,Array)) ; arrayDestroy(pgm) ; } if (!graphExists(qbuildGraph) && !graphExists(qbeGraph)) arrayDestroy(query_undo_set); messfree (quer) ; stackDestroy(dirStack) ; arrayDestroy(dirMarks) ; if(graphActivate(querGraph)) graphDestroy () ; querGraph = 0 ; } } /* modified gha 9/4/92 * Mouse pick function for query graph window...based upon * format of boxes as called in queryCreate()...caveat programmer. */ static void querPick (int k, double x_unused, double y_unused, int modifier_unused) { int i ; QUERGET("querPick"); if (k <= 0) return ; if (k > quer->pgmBox ) { /* for query entries */ i = (k - quer->pgmBox - 1)/2; if (i < arrayMax(quer->pgm)) { quer->curr = k ; graphTextScrollEntry (ARR2STRING(quer->pgm, i), 0, 0, 0, 0, 0) ; } } else return; graphActivate(quer->graph) ; } /******************* add 03.05.1992 kocab DKFZ **********/ /****************************************************************/ #ifdef FRED #include "igdevent.h" extern BOOL fredExists ; static void querySend (void) { fredscEvent event; int i; FredId j; Array s ; Array pgm ; static Stack buf = 0 ; QUERGET("querySend"); if (!fredExists) { messout ("aceServer is not initialised, sorry") ; return ; } pgm = quer->pgm ; if(!pgm || arrayMax(pgm) <= 1) { messout("No program to send") ; return ; } buf = stackReCreate(buf, 200) ; for(i=0; i < arrayMax(pgm) - 1; i++) { s = array(pgm,i,Array) ; if (arrayExists(s)) { catText(buf, arrp(s,0,char)) ; catText(buf,";") ; } /* catText(buf, arrp(s,0,char)) ; gha debug from jtm 5/25 */ } catText(buf, "\000") ; event.typeE = ACE_QUERY; event.typeD = DATA_IN_MEM_BUF; event.replyTo = 0; event.buffer.buff.bptr = stackText(buf,0) ; event.buffer.buff.blen = strlen(stackText(buf,0)) ; j = fredSendEvent(&event) ; printf("fredsendevent = %i \n",(int)j ); fredKillEvent(&event); if (wait_to_events ( &event, DATA_OK | DATA_NOT_OK ) < 0 ) messout(" error in communication with face"); else if (event.typeE == DATA_NOT_OK ) messout("data not received by face"); fredKillEvent(&event); } #else static void querySend (void) { messout("To send query, please recompile with -D FRED") ; } #endif /******************* add 03.05.1992 kocab DKFZ **********/ /****************************************************************/ /*************** alternative aceclient/server external query **************/ /****************************************************************/ /*************** beginning of menu stuff *******************/ static void clearQueryCommands(void); static void qbeCallup(void) { qbeCreate(); querDisplay(); /* gha added to unhighlight by example button */ } static void qbuildCallup(void) { qbuildCreate(); querDisplay(); /* gha added to unhighlight builder button */ } static void querButtonUndo(void) { queryCommandUndo(); querDisplay(); /* gha added to unhighlight undo button */ } static void qNewKeySet (void) { KEYSET ks = keySetCreate(); keySetNewDisplay (ks, "Query Answer") ; } static MENUOPT querButtons[] = { { querDestroy, "Quit" }, { help, "Help" }, { graphPrint, "Print" }, { clearQueryCommands, "Clear" }, { qNewKeySet, "New KeySet" }, { qbeCallup, "By Example" }, { qbuildCallup, "Builder" }, { querParseFile, "Load" }, { querSaveFile, "Save" }, { queryCommandEdit, "Search" }, { querButtonUndo, "Undo" }, { 0, 0 } } ; static void querAutoSv(void); /* Look at following functions to make sure not to disturb [#] indexing */ /* querAutoSv and MENU_AUTO */ #define MENU_AUTO 13 static MENUOPT querMenu[] = { { querDestroy, "Quit" }, { help, "Help" }, { graphPrint, "Print Window" }, { menuSpacer, "" }, { querDisplay, "Refresh" }, { clearQueryCommands, "Clear Entries" }, { qNewKeySet, "New KeySet" }, { qbeCreate, "Query By Example" }, { qbuildCreate, "Query Builder" }, { menuSpacer, "" }, { querParseFile, "Load From File" }, { querSaveFile, "Save To File" }, { querySend, "Send" }, { querAutoSv, "Enable Autosave" }, /* MUST BE #13, see querAutoSv(), MENU_AUTO */ { menuSpacer, "" }, #ifdef IGD { queryCommandEdit, "Search Locally" }, { querySend, "Search IGD" }, { querySend2, "Search Server" }, #else { queryCommandEdit, "Search" }, #endif { queryCommandUndo, "Undo Search" }, { 0, 0 } } ; static void querAutoSv(void) { QUERGET("querAutoSv"); if (TESTFLAG(NO_AUTOSV)) { RMFLAG(NO_AUTOSV); querMenu[MENU_AUTO].text = "Disable AutoSave"; } else { SETFLAG(NO_AUTOSV); querMenu[MENU_AUTO].text = "Enable AutoSave "; } graphMenu(querMenu) ; } /*************** end of menu stuff *******************/ static void clearQueryCommands(void) { QUERGET("clearQueryCommands"); if (quer->pgm) { strcpy(ARR2STRING(quer->pgm, 0), ""); arrayMax(quer->pgm) = 1; } querDisplay(); } /* open/show query-interface window */ #define QC_OFFSET 7 /* should be at least 3 */ static void querDisplay(void) { int i = 0; QUERGET("querDisplay"); graphRegister (PICK,(GraphFunc)querPick) ; graphActivate(quer->graph) ; graphClear() ; graphButtons (querButtons, 1, 1, 75) ; /* put buttons on screen */ graphTextFormat(BOLD); quer->pgmBox = graphBoxStart() ; if(quer->pgm) { graphTextFormat(BOLD); graphText("Direct Query Commands:", 1.5 , QC_OFFSET - 2.2); graphTextFormat(PLAIN); graphText("Click line to select", 24.5, QC_OFFSET - 2.5); graphText("(Press Return key to execute, F4 to interrupt.)", 24.5, QC_OFFSET - 1.5); for(i=0; ipgm); i++) { if (i == quer->last_find) graphText(">", 1, i*1.5 + QC_OFFSET); graphText("Query:", 2, i*1.5 + QC_OFFSET); quer->curr = graphTextScrollEntry(ARR2STRING(quer->pgm, i), QBUFF_MULT*BUFFER_SIZE - 1, 73, 9, i*1.5 + QC_OFFSET, TEXT_ENTRY_FUNC_CAST queryCommandEdit) ; } } graphBoxEnd() ; graphTextBounds (80, (int)(QC_OFFSET + 1.5*i + 2)) ; /* see queryCreate */ graphRedraw() ; } /*********************************************************************/ /******************** public routines *****************************/ /* show formed-query in window's query command line */ void queryWindowShowQuery(char *buffer) { int box; QUERGET("queryWindowShowQuery"); box = quer->curr; if (strlen(buffer) >= QBUFF_MULT*BUFFER_SIZE) messout("Warning, the query command may have exceeded the buffer capacity: %d.\n", QBUFF_MULT*BUFFER_SIZE-1); strncpy(ARR2STRING(quer->pgm, (quer->curr - quer->pgmBox -1)/2), buffer, QBUFF_MULT*BUFFER_SIZE-1); quer->curr = graphTextScrollEntry(ARR2STRING(quer->pgm, (quer->curr-quer->pgmBox- 1)/2), 0, 0, 0, 0, 0); querPick(box, 0, 0, 0); } /* Calls query() on query syntax and re-displays * window with new blank entry line, setting current pointer to that line. */ void queryCommandEdit (void) { Array a ; int i ; KEYSET oldSet, newSet ; KeySetDisp look ; char *querText, *cp; QUERGET("queryCommandEdit"); quer->modif = TRUE ; i = (quer->curr - quer->pgmBox - 1) / 2 ; quer->last_find = i; if(i == arrayMax(quer->pgm) - 1 && arrayExists(array(quer->pgm,i,Array))) { cp = arrp(arr(quer->pgm,i,Array), 0, char) ; if (cp) while(*cp && *cp == ' ') cp++ ; if(cp && *cp) /* but only if line is not empty */ { /* One empty entry for a new instruction */ array(quer->pgm,i+1,Array) = a = arrayCreate(QBUFF_MULT*BUFFER_SIZE, char); array(a,0,char) = 0 ; querDisplay() ; } } /* Execute */ if (arrayExists(array(quer->pgm,i,Array))) { querText = arrp(arr(quer->pgm,i,Array), 0, char) ; cp = querText ; if (cp) while(*cp && *cp == ' ') cp++ ; if(!*cp) return ; /* do nothing on empty lines */ if(!keySetActive(&oldSet, &look)) qNewKeySet() ; if(keySetActive(&oldSet, &look)) { messStatus ("Searching") ; newSet = query(oldSet, querText) ; if (newSet != oldSet ) { if(keySetExists(query_undo_set) && query_undo_set != oldSet ) keySetDestroy(query_undo_set) ; query_undo_set = oldSet ; } keySetShow(newSet,look) ; if (newSet && keySetMax(newSet)) /* update class, taglist */ { qbuildNewClass(class(keySet(newSet, 0))); autoSave(); } querDisplay(); querPick(quer->pgmBox+ 2*(i+1) + 1, 0, 0, 0); /* go to next line */ } else messout("First select a keySet, thank you") ; } } /* Called by UNDO */ void queryCommandUndo (void) { KEYSET oldSet, newSet ; KeySetDisp look ; if (keySetExists(query_undo_set) && keySetActive(&oldSet,&look)) { keySetDestroy (oldSet) ; /* destroys the look->kSet of the active KeySet-window */ newSet = keySetCopy(query_undo_set); if (newSet) /* keySet should check for NULL; reset Taglist */ qbuildNewClass(class(keySet(newSet, 0))); keySetShow (newSet, look) ; /* will eventually re-assign look->kSet of the active window to newSet see ksetdisp.c:keySetShow2() */ } } /*************************************************************/ /* Initializes and creates all data structure necessary for * query-window interface. Also, calls querDisplay() to pop up * image. */ void queryCreate (void) { Array a ; QUER quer ; char *cp ; if(graphActivate(querGraph)) { graphPop() ; return ; } querGraph = displayCreate("DtQuery") ; quer=(QUER)messalloc(sizeof(struct QCTRLSTUFF)); quer->magic = MAGIC; quer->graph = querGraph ; /* provision for multi windows */ quer->last_find = -1 ; graphTextBounds (80,40) ; /* needed yfor text box sizing */ graphRegister (DESTROY, querDestroy) ; graphRegister (PICK, querPick) ; graphRetitle ("Query Commands"); /* acedb 1.9.1 prepends "DtQuery :" */ if (getenv("ACEDB_AUTOSAVE")) { RMFLAG(NO_AUTOSV); querMenu[MENU_AUTO].text = "Disable AutoSave"; } else { SETFLAG(NO_AUTOSV); querMenu[MENU_AUTO].text = "Enable AutoSave "; } graphMenu (querMenu) ; graphAssociate (&MAGIC, quer); graphHelp ("Query") ; if ((cp = dbPathStrictFilName ("wquery", 0, 0, "rd", 0))) { strcpy (quer->dirName, cp) ; messfree(cp); } strcpy (quer->fileName, "") ; quer->pgm = arrayCreate(5,Array) ; array(quer->pgm,0,Array) = a = arrayCreate(QBUFF_MULT*BUFFER_SIZE,char) ; array(a,0,char) = 0 ; querDisplay(); return; } /* queryCreate */ /************************* eof ******************************/