/* File: tablemakerdisp.c * Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1992 * ------------------------------------------------------------------- * 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: Table_Maker - graphical editor to create and edit * table-definitions * Exported functions: * * tableDisplay - DisplayFunc for table-definition objects * * tableMaker - top-level menu-func to start Table_Maker * with blank definition * HISTORY: * Last edited: May 6 14:17 2003 (edgrif) * * May 27 09:54 1999 (fw): complete re-write to achieve independence * from spread-struct. * Created: Thu Jun 11 22:04:35 1992 (mieg) * CVS info: $Id: tablemakerdisp.c,v 1.18 2003/05/06 13:19:48 edgrif Exp $ *------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include /* needs spread-Package internals */ #include #include #include #include #include /************************************************************/ static magic_t TableMaker_MAGIC = "TableMaker"; typedef struct TableMakerStruct { magic_t *magic; /* == &TableMaker_MAGIC */ SPREAD spread; /* the table definitions */ Graph graph, dataGraph; int paramBox; int titleBox; int sortColonneBox; int isPrecomputeBox; Array columnInfo; /* of type ColumnInfo */ int definitionBox ; /* contains the colonne definitions */ int defBoxPerCol; /* how many boxes drawn per colonne */ int activeColonne; char dirSelection[DIR_BUFFER_SIZE]; char fileSelection[FIL_BUFFER_SIZE]; } *TableMaker; /*************/ typedef struct ColumnInfoStruct { int number; int boundingBox; int colNumBox; int hideBox; int optionalBox; int typeBox; int headerEntryBox; int widthBox; int extendBox; int fromBox; int tagBox; int tagTextBox; int conditionBox; } ColumnInfo; /************************************************************/ static Graph tableMakerDisplayCreate (SPREAD spread); static void tableMakerDisplayReCreate (SPREAD spread); static void tableMakerDisplayDestroy (void); static void tableMakerAddColonne (void); static void tableMakerRemoveColonne (void); static void tableMakerSearchActiveKeySet (void) ; static void tableMakerSearchWholeClass(void); static void tableMakerDisplayDraw (BOOL doCheckEntries); static void tableMakerPickObj (void); static void tableMakerSaveObj (void); static void tableMakerImportDefs (void); static void tableMakerExportDefs (void); static void spreadChooseTag(TableMaker tmdisp, int box, COL *c, COL *fromC, BOOL continuation); static MENUOPT spreadDefMenu[] = { { graphDestroy, "Quit"}, { help, "Help"}, { graphPrint, "Print"}, { menuSpacer, ""}, { tableMakerPickObj, "Pick Obj"}, /* from existing object */ { tableMakerSaveObj, "Save Obj"}, /* store in object */ { menuSpacer, ""}, { tableMakerImportDefs, "Import Def"}, /* from *.def file */ { tableMakerExportDefs, "Export Def"}, /* to *.def file */ { menuSpacer, ""}, { tableMakerSearchWholeClass, "Search Whole Class"}, { tableMakerSearchActiveKeySet,"Search Active KeySet"}, { menuSpacer, ""}, { tableMakerAddColonne, "Add Definition" }, { tableMakerRemoveColonne, "Remove Definition" }, { 0, 0 } } ; /************************************************************/ /* draws an encasing rectangle around the box we've just drawn */ #define graphBoxBox(_box) { \ float _x1, _y1, _x2, _y2 ; \ graphBoxDim (_box, &_x1, &_y1, &_x2, &_y2) ; \ graphRectangle (_x1 - 0.4, _y1 - 0.1, _x2 + 0.4, _y2 + 0.1) ; \ } static FREEOPT *classMenuOptions; /* pointer to a dynamic array of * FREEOPT's of possible class names */ /************************************************************/ /* DisplayFunc for TableMaker definition objects in class _VTable */ BOOL tableDisplay (KEY key, KEY from, BOOL isOldGraph, void *unused) { SPREAD spread; if (class(key) != _VTable) return FALSE ; /* read defs literally without parameter substitution */ spread = spreadCreateFromObj (key, NULL); if (!spread) return FALSE; /***** get the window *****/ if (isOldGraph) tableMakerDisplayReCreate(spread); /* replace table defs * on active graph */ else tableMakerDisplayCreate(spread); /* open new graph */ return TRUE; } /* tableDisplay */ /***********************************************************************/ void tableMaker (void) /* top-level menu func to start * table maker with empty definition */ { SPREAD spread; Stack s = stackCreate (100); pushText (s, "Sortcolumn 1\n" "Colonne 1"); spread = spreadCreateFromStack (s, "") ; stackDestroy (s); tableMakerDisplayCreate(spread); return; } /* tableMaker */ /***********************************************************************/ /*********************** private functions *****************************/ /***********************************************************************/ static TableMaker currentTableMaker (char *caller) { /* find and verify TableMaker struct on active graph */ TableMaker tmdisp = 0 ; if (!(graphAssFind(&TableMaker_MAGIC, &tmdisp))) messcrash("%s() could not find TableMakerStruct on graph", caller); if (!tmdisp) messcrash("%s() received NULL TableMakerStruct pointer", caller); if (tmdisp->magic != &TableMaker_MAGIC) messcrash("%s() received non-magic TableMakerStruct pointer", caller); if (arrayMax(tmdisp->spread->colonnes) == 0) messcrash("%s() received a TableMaker->spread with no colonnes", caller); return tmdisp; } /* currentTableMaker */ static Graph tableMakerDisplayCreate (SPREAD spread) /* create a new Table_Maker window with an existing spread-sheet */ /* the spread struct now belongs to this function */ { TableMaker tmdisp; char *cp; if (arrayMax(spread->colonnes) == 0) messcrash("tableMakerDisplayCreate() - " "cannot accept empty spread->colonnes"); tmdisp = (TableMaker)messalloc(sizeof(struct TableMakerStruct)); tmdisp->magic = &TableMaker_MAGIC; tmdisp->graph = displayCreate ("DtSpreadSheet"); tmdisp->spread = spread; tmdisp->activeColonne = arrayMax(spread->colonnes)-1; cp = dbPathStrictFilName("wquery", "", "", "rd", 0); if (cp) { strcpy (tmdisp->dirSelection, cp); messfree(cp); } else /* set to root db-dir */ { cp = dbPathMakeFilName("", "", "", 0); strcpy (tmdisp->dirSelection, cp); messfree(cp); } if (graphHelp(0) == NULL) graphHelp("Table_Maker"); graphRegister (DESTROY, tableMakerDisplayDestroy) ; graphAssociate (&TableMaker_MAGIC, tmdisp) ; tableMakerDisplayDraw(FALSE); /* draw table_maker screen layout */ return tmdisp->graph; } /* tableMakerDisplayCreate */ /*****************************************/ static void tableMakerDisplayReCreate (SPREAD spread) /* re-use the active graph, and replace the table definitions * with the new ones, the user may be asked to save * the old ones, if they were loaded from a file */ { TableMaker tmdisp = currentTableMaker("tableMakerDisplayReCreate"); if (spread != tmdisp->spread) { spreadDestroy (tmdisp->spread); tmdisp->spread = spread; tmdisp->activeColonne = arrayMax(spread->colonnes) - 1; } tableMakerDisplayDraw(FALSE); /* draw table_maker screen layout */ return; } /* tableMakerDisplayReCreate */ /*****************************************/ static void tableMakerDisplayDestroy (void) /* called when "DtSpreadSheet" graph dies * it also removes its child windows */ { TableMaker tmdisp = currentTableMaker("tableMakerDisplayDestroy"); if (tmdisp->spread->isModified) { if (tmdisp->spread->filename && strlen(tmdisp->spread->filename) && messQuery ("%s has been modified, Save ?", filGetFilename(tmdisp->spread->filename))) { ACEOUT dump_out; dump_out = aceOutCreateToChooser ("Choose a File to store " "the Table-definition", tmdisp->dirSelection, tmdisp->fileSelection, "def", "w", 0); if (dump_out) { spreadDumpDefinitions (tmdisp->spread, dump_out); aceOutDestroy (dump_out); } } else if (tmdisp->spread->tableDefKey) { if (messQuery ("%s has been modified, Save ?", name(tmdisp->spread->tableDefKey)) && checkWriteAccess()) { /* The definitions have changed and we update the object * that they origibated from and we have to make sure * that the precomputation is updated as well */ spreadSaveDefInObj (tmdisp->spread, tmdisp->spread->tableDefKey) ; tmdisp->spread->valuesModified = TRUE; /* will update store precomputation if possible */ } else { /* the definitions have changed, but we didn't * want to save them, so we can't store a * precomputations anymore */ tmdisp->spread->precompute = FALSE; } } } spreadDestroy(tmdisp->spread) ; if (graphExists(tmdisp->dataGraph)) { graphActivate(tmdisp->dataGraph) ; graphDestroy() ; } tmdisp->magic = 0; messfree(tmdisp); return; } /* tableMakerDisplayDestroy */ /*****************************************************/ /* Colonne Definition Interface */ /*****************************************************/ static COL *activateColonne (TableMaker tmdisp, int colNum) { ColumnInfo *old, *cinfo; COL *col; old = arrayp(tmdisp->columnInfo, tmdisp->activeColonne, ColumnInfo); graphBoxDraw(old->colNumBox, BLACK, WHITE); tmdisp->activeColonne = colNum; cinfo = arrayp(tmdisp->columnInfo, tmdisp->activeColonne, ColumnInfo); graphBoxDraw(cinfo->colNumBox, BLACK, LIGHTGRAY); col = arrayp(tmdisp->spread->colonnes, tmdisp->activeColonne, COL); return col; } /* activateColonne */ static COL *activateColonneByBoxNum(TableMaker tmdisp, int box) { COL *col; int colNum; if (box > tmdisp->definitionBox) { colNum = tmdisp->defBoxPerCol ? (box - tmdisp->definitionBox) / tmdisp->defBoxPerCol : 0 ; } col = activateColonne(tmdisp, colNum); return col ; } /* activateColonneByBoxNum */ /******** Optional ********/ static void menuCallSpreadColOptional (KEY newValue, int box) { COL *col ; TableMaker tmdisp = currentTableMaker("menuCallSpreadColOptional"); col = activateColonneByBoxNum(tmdisp, box); spreadColSetPresence (tmdisp->spread, col->colonne, newValue); graphBoxDraw(box, BLACK, WHITE) ; return; } /* menuCallSpreadColOptional */ /******** Extend ********/ static void menuCallSpreadColExtend (KEY newValue, int box) { COL *col; TableMaker tmdisp = currentTableMaker("menuCallSpreadColExtend"); col = activateColonneByBoxNum(tmdisp, box) ; spreadColSetExtend (tmdisp->spread, col->colonne, newValue); graphBoxDraw(box, BLACK, WHITE) ; return; } /* menuCallSpreadColExtend */ /******** Hide ********/ static void menuCallSpreadColHide (KEY newValue, int box) { COL *col; TableMaker tmdisp = currentTableMaker("menuCallSpreadColHide"); col = activateColonneByBoxNum(tmdisp, box) ; spreadColSetHidden(tmdisp->spread, col->colonne, newValue); graphBoxDraw(box, BLACK, WHITE) ; return; } /* menuCallSpreadColHide */ /******** Type ********/ static FREEOPT typeChoice[] = { {9, "Class ..."}, {'k', "Class"}, {'i', "Integer"}, {'f', "Float"}, {'d', "Date"}, {'t', "Text"}, {'b', "Show_Tag"}, {'n', "Next_Tag"}, {'K', "Next_Key"}, {'5', "Count"} } ; static FREEOPT typeChoice2[] ={ {10, "Class ..."}, {'x', "Show Data"}, {'b', "Show Tag"}, {'n', "Show Next Tag"}, {'K', "Show Next Key"}, {SHOW_MIN, "Compute Min"}, {SHOW_MAX, "Compute Max"}, {SHOW_AVG, "Compute Average"}, {SHOW_VAR, "Compute Variance"}, {SHOW_SUM, "Compute Sum"}, {'c', "Count"} } ; static void menuCallSpreadColType (KEY newValue, int box) { COL *col; KEY oldValue; TableMaker tmdisp = currentTableMaker("menuCallSpreadColType") ; col = activateColonneByBoxNum(tmdisp, box); oldValue = col->type ; switch (newValue) { case 'b': /* "Show Tag" */ col->nonLocal = FALSE ; break ; case 'x': /* "Show Data" */ /* use real datatype of value */ col->nonLocal = FALSE ; col->showType = SHOW_ALL ; col->type = col->realType ; col->showtypep = freekey2text(newValue, typeChoice2) ; goto ok ; break ; case 'n': /* "Show Next Tag" */ col->classe = _VSystem ; col->nonLocal = FALSE ; break ; case 'K': /* "Show Next Key" */ { KEY classeKey ; if (graphSelect (&classeKey, classMenuOptions)) col->classe = classeKey ; else col->classe = 0 ; } col->nonLocal = FALSE ; break ; case SHOW_MIN: case SHOW_MAX: case SHOW_AVG: case SHOW_VAR: case SHOW_SUM: switch (col->realType) { case 'i': case 'f': case 'd': col->showType = newValue ; col->type = col->realType ; col->nonLocal = TRUE ; col->showtypep = freekey2text(newValue, typeChoice2) ; tmdisp->spread->isModified = TRUE ; goto ok ; break ; default: return ; } case 'c': col->nonLocal = TRUE ; break ; } col->showType = SHOW_ALL ; col->type = newValue ; col->typep = freekey2text(col->type, typeChoice2) ; if (oldValue != newValue) tmdisp->spread->isModified = TRUE ; ok: graphBoxDraw(box, BLACK, LIGHTBLUE) ; tableMakerDisplayDraw(FALSE); return; } /* menuCallSpreadColType */ /********* Pick boxes ************/ static void tableMakerPick(int box, double x, double y, int modifier_unused) { TableMaker tmdisp = currentTableMaker("tableMakerPick") ; int colNum; COL *col ; ColumnInfo *cinfo; if (!graphCheckEditors (graphActive(), 0)) return ; if (box == 0) /* background */ return ; if (box == tmdisp->titleBox) { graphTextEntry (tmdisp->spread->titleBuffer,0,0,0,0) ; tmdisp->spread->isModified = TRUE; /* assuming, that user will edit */ return ; } else if (box == tmdisp->paramBox) { graphTextEntry(tmdisp->spread->paramBuffer,0,0,0,0) ; return ; } else if (box == tmdisp->sortColonneBox) return ; tmdisp->spread->isModified = TRUE; /* assume we'll change something */ for (colNum = 0; colNum < arrayMax(tmdisp->spread->colonnes); colNum++) { cinfo = arrayp(tmdisp->columnInfo, colNum, ColumnInfo); if (box == cinfo->boundingBox || box == cinfo->colNumBox || box == cinfo->widthBox) { activateColonne(tmdisp, colNum); break; } else if (box == cinfo->fromBox) { activateColonne(tmdisp, colNum); if (tmdisp->activeColonne == 0) messcrash("shouldn't see the from box in colonne 0"); break; } else if (box == cinfo->conditionBox) { col = activateColonne(tmdisp, colNum); graphTextScrollEntry(col->conditionBuffer,0,0,0,0,0) ; break; } else if (box == cinfo->headerEntryBox) { col = activateColonne(tmdisp, colNum); graphTextEntry(col->headerBuffer,0,0,0,0) ; break; } else if (box == cinfo->typeBox) { KEY typeValue; col = activateColonne (tmdisp, colNum); typeValue = col->type; if (tmdisp->activeColonne == 0) { /* select classe of master colonne */ if (graphSelect (&typeValue, classMenuOptions)) { col->type = col->realType = 'k' ; col->classe = typeValue ; col->nonLocal = FALSE ; col->typep = freekey2text (col->classe, classMenuOptions) ; } } else { if (graphSelect (&typeValue, typeChoice2)) menuCallSpreadColType (typeValue, box) ; } graphBoxDraw (box, BLACK, WHITE) ; tableMakerDisplayDraw (FALSE); break; } else if (box == cinfo->tagBox) { col = activateColonne (tmdisp, colNum); spreadChooseTag (tmdisp, box, col, arrp(tmdisp->spread->colonnes, col->from-1 , COL), col->extend) ; break; } else if (box == cinfo->tagTextBox) { col = activateColonne (tmdisp, colNum); graphTextScrollEntry (col->tagTextBuffer,0,0,0,0,0) ; break; } else if (box == cinfo->hideBox) { activateColonne (tmdisp, colNum); spreadColCycleHidden (tmdisp->spread, colNum); graphBoxDraw (box, BLACK, WHITE) ; break; } else if (box == cinfo->optionalBox) { activateColonne (tmdisp, colNum); spreadColCyclePresence (tmdisp->spread, colNum); graphBoxDraw (box, BLACK, WHITE) ; break; } else if (box == cinfo->extendBox) { col = activateColonne (tmdisp, colNum); spreadColCycleExtend (tmdisp->spread, colNum); graphBoxDraw (box, BLACK, WHITE); if (col->extend == COLEXTEND_RIGHT_OF && col->from == 1) col->from = col->colonne; else if (col->extend == COLEXTEND_FROM && col->from != 1) col->from = 1 ; tableMakerDisplayDraw(FALSE) ; break; } } return; } /* tableMakerPick */ /*********Tag Chooser 1 *******************/ static void spreadChooseTag(TableMaker tmdisp, int box, COL *c, COL *fromC, BOOL continuation) { int classe ; COL *c1 = c ; Stack s1 = 0 ; KEY tag1 ; int type1 ; while (c1->extend == COLEXTEND_RIGHT_OF && fromC->from > 0 && fromC->from < arrayMax(tmdisp->spread->colonnes)) { c1 = fromC ; fromC = arrayp(tmdisp->spread->colonnes, fromC->from - 1, COL) ; } if (fromC->type == 'K' && !fromC->classe) { messout("First define the class of column %d",c->from) ; return ; } if (freelower(fromC->type) != 'k' || !fromC->classe) { messout("First define the colonne you construct from") ; return ; } if (pickList[superClass(fromC->classe)].type != 'B') { messout("You cannot select a tag in non B-class: %s", name(fromC->classe)) ; return ; } /* if user cancels, do not touch anything in c-> */ s1 = stackCreate (32) ; tag1 = c->tag ; type1 = c->type ; if (!treeChooseTagFromModel(&type1, &classe, fromC->classe, &tag1, s1, continuation)) return ; c->tag = tag1 ; c->type = type1 ; stackDestroy (c->tagStack) ; c->tagStack = s1 ; c->nonLocal = FALSE ; c->showType = SHOW_ALL ; c->realType = c->type ; lexword2key(pickClass2Word(classe), &c->classe, _VClass) ; c->tagp = stackText(c->tagStack, 0) ; tmdisp->spread->isModified = TRUE ; tableMakerDisplayDraw(FALSE) ; return; } /* spreadChooseTag */ static void menuCallSpreadColClass (KEY newValue, int box) { COL *col; int oldValue; TableMaker tmdisp = currentTableMaker("menuCallSpreadColClass") ; col = activateColonneByBoxNum(tmdisp, box) ; oldValue = col->classe ; col->classe = newValue ; col->classp = name(col->classe) ; col->type = col->realType = 'k' ; col->nonLocal = FALSE ; tableMakerDisplayDraw(FALSE) ; if (newValue != oldValue) tmdisp->spread->isModified = TRUE ; return; } /* menuCallSpreadColClass */ /************************************************/ static void entrySpreadTitle (char *entry) /* entryfunc for text-entry of colonne->titleBuffer */ { char *cp ; TableMaker tmdisp = currentTableMaker("entrySpreadTitle") ; cp = tmdisp->spread->titleBuffer ; while (*cp) cp ++ ; while (--cp >= tmdisp->spread->titleBuffer && *cp == ' ') *cp = 0 ; tmdisp->spread->isModified = TRUE ; tableMakerDisplayDraw(FALSE); /* may want to retitle */ return; } /* entrySpreadTitle */ /************************************************/ static void entrySpreadParam (char *entry) /* entryfunc for text-entry of colonne->paramBuffer */ { char *cp ; TableMaker tmdisp = currentTableMaker("entrySpreadParam") ; cp = tmdisp->spread->paramBuffer ; while (*cp) cp ++ ; while (--cp >= tmdisp->spread->paramBuffer && *cp == ' ') *cp = 0 ; tmdisp->spread->isModified = TRUE ; return; } /* entrySpreadParam */ /************************************************/ static void togglePrecompute (void) /* only possible on spread-defs that come from an object */ { TableMaker tmdisp = currentTableMaker("entrySpreadParam") ; if (tmdisp->spread->precompute) { tmdisp->spread->precompute = FALSE; graphBoxDraw (tmdisp->isPrecomputeBox, BLACK, WHITE); } else { tmdisp->spread->precompute = TRUE; graphBoxDraw (tmdisp->isPrecomputeBox, BLACK, LIGHTBLUE); } tmdisp->spread->isModified = TRUE; return; } /* togglePrecompute */ /************************************************/ static BOOL checkSpreadSortColumn (int n) /* check function for graphIntEditor on spread->sortColumn */ { TableMaker tmdisp = currentTableMaker("checkSpreadSortColumn") ; if (n < 0 || n > arrayMax(tmdisp->spread->colonnes)) { messout ("Error: Sort column - value must be between a valid " "column number or 0, which means left " "to right ordering.") ; return FALSE ; } return TRUE ; } /* checkSpreadSortColumn */ /************************************************/ static BOOL checkSpreadColFrom (int n) /* check function for graphIntEditor on colonne->from */ { TableMaker tmdisp = currentTableMaker("checkSpreadColFrom") ; if (tmdisp->activeColonne == 0) return TRUE ; /* make sure it's a valid colonne number */ if (n <= 0 || n >= arrayMax(tmdisp->spread->colonnes)) { messout("Colonne %d is built \"From\" invalid colonne %d", tmdisp->activeColonne, n) ; return FALSE ; } return TRUE ; } /* checkSpreadColFrom */ /************************************************/ static BOOL checkSpreadColWidth (int n) /* check function for graphIntEditor on colonne->width */ { return (n > 0) ; } /************************************************/ static void entrySpreadColHeader (char *entry) /* entryfunc for text-entry of colonne->headerBuffer */ { COL *col ; char *cp ; TableMaker tmdisp = currentTableMaker("entrySpreadColHeader") ; col = arrayp(tmdisp->spread->colonnes, tmdisp->activeColonne, COL) ; cp = col->headerBuffer ; while (*cp) cp ++ ; while (--cp >= col->headerBuffer && *cp == ' ') *cp = 0 ; tmdisp->spread->isModified = TRUE ; return; } /* entrySpreadColHeader */ /************************************************/ static void entrySpreadColTagText(char *entry) { COL *col ; char *cp ; TableMaker tmdisp = currentTableMaker("entrySpreadColTagText") ; col = arrayp(tmdisp->spread->colonnes, tmdisp->activeColonne, COL) ; cp = col->tagTextBuffer ; if (!*cp) strcpy(cp, "?") ; col->tagStack = stackReCreate(col->tagStack, 32) ; pushText(col->tagStack, cp) ; col->tagp = stackText(col->tagStack, 0) ; tmdisp->spread->isModified = TRUE ; tableMakerDisplayDraw(FALSE) ; return; } /* entrySpreadColTagText */ /************************************************/ static void entrySpreadColCondition (char *entry) /* entryfunc for text-entry of colonne->conditionBuffer */ { COL *col ; char *cp ; TableMaker tmdisp = currentTableMaker("entrySpreadColCondition") ; col = arrayp(tmdisp->spread->colonnes, tmdisp->activeColonne, COL) ; cp = col->conditionBuffer ; while (*cp) cp ++ ; while (--cp >= col->conditionBuffer && *cp == ' ') *cp = 0 ; if (*col->conditionBuffer && !condCheckSyntax(messprintf(" %s", col->conditionBuffer))) messout("Please correct this syntax error") ; tmdisp->spread->isModified = TRUE ; return; } /* entrySpreadColCondition */ /************************************************/ static void tableMakerAddColonne (void) { TableMaker tmdisp = currentTableMaker("tableMakerAddColonne") ; COL *col; col = spreadColInit(tmdisp->spread, arrayMax(tmdisp->spread->colonnes)); tmdisp->activeColonne = col->colonne; tableMakerDisplayDraw(FALSE) ; /* re-draw */ return; } /* tableMakerAddColonne */ /************************************************/ static void tableMakerRemoveColonne (void) { TableMaker tmdisp = currentTableMaker("tableMakerRemoveColonne") ; if (tmdisp->activeColonne == 0) { messout ("You cannot remove the first colonne") ; return; } if (!messQuery(messprintf("Do you really want to remove colonne %d", tmdisp->activeColonne + 1))) return ; tmdisp->activeColonne = spreadRemoveColonne(tmdisp->spread, tmdisp->activeColonne); tableMakerDisplayDraw(FALSE) ; return; } /* tableMakerRemoveColonne */ /***********************************************************/ /*********** Input Output of the definitions ***************/ /* The actual operation are in a separate non graphic file */ static void selectPickedDefinitionObj (KEY key) /* return from the display-block to "Pick a table object" */ { displayUnBlock () ; if (class(key) != _VTable) messout ("Sorry, you must pick a Table object") ; else if (!iskey(key)) messout ("Sorry, this object is empty.") ; else { /* display this tableObject and re-use existing graph */ tableDisplay(key, 0, TRUE, NULL); graphPop(); } return; } /* selectPickedDefinitionObj */ static void tableMakerPickObj (void) { KEYSET ks = query (0,"FIND Table") ; keySetNewDisplay (ks, "Table definitions") ; displayBlock (selectPickedDefinitionObj, "Pick a Table object") ; return; } /* tableMakerPickObj */ static void tableMakerSaveObj (void) { char *previous_name; char *nam = 0; TableMaker tmdisp = currentTableMaker("tableMakerSaveObj") ; ACEIN name_in; if (!graphCheckEditors (graphActive(), 0)) return ; if (tmdisp->spread->tableDefKey) previous_name = name(tmdisp->spread->tableDefKey); else previous_name = ""; name_in = messPrompt ("Please enter a Name to save this " "table-definition as an acedb object", previous_name, "w", 0); if (!name_in) goto abort; nam = strnew (aceInWord(name_in), 0) ; aceInDestroy (name_in); if (lexword2key (nam, &tmdisp->spread->tableDefKey, _VTable)) { if (!messQuery ("This table-definition already exists, " "do you want to overwrite it ?")) goto abort ; } if (checkWriteAccess()) { lexaddkey (nam, &tmdisp->spread->tableDefKey, _VTable) ; spreadSaveDefInObj (tmdisp->spread, tmdisp->spread->tableDefKey) ; tmdisp->spread->isModified = FALSE; } abort: messfree (nam) ; return; } /* tableMakerSaveObj */ static void tableMakerImportDefs (void) { TableMaker tmdisp = currentTableMaker("tableMakerDisplayDestroy"); SPREAD newSpread; ACEIN spread_in; spread_in = aceInCreateFromChooser ("Choose a Table-definition file", tmdisp->dirSelection, tmdisp->fileSelection, "def","r", 0); if (!spread_in) return ; newSpread = spreadCreateFromAceIn (spread_in, NULL); aceInDestroy (spread_in); if (!newSpread) return; tableMakerDisplayReCreate(newSpread); if (!graphCheckEditors (graphActive(), 0)) { /* the definitions have been drawn, and some values * in the editor boxes don't check out */ messout ("There are errors in some entry fields") ; } return; } /* tableMakerImportDefs */ static void tableMakerExportDefs (void) { TableMaker tmdisp = currentTableMaker("tableMakerExportDefs") ; ACEOUT dump_out; if (!graphCheckEditors (graphActive(), 0)) return ; dump_out = aceOutCreateToChooser ("Choose a File to store the Table-definition", tmdisp->dirSelection, tmdisp->fileSelection, "def", "w", 0); if (dump_out) { spreadDumpDefinitions (tmdisp->spread, dump_out); aceOutDestroy (dump_out); tmdisp->spread->isModified = FALSE; } return; } /* tableMakerExportDefs */ /**********************************************************/ static void tableMakerJumpToTop (void) { graphGoto (1,1) ; } /**********************************************************/ static void showResultTable (TABLE *table, char *title, Array flipped, Array widths) { TableMaker tmdisp = currentTableMaker("showResultTable") ; if (table) { if (graphActivate(tmdisp->dataGraph)) tableDisplayReCreate (table, title, flipped, widths); else tmdisp->dataGraph = tableDisplayCreate(table, title, flipped, widths); } if (graphActivate(tmdisp->dataGraph)) graphPop(); return; } /* showResultTable */ static void tableMakerSearchWholeClass(void) { TableMaker tmdisp = currentTableMaker("tableMakerSearchWholeClass") ; SPREAD calcSpread = 0; TABLE *table = 0; char *title_p; Array flipped, widths; if (!graphCheckEditors (graphActive(), 0)) return ; tableDestroy(tmdisp->spread->values); /* try to pre-load */ if (!tmdisp->spread->isModified && spreadGetPrecomputation(tmdisp->spread)) { printf ("loaded precomputation\n"); table = tmdisp->spread->values; title_p = &tmdisp->spread->titleBuffer[0]; flipped = spreadGetFlipInfo(tmdisp->spread); widths = spreadGetWidths(tmdisp->spread); } else { Stack s; ACEOUT def_out; s = stackCreate(1000); def_out = aceOutCreateToStack (s, 0); spreadDumpDefinitions (tmdisp->spread, def_out); aceOutDestroy (def_out); /* now read defs with parameter substitution (params != NULL) * but only using the params already given in the * Parameter field */ calcSpread = spreadCreateFromStack (s, ""); stackDestroy(s); /* For the title for the tableDisplay, we use the * title of the definitions where parameter * substitution was performed. */ title_p = &calcSpread->titleBuffer[0]; flipped = spreadGetFlipInfo(calcSpread); widths = spreadGetWidths(calcSpread); if (spreadCalculateOverWholeClass(calcSpread)) { table = calcSpread->values; tmdisp->spread->values = tableCopy(calcSpread->values, 0); tmdisp->spread->valuesModified = TRUE; } } if (table) showResultTable (table, title_p, flipped, widths); arrayDestroy (flipped); arrayDestroy (widths); if (calcSpread) spreadDestroy(calcSpread); return; } /* tableMakerSearchWholeClass */ /**********************************************************/ void tableMakerSearchActiveKeySet (void) /* derive the first master column from the active keyset * rather than the selected class */ { KEYSET ks = 0, ks2 = 0 ; KeySetDisp look ; COL *col ; TableMaker tmdisp = currentTableMaker("tableMakerSearchActiveKeySet") ; SPREAD calcSpread = 0; Array flipped; Array widths; Stack s; ACEOUT def_out; if (!graphCheckEditors (graphActive(), 0)) return ; if (!spreadCheckConditions(tmdisp->spread)) return ; col = arrp(tmdisp->spread->colonnes, 0, COL) ; if (!col->classe) { messout ("First choose the class of column 1 ") ; return ; } if (strlen(col->conditionBuffer) > 0 && ! condCheckSyntax(messprintf(" %s", col->conditionBuffer))) { messout ("First fix the syntax error in column 1's condition") ; return ; } if (!keySetActive(&ks, &look)) { messout("First select a KeySet, thank you") ; return ; } tableDestroy (tmdisp->spread->values); /*************************************************************** * run the calculation on definitions where we've performed parameter * substitution, so % strings aren't left in conditionBuffers etc. * So we dumpt the definitions into a stack and parse them back in * whilst performing parameter substitution. */ s = stackCreate(1000); def_out = aceOutCreateToStack (s, 0); /* dump the definitions */ spreadDumpDefinitions (tmdisp->spread, def_out); aceOutDestroy (def_out); /* and read them in with no extra parameters, other than the ones * given in the definition already */ calcSpread = spreadCreateFromStack (s, ""); stackDestroy(s); ks2 = spreadFilterKeySet (calcSpread, ks) ; calcSpread->isActiveKeySet = TRUE ; spreadCalculateOverKeySet (calcSpread, ks2, NULL); calcSpread->isActiveKeySet = FALSE ; flipped = spreadGetFlipInfo (calcSpread); widths = spreadGetWidths (calcSpread); if (calcSpread->values) { showResultTable (calcSpread->values, calcSpread->titleBuffer, flipped, widths); tmdisp->spread->values = tableCopy (calcSpread->values, 0); /* This tableResult is based on an active keyset and therefor * unsuitable to be saved as a precomputed result. * We set valuesModified to false, which will make sure * the tmdisp->spread->values aren't saved on destruction * of tmdisp->spread. */ tmdisp->spread->valuesModified = FALSE; } arrayDestroy(flipped); arrayDestroy(widths); keySetDestroy (ks2) ; spreadDestroy(calcSpread); return; } /* tableMakerSearchActiveKeySet */ /************************************************************/ extern FREEOPT presenceChoice[], hideChoice[], extendChoice[]; static void tableMakerDisplayDraw (BOOL doCheckEntries) /* draw table_maker screen layout */ { static Array classMenuArray = 0; char *windowTitle; COL *col , *fromCol ; ColumnInfo *cinfo; int i, max, from; int lastBoxInCol, menuBox; float line, centralLine = 1 ; TableMaker tmdisp = currentTableMaker("tableMakerDisplayDraw") ; if (doCheckEntries && !graphCheckEditors (graphActive(), 0)) return ; if (!arrayMax(tmdisp->spread->colonnes)) messcrash("tableMakerDisplayDraw - no colonnes"); /* set title, observing settings from displays.wrm if avail */ windowTitle = displayGetTitle("DtSpreadSheet"); if (strcmp(windowTitle, "DtSpreadSheet") == 0) windowTitle = "Table Maker"; /* if undef in displays.wrm */ if (strlen(tmdisp->spread->titleBuffer) > 0) graphRetitle(messprintf("%s : %s", windowTitle, tmdisp->spread->titleBuffer)); else graphRetitle(messprintf("%s : untitled", windowTitle)); /* re-do the menulist for the choice of possible classes */ classMenuArray = classListCreate(classMenuArray, /* hidden visible or buried * have to be B-classes with model */ TRUE, TRUE, TRUE, FALSE); classMenuOptions = arrp(classMenuArray, 0, FREEOPT); graphClear() ; graphMenu(spreadDefMenu) ; graphRegister (PICK, tableMakerPick) ; menuBox = graphBoxStart() ; graphButtons (spreadDefMenu, 1, 1, 75) ; graphBoxEnd() ; /* find out how far down the menu-buttons have been drawn */ graphBoxDim (menuBox, 0, 0, 0, &line) ; line += 1 ; /* separator line */ graphLine(0, line, 1000, line); line += 0.5; /***************************************************************/ /* draw table header fields */ /***************************************************************/ graphText ("Sort column:", 3, line) ; tmdisp->sortColonneBox = graphIntEditor ("", &tmdisp->spread->sortColonne, 16, line, checkSpreadSortColumn) ; graphText ("F4 to interrupt", 40, line) ; line += 1.5 ; graphText ("Title:", 3, line) ; tmdisp->titleBox = graphTextEntry (tmdisp->spread->titleBuffer, 59, 16, line, entrySpreadTitle) ; line += 1.5 ; graphText ("Parameters:", 3, line) ; tmdisp->paramBox = graphTextScrollEntry (tmdisp->spread->paramBuffer, 179, 59, 16, line, entrySpreadParam) ; line += 1.5 ; if (tmdisp->spread->tableDefKey) { tmdisp->isPrecomputeBox = graphButton ("Precompute", togglePrecompute, 3, line); if (tmdisp->spread->precompute) graphBoxDraw (tmdisp->isPrecomputeBox, BLACK, LIGHTBLUE); graphText ("... to store the results in the database.", 16, line); line += 1.5 ; } /* separator line */ graphLine(0, line, 1000, line); line += 0.5; /***************************************************************/ /* draw table colonne definitions */ /***************************************************************/ tmdisp->definitionBox = graphBoxStart() ; graphText ("Column", 1, line) ; line += 1.5 ; tmdisp->defBoxPerCol = 0; max = arrayMax(tmdisp->spread->colonnes) ; tmdisp->columnInfo = arrayReCreate(tmdisp->columnInfo, max, ColumnInfo); for (i = 0; i < max ; i++) { col = arrayp(tmdisp->spread->colonnes, i, COL); cinfo = arrayp(tmdisp->columnInfo, i, ColumnInfo); cinfo->boundingBox = graphBoxStart(); cinfo->colNumBox = graphBoxStart(); graphText(messprintf("%3d", i + 1), 2, line+2.5) ; graphRectangle(2 -0.4, line -0.1, 2+3 +0.6, line+6 +0.1); graphBoxEnd(); if (i == tmdisp->activeColonne) { graphBoxDraw(cinfo->colNumBox, BLACK, LIGHTGRAY); centralLine = line ; } graphText ("Header", 7, line) ; cinfo->headerEntryBox = graphTextEntry (col->headerBuffer, 58, 17, line, entrySpreadColHeader) ; graphText ("Width", 7, line += 1.3) ; cinfo->widthBox = graphIntEditor ("", &col->width, 14, line, checkSpreadColWidth) ; cinfo->hideBox = graphBoxStart() ; graphTextPtrPtr(&col->hiddenp, 24, line, 7) ; graphBoxEnd() ; graphBoxBox(cinfo->hideBox) ; graphBoxFreeMenu(cinfo->hideBox, menuCallSpreadColHide, hideChoice); cinfo->optionalBox = graphBoxStart() ; graphTextPtrPtr(&col->optionalp, 33, line, 9) ; graphBoxEnd() ; if (i > 0) { graphBoxBox(cinfo->optionalBox) ; graphBoxFreeMenu(cinfo->optionalBox, menuCallSpreadColOptional, presenceChoice) ; } else graphBoxClear(cinfo->optionalBox) ; cinfo->typeBox = graphBoxStart() ; switch (col->showType) { case SHOW_ALL: if (col->type != 'c') { graphTextPtrPtr(&col->typep, 45, line, 7) ; graphTextPtrPtr(&col->classp, 53, line, 22) ; } else { col->showtypep = "COUNT" ; col->realType = col->type ; /*mhmp 22.02.99 */ graphTextPtrPtr(&col->showtypep, 45, line, 12) ; } break ; case SHOW_MIN: case SHOW_MAX: case SHOW_AVG: case SHOW_VAR: case SHOW_SUM: col->showtypep = freekey2text (col->showType, typeChoice2) ; graphTextPtrPtr(&col->showtypep, 41, line, 12) ; break ; } col->typep = freekey2text(col->type, typeChoice) ; col->classp = col->classe && freelower(col->type) == 'k' ? name(col->classe) : 0 ; graphBoxEnd() ; graphBoxBox(cinfo->typeBox) ; if (i > 0) graphBoxFreeMenu(cinfo->typeBox, menuCallSpreadColType, typeChoice2) ; else graphBoxFreeMenu(cinfo->typeBox, menuCallSpreadColClass, classMenuOptions) ; line += 1.5; cinfo->extendBox = graphBoxStart() ; graphTextPtrPtr(&col->extendp, 8, line, 8) ; graphBoxEnd() ; if (i > 0) { graphBoxBox(cinfo->extendBox); graphBoxFreeMenu(cinfo->extendBox, menuCallSpreadColExtend, extendChoice) ; } else graphBoxClear(cinfo->extendBox) ; from = col->from; if (i > 0) cinfo->fromBox = graphIntEditor ("", &col->from, 17, line, checkSpreadColFrom) ; else { /* editor not really needed in master colonne, but we still * draw the box without check-func to get the same number of boxes * in each definition block */ cinfo->fromBox = graphIntEditor ("", &col->from, 17, line, 0) ; graphBoxClear(cinfo->fromBox); /* clear the main editor box, * NOTE: cursor box still around */ } cinfo->tagBox = graphBoxStart() ; graphText ("Tag:" , 29, line) ; graphBoxEnd() ; if (i > 0) graphBoxBox(cinfo->tagBox) ; if (from > 0) fromCol = arrp(tmdisp->spread->colonnes, from - 1, COL) ; else fromCol = 0 ; if (col->extend == COLEXTEND_FROM) if (i == 0 || !fromCol || freelower(fromCol->type) != 'k' || !fromCol->classe) graphBoxClear(cinfo->tagBox) ; if (!stackExists(col->tagStack)) strcpy(col->tagTextBuffer, "?") ; else strncpy(col->tagTextBuffer, stackText(col->tagStack,0), 359) ; cinfo->tagTextBox = graphTextScrollEntry(col->tagTextBuffer, 359, 41, 34, line, entrySpreadColTagText) ; if (i == 0) { graphBoxClear(cinfo->tagTextBox) ; graphText ("To restrict the search, use the condition box " "or search a keyset", 9 , line) ; } graphText ("Condition", 7, line += 1.3) ; cinfo->conditionBox = graphTextScrollEntry (col->conditionBuffer, 359, 58, 17, line, entrySpreadColCondition) ; graphBoxEnd(); /* boundingBox */ /* last paragraph of the loop */ lastBoxInCol = graphBoxStart() ; graphBoxEnd() ; if (tmdisp->defBoxPerCol == 0) tmdisp->defBoxPerCol = lastBoxInCol - tmdisp->definitionBox ; line += 2.5; } graphBoxEnd() ; graphButton("Add Definition", tableMakerAddColonne, 2, line) ; graphButton("Page top", tableMakerJumpToTop, 25, line) ; graphTextBounds (78, line + 5) ; graphRedraw() ; graphGoto (1, centralLine) ; return ; } /* tableMakerDisplayDraw */ /*********************** eof ********************************/