1/* 2 * tkTableEdit.c -- 3 * 4 * This module implements editing functions of a table widget. 5 * 6 * Copyright (c) 1998-2000 Jeffrey Hobbs 7 * 8 * See the file "license.terms" for information on usage and redistribution 9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10 * 11 * RCS: @(#) $Id: tkTableEdit.c,v 1.7 2002/10/16 07:30:56 hobbs Exp $ 12 */ 13 14#include "tkTable.h" 15 16static void TableModifyRC _ANSI_ARGS_((register Table *tablePtr, 17 int doRows, int movetag, 18 Tcl_HashTable *tagTblPtr, Tcl_HashTable *dimTblPtr, 19 int offset, int from, int to, int lo, int hi, 20 int outOfBounds)); 21 22/* insert/delete subcommands */ 23static CONST84 char *modCmdNames[] = { 24 "active", "cols", "rows", (char *)NULL 25}; 26enum modCmd { 27 MOD_ACTIVE, MOD_COLS, MOD_ROWS 28}; 29 30/* insert/delete row/col switches */ 31static CONST84 char *rcCmdNames[] = { 32 "-keeptitles", "-holddimensions", "-holdselection", 33 "-holdtags", "-holdwindows", "--", 34 (char *) NULL 35}; 36enum rcCmd { 37 OPT_TITLES, OPT_DIMS, OPT_SEL, 38 OPT_TAGS, OPT_WINS, OPT_LAST 39}; 40 41#define HOLD_TITLES 1<<0 42#define HOLD_DIMS 1<<1 43#define HOLD_TAGS 1<<2 44#define HOLD_WINS 1<<3 45#define HOLD_SEL 1<<4 46 47 48/* 49 *-------------------------------------------------------------- 50 * 51 * Table_EditCmd -- 52 * This procedure is invoked to process the insert/delete method 53 * that corresponds to a table widget managed by this module. 54 * See the user documentation for details on what it does. 55 * 56 * Results: 57 * A standard Tcl result. 58 * 59 * Side effects: 60 * See the user documentation. 61 * 62 *-------------------------------------------------------------- 63 */ 64int 65Table_EditCmd(ClientData clientData, register Tcl_Interp *interp, 66 int objc, Tcl_Obj *CONST objv[]) 67{ 68 register Table *tablePtr = (Table *) clientData; 69 int doInsert, cmdIndex, first, last; 70 71 if (objc < 4) { 72 Tcl_WrongNumArgs(interp, 2, objv, 73 "option ?switches? arg ?arg?"); 74 return TCL_ERROR; 75 } 76 if (Tcl_GetIndexFromObj(interp, objv[2], modCmdNames, 77 "option", 0, &cmdIndex) != TCL_OK) { 78 return TCL_ERROR; 79 } 80 81 doInsert = (*(Tcl_GetString(objv[1])) == 'i'); 82 switch ((enum modCmd) cmdIndex) { 83 case MOD_ACTIVE: 84 if (doInsert) { 85 /* INSERT */ 86 if (objc != 5) { 87 Tcl_WrongNumArgs(interp, 3, objv, "index string"); 88 return TCL_ERROR; 89 } 90 if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) { 91 return TCL_ERROR; 92 } else if ((tablePtr->flags & HAS_ACTIVE) && 93 !(tablePtr->flags & ACTIVE_DISABLED) && 94 tablePtr->state == STATE_NORMAL) { 95 TableInsertChars(tablePtr, first, Tcl_GetString(objv[4])); 96 } 97 } else { 98 /* DELETE */ 99 if (objc > 5) { 100 Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); 101 return TCL_ERROR; 102 } 103 if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) { 104 return TCL_ERROR; 105 } 106 if (objc == 4) { 107 last = first+1; 108 } else if (TableGetIcursorObj(tablePtr, objv[4], 109 &last) != TCL_OK) { 110 return TCL_ERROR; 111 } 112 if ((last >= first) && (tablePtr->flags & HAS_ACTIVE) && 113 !(tablePtr->flags & ACTIVE_DISABLED) && 114 tablePtr->state == STATE_NORMAL) { 115 TableDeleteChars(tablePtr, first, last-first); 116 } 117 } 118 break; /* EDIT ACTIVE */ 119 120 case MOD_COLS: 121 case MOD_ROWS: { 122 /* 123 * ROW/COL INSERTION/DELETION 124 * FIX: This doesn't handle spans 125 */ 126 int i, lo, hi, argsLeft, offset, minkeyoff, doRows; 127 int maxrow, maxcol, maxkey, minkey, flags, count, *dimPtr; 128 Tcl_HashTable *tagTblPtr, *dimTblPtr; 129 Tcl_HashSearch search; 130 131 doRows = (cmdIndex == MOD_ROWS); 132 flags = 0; 133 for (i = 3; i < objc; i++) { 134 if (*(Tcl_GetString(objv[i])) != '-') { 135 break; 136 } 137 if (Tcl_GetIndexFromObj(interp, objv[i], rcCmdNames, 138 "switch", 0, &cmdIndex) != TCL_OK) { 139 return TCL_ERROR; 140 } 141 if (cmdIndex == OPT_LAST) { 142 i++; 143 break; 144 } 145 switch (cmdIndex) { 146 case OPT_TITLES: 147 flags |= HOLD_TITLES; 148 break; 149 case OPT_DIMS: 150 flags |= HOLD_DIMS; 151 break; 152 case OPT_SEL: 153 flags |= HOLD_SEL; 154 break; 155 case OPT_TAGS: 156 flags |= HOLD_TAGS; 157 break; 158 case OPT_WINS: 159 flags |= HOLD_WINS; 160 break; 161 } 162 } 163 argsLeft = objc - i; 164 if (argsLeft < 1 || argsLeft > 2) { 165 Tcl_WrongNumArgs(interp, 3, objv, "?switches? index ?count?"); 166 return TCL_ERROR; 167 } 168 169 count = 1; 170 maxcol = tablePtr->cols-1+tablePtr->colOffset; 171 maxrow = tablePtr->rows-1+tablePtr->rowOffset; 172 if (strcmp(Tcl_GetString(objv[i]), "end") == 0) { 173 /* allow "end" to be specified as an index */ 174 first = (doRows) ? maxrow : maxcol; 175 } else if (Tcl_GetIntFromObj(interp, objv[i], &first) != TCL_OK) { 176 return TCL_ERROR; 177 } 178 if (argsLeft == 2 && 179 Tcl_GetIntFromObj(interp, objv[++i], &count) != TCL_OK) { 180 return TCL_ERROR; 181 } 182 if (count == 0 || (tablePtr->state == STATE_DISABLED)) { 183 return TCL_OK; 184 } 185 186 if (doRows) { 187 maxkey = maxrow; 188 minkey = tablePtr->rowOffset; 189 minkeyoff = tablePtr->rowOffset+tablePtr->titleRows; 190 offset = tablePtr->rowOffset; 191 tagTblPtr = tablePtr->rowStyles; 192 dimTblPtr = tablePtr->rowHeights; 193 dimPtr = &(tablePtr->rows); 194 lo = tablePtr->colOffset 195 + ((flags & HOLD_TITLES) ? tablePtr->titleCols : 0); 196 hi = maxcol; 197 } else { 198 maxkey = maxcol; 199 minkey = tablePtr->colOffset; 200 minkeyoff = tablePtr->colOffset+tablePtr->titleCols; 201 offset = tablePtr->colOffset; 202 tagTblPtr = tablePtr->colStyles; 203 dimTblPtr = tablePtr->colWidths; 204 dimPtr = &(tablePtr->cols); 205 lo = tablePtr->rowOffset 206 + ((flags & HOLD_TITLES) ? tablePtr->titleRows : 0); 207 hi = maxrow; 208 } 209 210 /* constrain the starting index */ 211 if (first > maxkey) { 212 first = maxkey; 213 } else if (first < minkey) { 214 first = minkey; 215 } 216 if (doInsert) { 217 /* +count means insert after index, 218 * -count means insert before index */ 219 if (count < 0) { 220 count = -count; 221 } else { 222 first++; 223 } 224 if ((flags & HOLD_TITLES) && (first < minkeyoff)) { 225 count -= minkeyoff-first; 226 if (count <= 0) { 227 return TCL_OK; 228 } 229 first = minkeyoff; 230 } 231 if (!(flags & HOLD_DIMS)) { 232 maxkey += count; 233 *dimPtr += count; 234 } 235 /* 236 * We need to call TableAdjustParams before TableModifyRC to 237 * ensure that side effect code like var traces that might get 238 * called will access the correct new dimensions. 239 */ 240 if (*dimPtr < 1) { 241 *dimPtr = 1; 242 } 243 TableAdjustParams(tablePtr); 244 for (i = maxkey; i >= first; i--) { 245 /* move row/col style && width/height here */ 246 TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, 247 offset, i, i-count, lo, hi, ((i-count) < first)); 248 } 249 if (!(flags & HOLD_WINS)) { 250 /* 251 * This may be a little severe, but it does unmap the 252 * windows that need to be unmapped, and those that should 253 * stay do remap correctly. [Bug #551325] 254 */ 255 if (doRows) { 256 EmbWinUnmap(tablePtr, 257 first - tablePtr->rowOffset, 258 maxkey - tablePtr->rowOffset, 259 lo - tablePtr->colOffset, 260 hi - tablePtr->colOffset); 261 } else { 262 EmbWinUnmap(tablePtr, 263 lo - tablePtr->rowOffset, 264 hi - tablePtr->rowOffset, 265 first - tablePtr->colOffset, 266 maxkey - tablePtr->colOffset); 267 } 268 } 269 } else { 270 /* (index = i && count = 1) == (index = i && count = -1) */ 271 if (count < 0) { 272 /* if the count is negative, make sure that the col count will 273 * delete no greater than the original index */ 274 if (first+count < minkey) { 275 if (first-minkey < abs(count)) { 276 /* 277 * In this case, the user is asking to delete more rows 278 * than exist before the minkey, so we have to shrink 279 * the count down to the existing rows up to index. 280 */ 281 count = first-minkey; 282 } else { 283 count += first-minkey; 284 } 285 first = minkey; 286 } else { 287 first += count; 288 count = -count; 289 } 290 } 291 if ((flags & HOLD_TITLES) && (first <= minkeyoff)) { 292 count -= minkeyoff-first; 293 if (count <= 0) { 294 return TCL_OK; 295 } 296 first = minkeyoff; 297 } 298 if (count > maxkey-first+1) { 299 count = maxkey-first+1; 300 } 301 if (!(flags & HOLD_DIMS)) { 302 *dimPtr -= count; 303 } 304 /* 305 * We need to call TableAdjustParams before TableModifyRC to 306 * ensure that side effect code like var traces that might get 307 * called will access the correct new dimensions. 308 */ 309 if (*dimPtr < 1) { 310 *dimPtr = 1; 311 } 312 TableAdjustParams(tablePtr); 313 for (i = first; i <= maxkey; i++) { 314 TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, 315 offset, i, i+count, lo, hi, ((i+count) > maxkey)); 316 } 317 } 318 if (!(flags & HOLD_SEL) && 319 Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL) { 320 /* clear selection - forceful, but effective */ 321 Tcl_DeleteHashTable(tablePtr->selCells); 322 Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS); 323 } 324 325 /* 326 * Make sure that the modified dimension is actually legal 327 * after removing all that stuff. 328 */ 329 if (*dimPtr < 1) { 330 *dimPtr = 1; 331 TableAdjustParams(tablePtr); 332 } 333 334 /* change the geometry */ 335 TableGeometryRequest(tablePtr); 336 /* FIX: 337 * This has to handle when the previous rows/cols resize because 338 * of the *stretchmode. InvalidateAll does that, but could be 339 * more efficient. 340 */ 341 TableInvalidateAll(tablePtr, 0); 342 break; 343 } 344 345 } 346 return TCL_OK; 347} 348 349/* 350 *---------------------------------------------------------------------- 351 * 352 * TableDeleteChars -- 353 * Remove one or more characters from an table widget. 354 * 355 * Results: 356 * None. 357 * 358 * Side effects: 359 * Memory gets freed, the table gets modified and (eventually) 360 * redisplayed. 361 * 362 *---------------------------------------------------------------------- 363 */ 364void 365TableDeleteChars(tablePtr, index, count) 366 register Table *tablePtr; /* Table widget to modify. */ 367 int index; /* Index of first character to delete. */ 368 int count; /* How many characters to delete. */ 369{ 370#ifdef TCL_UTF_MAX 371 int byteIndex, byteCount, newByteCount, numBytes, numChars; 372 char *new, *string; 373 374 string = tablePtr->activeBuf; 375 numBytes = strlen(string); 376 numChars = Tcl_NumUtfChars(string, numBytes); 377 if ((index + count) > numChars) { 378 count = numChars - index; 379 } 380 if (count <= 0) { 381 return; 382 } 383 384 byteIndex = Tcl_UtfAtIndex(string, index) - string; 385 byteCount = Tcl_UtfAtIndex(string + byteIndex, count) 386 - (string + byteIndex); 387 388 newByteCount = numBytes + 1 - byteCount; 389 new = (char *) ckalloc((unsigned) newByteCount); 390 memcpy(new, string, (size_t) byteIndex); 391 strcpy(new + byteIndex, string + byteIndex + byteCount); 392#else 393 int oldlen; 394 char *new; 395 396 /* this gets the length of the string, as well as ensuring that 397 * the cursor isn't beyond the end char */ 398 TableGetIcursor(tablePtr, "end", &oldlen); 399 400 if ((index+count) > oldlen) 401 count = oldlen-index; 402 if (count <= 0) 403 return; 404 405 new = (char *) ckalloc((unsigned)(oldlen-count+1)); 406 strncpy(new, tablePtr->activeBuf, (size_t) index); 407 strcpy(new+index, tablePtr->activeBuf+index+count); 408 /* make sure this string is null terminated */ 409 new[oldlen-count] = '\0'; 410#endif 411 /* This prevents deletes on BREAK or validation error. */ 412 if (tablePtr->validate && 413 TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, 414 tablePtr->activeCol+tablePtr->colOffset, 415 tablePtr->activeBuf, new, index) != TCL_OK) { 416 ckfree(new); 417 return; 418 } 419 420 ckfree(tablePtr->activeBuf); 421 tablePtr->activeBuf = new; 422 423 /* mark the text as changed */ 424 tablePtr->flags |= TEXT_CHANGED; 425 426 if (tablePtr->icursor >= index) { 427 if (tablePtr->icursor >= (index+count)) { 428 tablePtr->icursor -= count; 429 } else { 430 tablePtr->icursor = index; 431 } 432 } 433 434 TableSetActiveIndex(tablePtr); 435 436 TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); 437} 438 439/* 440 *---------------------------------------------------------------------- 441 * 442 * TableInsertChars -- 443 * Add new characters to the active cell of a table widget. 444 * 445 * Results: 446 * None. 447 * 448 * Side effects: 449 * New information gets added to tablePtr; it will be redisplayed 450 * soon, but not necessarily immediately. 451 * 452 *---------------------------------------------------------------------- 453 */ 454void 455TableInsertChars(tablePtr, index, value) 456 register Table *tablePtr; /* Table that is to get the new elements. */ 457 int index; /* Add the new elements before this element. */ 458 char *value; /* New characters to add (NULL-terminated 459 * string). */ 460{ 461#ifdef TCL_UTF_MAX 462 int oldlen, byteIndex, byteCount; 463 char *new, *string; 464 465 byteCount = strlen(value); 466 if (byteCount == 0) { 467 return; 468 } 469 470 /* Is this an autoclear and this is the first update */ 471 /* Note that this clears without validating */ 472 if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) { 473 /* set the buffer to be empty */ 474 tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1); 475 tablePtr->activeBuf[0] = '\0'; 476 /* the insert position now has to be 0 */ 477 index = 0; 478 tablePtr->icursor = 0; 479 } 480 481 string = tablePtr->activeBuf; 482 byteIndex = Tcl_UtfAtIndex(string, index) - string; 483 484 oldlen = strlen(string); 485 new = (char *) ckalloc((unsigned)(oldlen + byteCount + 1)); 486 memcpy(new, string, (size_t) byteIndex); 487 strcpy(new + byteIndex, value); 488 strcpy(new + byteIndex + byteCount, string + byteIndex); 489 490 /* validate potential new active buffer */ 491 /* This prevents inserts on either BREAK or validation error. */ 492 if (tablePtr->validate && 493 TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, 494 tablePtr->activeCol+tablePtr->colOffset, 495 tablePtr->activeBuf, new, byteIndex) != TCL_OK) { 496 ckfree(new); 497 return; 498 } 499 500 /* 501 * The following construction is used because inserting improperly 502 * formed UTF-8 sequences between other improperly formed UTF-8 503 * sequences could result in actually forming valid UTF-8 sequences; 504 * the number of characters added may not be Tcl_NumUtfChars(string, -1), 505 * because of context. The actual number of characters added is how 506 * many characters were are in the string now minus the number that 507 * used to be there. 508 */ 509 510 if (tablePtr->icursor >= index) { 511 tablePtr->icursor += Tcl_NumUtfChars(new, oldlen+byteCount) 512 - Tcl_NumUtfChars(tablePtr->activeBuf, oldlen); 513 } 514 515 ckfree(string); 516 tablePtr->activeBuf = new; 517 518#else 519 int oldlen, newlen; 520 char *new; 521 522 newlen = strlen(value); 523 if (newlen == 0) return; 524 525 /* Is this an autoclear and this is the first update */ 526 /* Note that this clears without validating */ 527 if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) { 528 /* set the buffer to be empty */ 529 tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1); 530 tablePtr->activeBuf[0] = '\0'; 531 /* the insert position now has to be 0 */ 532 index = 0; 533 } 534 oldlen = strlen(tablePtr->activeBuf); 535 /* get the buffer to at least the right length */ 536 new = (char *) ckalloc((unsigned)(oldlen+newlen+1)); 537 strncpy(new, tablePtr->activeBuf, (size_t) index); 538 strcpy(new+index, value); 539 strcpy(new+index+newlen, (tablePtr->activeBuf)+index); 540 /* make sure this string is null terminated */ 541 new[oldlen+newlen] = '\0'; 542 543 /* validate potential new active buffer */ 544 /* This prevents inserts on either BREAK or validation error. */ 545 if (tablePtr->validate && 546 TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, 547 tablePtr->activeCol+tablePtr->colOffset, 548 tablePtr->activeBuf, new, index) != TCL_OK) { 549 ckfree(new); 550 return; 551 } 552 ckfree(tablePtr->activeBuf); 553 tablePtr->activeBuf = new; 554 555 if (tablePtr->icursor >= index) { 556 tablePtr->icursor += newlen; 557 } 558#endif 559 560 /* mark the text as changed */ 561 tablePtr->flags |= TEXT_CHANGED; 562 563 TableSetActiveIndex(tablePtr); 564 565 TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); 566} 567 568/* 569 *---------------------------------------------------------------------- 570 * 571 * TableModifyRC -- 572 * Helper function that does the core work of moving rows/cols 573 * and associated tags. 574 * 575 * Results: 576 * None. 577 * 578 * Side effects: 579 * Moves cell data and possibly tag data 580 * 581 *---------------------------------------------------------------------- 582 */ 583static void 584TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, 585 offset, from, to, lo, hi, outOfBounds) 586 Table *tablePtr; /* Information about text widget. */ 587 int doRows; /* rows (1) or cols (0) */ 588 int flags; /* flags indicating what to move */ 589 Tcl_HashTable *tagTblPtr, *dimTblPtr; /* Pointers to the row/col tags 590 * and width/height tags */ 591 int offset; /* appropriate offset */ 592 int from, to; /* the from and to row/col */ 593 int lo, hi; /* the lo and hi col/row */ 594 int outOfBounds; /* the boundary check for shifting items */ 595{ 596 int j, new; 597 char buf[INDEX_BUFSIZE], buf1[INDEX_BUFSIZE]; 598 Tcl_HashEntry *entryPtr, *newPtr; 599 TableEmbWindow *ewPtr; 600 601 /* 602 * move row/col style && width/height here 603 * If -holdtags is specified, we don't move the user-set widths/heights 604 * of the absolute rows/columns, otherwise we enter here to move the 605 * dimensions appropriately 606 */ 607 if (!(flags & HOLD_TAGS)) { 608 entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)from); 609 if (entryPtr != NULL) { 610 Tcl_DeleteHashEntry(entryPtr); 611 } 612 entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)from-offset); 613 if (entryPtr != NULL) { 614 Tcl_DeleteHashEntry(entryPtr); 615 } 616 if (!outOfBounds) { 617 entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)to); 618 if (entryPtr != NULL) { 619 newPtr = Tcl_CreateHashEntry(tagTblPtr, (char *)from, &new); 620 Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); 621 Tcl_DeleteHashEntry(entryPtr); 622 } 623 entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)to-offset); 624 if (entryPtr != NULL) { 625 newPtr = Tcl_CreateHashEntry(dimTblPtr, (char *)from-offset, 626 &new); 627 Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); 628 Tcl_DeleteHashEntry(entryPtr); 629 } 630 } 631 } 632 for (j = lo; j <= hi; j++) { 633 if (doRows /* rows */) { 634 TableMakeArrayIndex(from, j, buf); 635 TableMakeArrayIndex(to, j, buf1); 636 TableMoveCellValue(tablePtr, to, j, buf1, from, j, buf, 637 outOfBounds); 638 } else { 639 TableMakeArrayIndex(j, from, buf); 640 TableMakeArrayIndex(j, to, buf1); 641 TableMoveCellValue(tablePtr, j, to, buf1, j, from, buf, 642 outOfBounds); 643 } 644 /* 645 * If -holdselection is specified, we leave the selected cells in the 646 * absolute cell values, otherwise we enter here to move the 647 * selection appropriately 648 */ 649 if (!(flags & HOLD_SEL)) { 650 entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf); 651 if (entryPtr != NULL) { 652 Tcl_DeleteHashEntry(entryPtr); 653 } 654 if (!outOfBounds) { 655 entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1); 656 if (entryPtr != NULL) { 657 Tcl_CreateHashEntry(tablePtr->selCells, buf, &new); 658 Tcl_DeleteHashEntry(entryPtr); 659 } 660 } 661 } 662 /* 663 * If -holdtags is specified, we leave the tags in the 664 * absolute cell values, otherwise we enter here to move the 665 * tags appropriately 666 */ 667 if (!(flags & HOLD_TAGS)) { 668 entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf); 669 if (entryPtr != NULL) { 670 Tcl_DeleteHashEntry(entryPtr); 671 } 672 if (!outOfBounds) { 673 entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf1); 674 if (entryPtr != NULL) { 675 newPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf, 676 &new); 677 Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); 678 Tcl_DeleteHashEntry(entryPtr); 679 } 680 } 681 } 682 /* 683 * If -holdwindows is specified, we leave the windows in the 684 * absolute cell values, otherwise we enter here to move the 685 * windows appropriately 686 */ 687 if (!(flags & HOLD_WINS)) { 688 /* 689 * Delete whatever window might be in our destination 690 */ 691 Table_WinDelete(tablePtr, buf); 692 if (!outOfBounds) { 693 /* 694 * buf1 is where the window is 695 * buf is where we want it to be 696 * 697 * This is an adaptation of Table_WinMove, which we can't 698 * use because we are intermediately fiddling with boundaries 699 */ 700 entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf1); 701 if (entryPtr != NULL) { 702 /* 703 * If there was a window in our source, 704 * get the window pointer to move it 705 */ 706 ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); 707 /* and free the old hash table entry */ 708 Tcl_DeleteHashEntry(entryPtr); 709 710 entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, 711 &new); 712 /* 713 * We needn't check if a window was in buf, since the 714 * Table_WinDelete above should guarantee that no window 715 * is there. Just set the new entry's value. 716 */ 717 Tcl_SetHashValue(entryPtr, (ClientData) ewPtr); 718 ewPtr->hPtr = entryPtr; 719 } 720 } 721 } 722 } 723} 724