724 lines
20 KiB
C
724 lines
20 KiB
C
/*
|
|
* tkTableEdit.c --
|
|
*
|
|
* This module implements editing functions of a table widget.
|
|
*
|
|
* Copyright (c) 1998-2000 Jeffrey Hobbs
|
|
*
|
|
* See the file "license.terms" for information on usage and redistribution
|
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
*
|
|
* RCS: @(#) $Id: tkTableEdit.c,v 1.7 2002/10/16 07:30:56 hobbs Exp $
|
|
*/
|
|
|
|
#include "tkTable.h"
|
|
|
|
static void TableModifyRC _ANSI_ARGS_((register Table *tablePtr,
|
|
int doRows, int movetag,
|
|
Tcl_HashTable *tagTblPtr, Tcl_HashTable *dimTblPtr,
|
|
int offset, int from, int to, int lo, int hi,
|
|
int outOfBounds));
|
|
|
|
/* insert/delete subcommands */
|
|
static CONST84 char *modCmdNames[] = {
|
|
"active", "cols", "rows", (char *)NULL
|
|
};
|
|
enum modCmd {
|
|
MOD_ACTIVE, MOD_COLS, MOD_ROWS
|
|
};
|
|
|
|
/* insert/delete row/col switches */
|
|
static CONST84 char *rcCmdNames[] = {
|
|
"-keeptitles", "-holddimensions", "-holdselection",
|
|
"-holdtags", "-holdwindows", "--",
|
|
(char *) NULL
|
|
};
|
|
enum rcCmd {
|
|
OPT_TITLES, OPT_DIMS, OPT_SEL,
|
|
OPT_TAGS, OPT_WINS, OPT_LAST
|
|
};
|
|
|
|
#define HOLD_TITLES 1<<0
|
|
#define HOLD_DIMS 1<<1
|
|
#define HOLD_TAGS 1<<2
|
|
#define HOLD_WINS 1<<3
|
|
#define HOLD_SEL 1<<4
|
|
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
*
|
|
* Table_EditCmd --
|
|
* This procedure is invoked to process the insert/delete method
|
|
* that corresponds to a table widget managed by this module.
|
|
* See the user documentation for details on what it does.
|
|
*
|
|
* Results:
|
|
* A standard Tcl result.
|
|
*
|
|
* Side effects:
|
|
* See the user documentation.
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
int
|
|
Table_EditCmd(ClientData clientData, register Tcl_Interp *interp,
|
|
int objc, Tcl_Obj *CONST objv[])
|
|
{
|
|
register Table *tablePtr = (Table *) clientData;
|
|
int doInsert, cmdIndex, first, last;
|
|
|
|
if (objc < 4) {
|
|
Tcl_WrongNumArgs(interp, 2, objv,
|
|
"option ?switches? arg ?arg?");
|
|
return TCL_ERROR;
|
|
}
|
|
if (Tcl_GetIndexFromObj(interp, objv[2], modCmdNames,
|
|
"option", 0, &cmdIndex) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
doInsert = (*(Tcl_GetString(objv[1])) == 'i');
|
|
switch ((enum modCmd) cmdIndex) {
|
|
case MOD_ACTIVE:
|
|
if (doInsert) {
|
|
/* INSERT */
|
|
if (objc != 5) {
|
|
Tcl_WrongNumArgs(interp, 3, objv, "index string");
|
|
return TCL_ERROR;
|
|
}
|
|
if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
} else if ((tablePtr->flags & HAS_ACTIVE) &&
|
|
!(tablePtr->flags & ACTIVE_DISABLED) &&
|
|
tablePtr->state == STATE_NORMAL) {
|
|
TableInsertChars(tablePtr, first, Tcl_GetString(objv[4]));
|
|
}
|
|
} else {
|
|
/* DELETE */
|
|
if (objc > 5) {
|
|
Tcl_WrongNumArgs(interp, 3, objv, "first ?last?");
|
|
return TCL_ERROR;
|
|
}
|
|
if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
if (objc == 4) {
|
|
last = first+1;
|
|
} else if (TableGetIcursorObj(tablePtr, objv[4],
|
|
&last) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
if ((last >= first) && (tablePtr->flags & HAS_ACTIVE) &&
|
|
!(tablePtr->flags & ACTIVE_DISABLED) &&
|
|
tablePtr->state == STATE_NORMAL) {
|
|
TableDeleteChars(tablePtr, first, last-first);
|
|
}
|
|
}
|
|
break; /* EDIT ACTIVE */
|
|
|
|
case MOD_COLS:
|
|
case MOD_ROWS: {
|
|
/*
|
|
* ROW/COL INSERTION/DELETION
|
|
* FIX: This doesn't handle spans
|
|
*/
|
|
int i, lo, hi, argsLeft, offset, minkeyoff, doRows;
|
|
int maxrow, maxcol, maxkey, minkey, flags, count, *dimPtr;
|
|
Tcl_HashTable *tagTblPtr, *dimTblPtr;
|
|
Tcl_HashSearch search;
|
|
|
|
doRows = (cmdIndex == MOD_ROWS);
|
|
flags = 0;
|
|
for (i = 3; i < objc; i++) {
|
|
if (*(Tcl_GetString(objv[i])) != '-') {
|
|
break;
|
|
}
|
|
if (Tcl_GetIndexFromObj(interp, objv[i], rcCmdNames,
|
|
"switch", 0, &cmdIndex) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
if (cmdIndex == OPT_LAST) {
|
|
i++;
|
|
break;
|
|
}
|
|
switch (cmdIndex) {
|
|
case OPT_TITLES:
|
|
flags |= HOLD_TITLES;
|
|
break;
|
|
case OPT_DIMS:
|
|
flags |= HOLD_DIMS;
|
|
break;
|
|
case OPT_SEL:
|
|
flags |= HOLD_SEL;
|
|
break;
|
|
case OPT_TAGS:
|
|
flags |= HOLD_TAGS;
|
|
break;
|
|
case OPT_WINS:
|
|
flags |= HOLD_WINS;
|
|
break;
|
|
}
|
|
}
|
|
argsLeft = objc - i;
|
|
if (argsLeft < 1 || argsLeft > 2) {
|
|
Tcl_WrongNumArgs(interp, 3, objv, "?switches? index ?count?");
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
count = 1;
|
|
maxcol = tablePtr->cols-1+tablePtr->colOffset;
|
|
maxrow = tablePtr->rows-1+tablePtr->rowOffset;
|
|
if (strcmp(Tcl_GetString(objv[i]), "end") == 0) {
|
|
/* allow "end" to be specified as an index */
|
|
first = (doRows) ? maxrow : maxcol;
|
|
} else if (Tcl_GetIntFromObj(interp, objv[i], &first) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
if (argsLeft == 2 &&
|
|
Tcl_GetIntFromObj(interp, objv[++i], &count) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
if (count == 0 || (tablePtr->state == STATE_DISABLED)) {
|
|
return TCL_OK;
|
|
}
|
|
|
|
if (doRows) {
|
|
maxkey = maxrow;
|
|
minkey = tablePtr->rowOffset;
|
|
minkeyoff = tablePtr->rowOffset+tablePtr->titleRows;
|
|
offset = tablePtr->rowOffset;
|
|
tagTblPtr = tablePtr->rowStyles;
|
|
dimTblPtr = tablePtr->rowHeights;
|
|
dimPtr = &(tablePtr->rows);
|
|
lo = tablePtr->colOffset
|
|
+ ((flags & HOLD_TITLES) ? tablePtr->titleCols : 0);
|
|
hi = maxcol;
|
|
} else {
|
|
maxkey = maxcol;
|
|
minkey = tablePtr->colOffset;
|
|
minkeyoff = tablePtr->colOffset+tablePtr->titleCols;
|
|
offset = tablePtr->colOffset;
|
|
tagTblPtr = tablePtr->colStyles;
|
|
dimTblPtr = tablePtr->colWidths;
|
|
dimPtr = &(tablePtr->cols);
|
|
lo = tablePtr->rowOffset
|
|
+ ((flags & HOLD_TITLES) ? tablePtr->titleRows : 0);
|
|
hi = maxrow;
|
|
}
|
|
|
|
/* constrain the starting index */
|
|
if (first > maxkey) {
|
|
first = maxkey;
|
|
} else if (first < minkey) {
|
|
first = minkey;
|
|
}
|
|
if (doInsert) {
|
|
/* +count means insert after index,
|
|
* -count means insert before index */
|
|
if (count < 0) {
|
|
count = -count;
|
|
} else {
|
|
first++;
|
|
}
|
|
if ((flags & HOLD_TITLES) && (first < minkeyoff)) {
|
|
count -= minkeyoff-first;
|
|
if (count <= 0) {
|
|
return TCL_OK;
|
|
}
|
|
first = minkeyoff;
|
|
}
|
|
if (!(flags & HOLD_DIMS)) {
|
|
maxkey += count;
|
|
*dimPtr += count;
|
|
}
|
|
/*
|
|
* We need to call TableAdjustParams before TableModifyRC to
|
|
* ensure that side effect code like var traces that might get
|
|
* called will access the correct new dimensions.
|
|
*/
|
|
if (*dimPtr < 1) {
|
|
*dimPtr = 1;
|
|
}
|
|
TableAdjustParams(tablePtr);
|
|
for (i = maxkey; i >= first; i--) {
|
|
/* move row/col style && width/height here */
|
|
TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr,
|
|
offset, i, i-count, lo, hi, ((i-count) < first));
|
|
}
|
|
if (!(flags & HOLD_WINS)) {
|
|
/*
|
|
* This may be a little severe, but it does unmap the
|
|
* windows that need to be unmapped, and those that should
|
|
* stay do remap correctly. [Bug #551325]
|
|
*/
|
|
if (doRows) {
|
|
EmbWinUnmap(tablePtr,
|
|
first - tablePtr->rowOffset,
|
|
maxkey - tablePtr->rowOffset,
|
|
lo - tablePtr->colOffset,
|
|
hi - tablePtr->colOffset);
|
|
} else {
|
|
EmbWinUnmap(tablePtr,
|
|
lo - tablePtr->rowOffset,
|
|
hi - tablePtr->rowOffset,
|
|
first - tablePtr->colOffset,
|
|
maxkey - tablePtr->colOffset);
|
|
}
|
|
}
|
|
} else {
|
|
/* (index = i && count = 1) == (index = i && count = -1) */
|
|
if (count < 0) {
|
|
/* if the count is negative, make sure that the col count will
|
|
* delete no greater than the original index */
|
|
if (first+count < minkey) {
|
|
if (first-minkey < abs(count)) {
|
|
/*
|
|
* In this case, the user is asking to delete more rows
|
|
* than exist before the minkey, so we have to shrink
|
|
* the count down to the existing rows up to index.
|
|
*/
|
|
count = first-minkey;
|
|
} else {
|
|
count += first-minkey;
|
|
}
|
|
first = minkey;
|
|
} else {
|
|
first += count;
|
|
count = -count;
|
|
}
|
|
}
|
|
if ((flags & HOLD_TITLES) && (first <= minkeyoff)) {
|
|
count -= minkeyoff-first;
|
|
if (count <= 0) {
|
|
return TCL_OK;
|
|
}
|
|
first = minkeyoff;
|
|
}
|
|
if (count > maxkey-first+1) {
|
|
count = maxkey-first+1;
|
|
}
|
|
if (!(flags & HOLD_DIMS)) {
|
|
*dimPtr -= count;
|
|
}
|
|
/*
|
|
* We need to call TableAdjustParams before TableModifyRC to
|
|
* ensure that side effect code like var traces that might get
|
|
* called will access the correct new dimensions.
|
|
*/
|
|
if (*dimPtr < 1) {
|
|
*dimPtr = 1;
|
|
}
|
|
TableAdjustParams(tablePtr);
|
|
for (i = first; i <= maxkey; i++) {
|
|
TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr,
|
|
offset, i, i+count, lo, hi, ((i+count) > maxkey));
|
|
}
|
|
}
|
|
if (!(flags & HOLD_SEL) &&
|
|
Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL) {
|
|
/* clear selection - forceful, but effective */
|
|
Tcl_DeleteHashTable(tablePtr->selCells);
|
|
Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
|
|
}
|
|
|
|
/*
|
|
* Make sure that the modified dimension is actually legal
|
|
* after removing all that stuff.
|
|
*/
|
|
if (*dimPtr < 1) {
|
|
*dimPtr = 1;
|
|
TableAdjustParams(tablePtr);
|
|
}
|
|
|
|
/* change the geometry */
|
|
TableGeometryRequest(tablePtr);
|
|
/* FIX:
|
|
* This has to handle when the previous rows/cols resize because
|
|
* of the *stretchmode. InvalidateAll does that, but could be
|
|
* more efficient.
|
|
*/
|
|
TableInvalidateAll(tablePtr, 0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
return TCL_OK;
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* TableDeleteChars --
|
|
* Remove one or more characters from an table widget.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Memory gets freed, the table gets modified and (eventually)
|
|
* redisplayed.
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
void
|
|
TableDeleteChars(tablePtr, index, count)
|
|
register Table *tablePtr; /* Table widget to modify. */
|
|
int index; /* Index of first character to delete. */
|
|
int count; /* How many characters to delete. */
|
|
{
|
|
#ifdef TCL_UTF_MAX
|
|
int byteIndex, byteCount, newByteCount, numBytes, numChars;
|
|
char *new, *string;
|
|
|
|
string = tablePtr->activeBuf;
|
|
numBytes = strlen(string);
|
|
numChars = Tcl_NumUtfChars(string, numBytes);
|
|
if ((index + count) > numChars) {
|
|
count = numChars - index;
|
|
}
|
|
if (count <= 0) {
|
|
return;
|
|
}
|
|
|
|
byteIndex = Tcl_UtfAtIndex(string, index) - string;
|
|
byteCount = Tcl_UtfAtIndex(string + byteIndex, count)
|
|
- (string + byteIndex);
|
|
|
|
newByteCount = numBytes + 1 - byteCount;
|
|
new = (char *) ckalloc((unsigned) newByteCount);
|
|
memcpy(new, string, (size_t) byteIndex);
|
|
strcpy(new + byteIndex, string + byteIndex + byteCount);
|
|
#else
|
|
int oldlen;
|
|
char *new;
|
|
|
|
/* this gets the length of the string, as well as ensuring that
|
|
* the cursor isn't beyond the end char */
|
|
TableGetIcursor(tablePtr, "end", &oldlen);
|
|
|
|
if ((index+count) > oldlen)
|
|
count = oldlen-index;
|
|
if (count <= 0)
|
|
return;
|
|
|
|
new = (char *) ckalloc((unsigned)(oldlen-count+1));
|
|
strncpy(new, tablePtr->activeBuf, (size_t) index);
|
|
strcpy(new+index, tablePtr->activeBuf+index+count);
|
|
/* make sure this string is null terminated */
|
|
new[oldlen-count] = '\0';
|
|
#endif
|
|
/* This prevents deletes on BREAK or validation error. */
|
|
if (tablePtr->validate &&
|
|
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
|
tablePtr->activeBuf, new, index) != TCL_OK) {
|
|
ckfree(new);
|
|
return;
|
|
}
|
|
|
|
ckfree(tablePtr->activeBuf);
|
|
tablePtr->activeBuf = new;
|
|
|
|
/* mark the text as changed */
|
|
tablePtr->flags |= TEXT_CHANGED;
|
|
|
|
if (tablePtr->icursor >= index) {
|
|
if (tablePtr->icursor >= (index+count)) {
|
|
tablePtr->icursor -= count;
|
|
} else {
|
|
tablePtr->icursor = index;
|
|
}
|
|
}
|
|
|
|
TableSetActiveIndex(tablePtr);
|
|
|
|
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL);
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* TableInsertChars --
|
|
* Add new characters to the active cell of a table widget.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* New information gets added to tablePtr; it will be redisplayed
|
|
* soon, but not necessarily immediately.
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
void
|
|
TableInsertChars(tablePtr, index, value)
|
|
register Table *tablePtr; /* Table that is to get the new elements. */
|
|
int index; /* Add the new elements before this element. */
|
|
char *value; /* New characters to add (NULL-terminated
|
|
* string). */
|
|
{
|
|
#ifdef TCL_UTF_MAX
|
|
int oldlen, byteIndex, byteCount;
|
|
char *new, *string;
|
|
|
|
byteCount = strlen(value);
|
|
if (byteCount == 0) {
|
|
return;
|
|
}
|
|
|
|
/* Is this an autoclear and this is the first update */
|
|
/* Note that this clears without validating */
|
|
if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
|
|
/* set the buffer to be empty */
|
|
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
|
|
tablePtr->activeBuf[0] = '\0';
|
|
/* the insert position now has to be 0 */
|
|
index = 0;
|
|
tablePtr->icursor = 0;
|
|
}
|
|
|
|
string = tablePtr->activeBuf;
|
|
byteIndex = Tcl_UtfAtIndex(string, index) - string;
|
|
|
|
oldlen = strlen(string);
|
|
new = (char *) ckalloc((unsigned)(oldlen + byteCount + 1));
|
|
memcpy(new, string, (size_t) byteIndex);
|
|
strcpy(new + byteIndex, value);
|
|
strcpy(new + byteIndex + byteCount, string + byteIndex);
|
|
|
|
/* validate potential new active buffer */
|
|
/* This prevents inserts on either BREAK or validation error. */
|
|
if (tablePtr->validate &&
|
|
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
|
tablePtr->activeBuf, new, byteIndex) != TCL_OK) {
|
|
ckfree(new);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* The following construction is used because inserting improperly
|
|
* formed UTF-8 sequences between other improperly formed UTF-8
|
|
* sequences could result in actually forming valid UTF-8 sequences;
|
|
* the number of characters added may not be Tcl_NumUtfChars(string, -1),
|
|
* because of context. The actual number of characters added is how
|
|
* many characters were are in the string now minus the number that
|
|
* used to be there.
|
|
*/
|
|
|
|
if (tablePtr->icursor >= index) {
|
|
tablePtr->icursor += Tcl_NumUtfChars(new, oldlen+byteCount)
|
|
- Tcl_NumUtfChars(tablePtr->activeBuf, oldlen);
|
|
}
|
|
|
|
ckfree(string);
|
|
tablePtr->activeBuf = new;
|
|
|
|
#else
|
|
int oldlen, newlen;
|
|
char *new;
|
|
|
|
newlen = strlen(value);
|
|
if (newlen == 0) return;
|
|
|
|
/* Is this an autoclear and this is the first update */
|
|
/* Note that this clears without validating */
|
|
if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
|
|
/* set the buffer to be empty */
|
|
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
|
|
tablePtr->activeBuf[0] = '\0';
|
|
/* the insert position now has to be 0 */
|
|
index = 0;
|
|
}
|
|
oldlen = strlen(tablePtr->activeBuf);
|
|
/* get the buffer to at least the right length */
|
|
new = (char *) ckalloc((unsigned)(oldlen+newlen+1));
|
|
strncpy(new, tablePtr->activeBuf, (size_t) index);
|
|
strcpy(new+index, value);
|
|
strcpy(new+index+newlen, (tablePtr->activeBuf)+index);
|
|
/* make sure this string is null terminated */
|
|
new[oldlen+newlen] = '\0';
|
|
|
|
/* validate potential new active buffer */
|
|
/* This prevents inserts on either BREAK or validation error. */
|
|
if (tablePtr->validate &&
|
|
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
|
tablePtr->activeBuf, new, index) != TCL_OK) {
|
|
ckfree(new);
|
|
return;
|
|
}
|
|
ckfree(tablePtr->activeBuf);
|
|
tablePtr->activeBuf = new;
|
|
|
|
if (tablePtr->icursor >= index) {
|
|
tablePtr->icursor += newlen;
|
|
}
|
|
#endif
|
|
|
|
/* mark the text as changed */
|
|
tablePtr->flags |= TEXT_CHANGED;
|
|
|
|
TableSetActiveIndex(tablePtr);
|
|
|
|
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL);
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* TableModifyRC --
|
|
* Helper function that does the core work of moving rows/cols
|
|
* and associated tags.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Moves cell data and possibly tag data
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr,
|
|
offset, from, to, lo, hi, outOfBounds)
|
|
Table *tablePtr; /* Information about text widget. */
|
|
int doRows; /* rows (1) or cols (0) */
|
|
int flags; /* flags indicating what to move */
|
|
Tcl_HashTable *tagTblPtr, *dimTblPtr; /* Pointers to the row/col tags
|
|
* and width/height tags */
|
|
int offset; /* appropriate offset */
|
|
int from, to; /* the from and to row/col */
|
|
int lo, hi; /* the lo and hi col/row */
|
|
int outOfBounds; /* the boundary check for shifting items */
|
|
{
|
|
int j, new;
|
|
char buf[INDEX_BUFSIZE], buf1[INDEX_BUFSIZE];
|
|
Tcl_HashEntry *entryPtr, *newPtr;
|
|
TableEmbWindow *ewPtr;
|
|
|
|
/*
|
|
* move row/col style && width/height here
|
|
* If -holdtags is specified, we don't move the user-set widths/heights
|
|
* of the absolute rows/columns, otherwise we enter here to move the
|
|
* dimensions appropriately
|
|
*/
|
|
if (!(flags & HOLD_TAGS)) {
|
|
entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)from);
|
|
if (entryPtr != NULL) {
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)from-offset);
|
|
if (entryPtr != NULL) {
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
if (!outOfBounds) {
|
|
entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)to);
|
|
if (entryPtr != NULL) {
|
|
newPtr = Tcl_CreateHashEntry(tagTblPtr, (char *)from, &new);
|
|
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)to-offset);
|
|
if (entryPtr != NULL) {
|
|
newPtr = Tcl_CreateHashEntry(dimTblPtr, (char *)from-offset,
|
|
&new);
|
|
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
}
|
|
}
|
|
for (j = lo; j <= hi; j++) {
|
|
if (doRows /* rows */) {
|
|
TableMakeArrayIndex(from, j, buf);
|
|
TableMakeArrayIndex(to, j, buf1);
|
|
TableMoveCellValue(tablePtr, to, j, buf1, from, j, buf,
|
|
outOfBounds);
|
|
} else {
|
|
TableMakeArrayIndex(j, from, buf);
|
|
TableMakeArrayIndex(j, to, buf1);
|
|
TableMoveCellValue(tablePtr, j, to, buf1, j, from, buf,
|
|
outOfBounds);
|
|
}
|
|
/*
|
|
* If -holdselection is specified, we leave the selected cells in the
|
|
* absolute cell values, otherwise we enter here to move the
|
|
* selection appropriately
|
|
*/
|
|
if (!(flags & HOLD_SEL)) {
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf);
|
|
if (entryPtr != NULL) {
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
if (!outOfBounds) {
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1);
|
|
if (entryPtr != NULL) {
|
|
Tcl_CreateHashEntry(tablePtr->selCells, buf, &new);
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* If -holdtags is specified, we leave the tags in the
|
|
* absolute cell values, otherwise we enter here to move the
|
|
* tags appropriately
|
|
*/
|
|
if (!(flags & HOLD_TAGS)) {
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf);
|
|
if (entryPtr != NULL) {
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
if (!outOfBounds) {
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf1);
|
|
if (entryPtr != NULL) {
|
|
newPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf,
|
|
&new);
|
|
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* If -holdwindows is specified, we leave the windows in the
|
|
* absolute cell values, otherwise we enter here to move the
|
|
* windows appropriately
|
|
*/
|
|
if (!(flags & HOLD_WINS)) {
|
|
/*
|
|
* Delete whatever window might be in our destination
|
|
*/
|
|
Table_WinDelete(tablePtr, buf);
|
|
if (!outOfBounds) {
|
|
/*
|
|
* buf1 is where the window is
|
|
* buf is where we want it to be
|
|
*
|
|
* This is an adaptation of Table_WinMove, which we can't
|
|
* use because we are intermediately fiddling with boundaries
|
|
*/
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf1);
|
|
if (entryPtr != NULL) {
|
|
/*
|
|
* If there was a window in our source,
|
|
* get the window pointer to move it
|
|
*/
|
|
ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
|
|
/* and free the old hash table entry */
|
|
Tcl_DeleteHashEntry(entryPtr);
|
|
|
|
entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf,
|
|
&new);
|
|
/*
|
|
* We needn't check if a window was in buf, since the
|
|
* Table_WinDelete above should guarantee that no window
|
|
* is there. Just set the new entry's value.
|
|
*/
|
|
Tcl_SetHashValue(entryPtr, (ClientData) ewPtr);
|
|
ewPtr->hPtr = entryPtr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|