2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: EditCalls.c /main/4 1996/03/26 19:53:27 drk $
24 **********************************<+>*************************************
25 ***************************************************************************
29 ** Project: DtEditor widget interface for text edit services.
31 ** Description: Contains the public functions related to undo,
32 ** cut, copy, paste, and the internal Modify/Verify callback.
35 *******************************************************************
36 * (c) Copyright 1996 Digital Equipment Corporation.
37 * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company.
38 * (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
39 * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
40 * (c) Copyright 1996 Novell, Inc.
41 * (c) Copyright 1996 FUJITSU LIMITED.
42 * (c) Copyright 1996 Hitachi.
43 * (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
44 ********************************************************************
47 **************************************************************************
48 **********************************<+>*************************************/
51 #include "DtWidgetI.h"
55 DtEditorWidget editor)
59 * Reset deletion & insertion contexts.
62 if( (M_deletedText(editor) != (char *)NULL) &&
63 (strlen(M_deletedText(editor)) != 0) )
65 XtFree(M_deletedText(editor));
66 M_deletedText(editor) = (char *) NULL;
69 M_deletionStart(editor) = NO_DELETION_IN_PROGRESS;
70 M_insertStart(editor) = 0;
71 M_insertionLength(editor) = 0;
73 } /* end _DtEditorResetUndo */
80 DtEditorWidget pPriv = (DtEditorWidget) widget;
81 _DtWidgetToAppContext(widget);
85 * Remove any insertion, and then put back any previous deletion.
86 * The tricky part is that removing the insertion looks like a deletion
87 * and the modifyVerify callback will save in the undo buffer, wiping
88 * out any previous deletion (before we can reinsert it). So we have to
89 * save the previous deletion before undoing the insertion so we can
90 * reinsert it. Make sense?
92 if(M_insertionLength(pPriv) != 0)
95 * There is an insertion so remove everything we just inserted
97 if( (M_deletedText(pPriv) != (char *)NULL) &&
98 (strlen(M_deletedText(pPriv)) != 0) )
101 * If there is a current deletion, save it before removing the
102 * insertion so we can put it back (i.e. undo the deletion).
104 int oldDeleteStart = M_deletionStart(pPriv);
105 char *oldDeletion = M_deletedText(pPriv);
106 M_deletedText(pPriv) = (char *)NULL;
109 * 1. Delete the last insertion.
111 XmTextSetSelection(M_text(pPriv), M_insertStart(pPriv),
112 M_insertStart(pPriv) + M_insertionLength(pPriv),
115 M_insertionLength(pPriv)=0;
116 XmTextRemove(M_text(pPriv));
119 * 2. Put back the previous deletion.
121 XmTextInsert(M_text(pPriv), oldDeleteStart, oldDeletion);
128 * There is no deletion, so we just have to remove the
131 XmTextSetSelection(M_text(pPriv), M_insertStart(pPriv),
132 M_insertStart(pPriv) + M_insertionLength(pPriv),
134 M_insertionLength(pPriv) = 0;
135 XmTextRemove(M_text(pPriv));
138 else if(M_deletedText(pPriv) != (char *)NULL)
141 * Nothing has been inserted so just undo the previous deletion.
144 char *oldDeletion = M_deletedText(pPriv);
145 M_deletedText(pPriv) = (char *)NULL;
147 XmTextInsert(M_text(pPriv), M_deletionStart(pPriv), oldDeletion);
154 * There is no insertion to remove or deletion to put back in
155 * (i.e. nothing to undo) so return False.
164 } /* end DtEditorUndoEdit */
167 DtEditorCutToClipboard(
171 DtEditorWidget editor = (DtEditorWidget) widget;
173 _DtWidgetToAppContext(widget);
177 * Create an event with a correct timestamp
179 event = (XEvent *) XtMalloc( sizeof(XEvent) );
180 event->xkey.time = XtLastTimestampProcessed( M_display(editor) );
183 * Call routine to cut selection to clipboard
185 XtCallActionProc(M_text(editor), "cut-clipboard", event, NULL, 0);
187 XtFree( (char *) event );
195 DtEditorCopyToClipboard(
198 DtEditorWidget editor = (DtEditorWidget) widget;
200 _DtWidgetToAppContext(widget);
204 * Create an event with a correct timestamp
206 event = (XEvent *) XtMalloc( sizeof(XEvent) );
207 event->xkey.time = XtLastTimestampProcessed( M_display(editor) );
210 * Call routine to copy selection to clipboard
212 XtCallActionProc(M_text(editor), "copy-clipboard", event, NULL, 0);
214 XtFree( (char *) event );
221 DtEditorPasteFromClipboard(
224 DtEditorWidget editor = (DtEditorWidget) widget;
226 _DtWidgetToAppContext(widget);
230 * Create an event with a correct timestamp
232 event = (XEvent *) XtMalloc( sizeof(XEvent) );
233 event->xkey.time = XtLastTimestampProcessed( M_display(editor) );
236 * Call routine to paste contents of clipboard at insertion cursor
238 XtCallActionProc(M_text(editor), "paste-clipboard", event, NULL, 0);
240 XtFree( (char *) event );
249 * SetUndoDeletionState maintains the contents of editStuff.undo related
250 * to deletion (the deleted text & its original starting position).
252 * SetUndoDeletionState can also reset/invalidate the undo contents related to
253 * insertion if it detects a "new" deletion. The idea is to treat consecutive
254 * deletions as atomic from the viewpoint of undo. A delete is
255 * non-consecutive if it's start or end position is not coincidental with
256 * the last deletion. One set of consecutive insertions is allowed following
257 * deletions, and will be undone by the DtEditorUndo(). Non-consecutive
258 * insertions will reset/invalidate the deletion undo buffer.
261 SetUndoDeletionState(
262 DtEditorWidget pPriv,
263 XmTextVerifyCallbackStruct *cb)
268 * Get the text which will be deleted from the text widget.
270 pDeletedText = (char *)_XmStringSourceGetString(
271 (XmTextWidget) M_text(pPriv),
276 if( M_deletedText(pPriv) != (char *)NULL &&
277 M_insertionLength(pPriv) == 0 &&
278 (cb->startPos == M_deletionStart(pPriv) ||
279 cb->endPos == M_deletionStart(pPriv))
283 * Continuation of the current deletion. For a continuation, there
284 * must have been no intervening insertions, and we must be deleting
285 * from the same point, either forward or backward.
287 char *oldUndo = M_deletedText(pPriv);
288 M_deletedText(pPriv) = XtMalloc( strlen(M_deletedText(pPriv)) +
289 strlen(pDeletedText) + 1 );
291 if(cb->startPos == M_deletionStart(pPriv)) {
293 * deleting forward - deletionStart remains the same.
295 strcpy(M_deletedText(pPriv), oldUndo);
296 strcat(M_deletedText(pPriv), pDeletedText);
300 * deleting backward (e.g. Backspace)
302 strcpy(M_deletedText(pPriv), pDeletedText);
303 strcat(M_deletedText(pPriv), oldUndo);
304 M_deletionStart(pPriv) = cb->startPos;
306 if(oldUndo != (char *)NULL)
312 * Starting a new deletion context. Replace the old deletion
313 * context, and remove the insertion context.
315 _DtEditorResetUndo( pPriv );
317 M_deletedText(pPriv) = XtMalloc(strlen(pDeletedText) + 1);
319 strcpy(M_deletedText(pPriv), pDeletedText);
320 M_deletionStart(pPriv) = cb->startPos;
321 M_insertStart(pPriv) = cb->startPos;
322 M_insertionLength(pPriv) = 0;
325 if( pDeletedText != (char *)NULL )
326 XtFree( pDeletedText );
327 } /* SetUndoDeletionState */
330 * SetUndoInsertionState maintains the contents of editStuff.undo related
331 * to insertions (the number of characters inserted & the position of the
335 SetUndoInsertionState(
336 DtEditorWidget pPriv,
337 XmTextVerifyCallbackStruct *cb)
339 if(M_insertionLength(pPriv) == 0) {
341 * We've started a new deletion context, so reset the insertion
344 M_insertStart(pPriv) = cb->startPos;
345 M_insertionLength(pPriv) = _DtEditor_CountCharacters(cb->text->ptr,
351 * Determine if we're continuing the current insertion context
352 * or beginning a new one.
354 if(cb->startPos == (M_insertStart(pPriv) + M_insertionLength(pPriv)))
355 M_insertionLength(pPriv) += _DtEditor_CountCharacters(
356 cb->text->ptr, cb->text->length);
360 * We're starting a new insertion context, so invalidate any
361 * existing deletion context, and reset the insertion context.
363 _DtEditorResetUndo( pPriv );
364 M_insertStart(pPriv) = cb->startPos;
365 M_insertionLength(pPriv) = _DtEditor_CountCharacters(
366 cb->text->ptr, cb->text->length);
369 } /* SetUndoInsertionState */
372 /************************************************************************
374 * _DtEditorModifyVerifyCB - The modify/verify callback
376 * The modify verify callback handles incoming data and the data which
377 * will be replaced. The replaced data is saved (for later undos).
380 * widget - the text widget
381 * client_data - the edit area widget
382 * call_data - callback structure
384 ************************************************************************/
388 _DtEditorModifyVerifyCB(
393 register XmTextVerifyCallbackStruct * cb =
394 (XmTextVerifyCallbackStruct *) call_data;
395 DtEditorWidget editor = (DtEditorWidget) client_data;
398 * Loading all new data so no need to set up the data for later undos
400 if (M_loadingAllNewData(editor) == True)
402 _DtEditorResetUndo( editor );
403 M_unreadChanges(editor) = False;
404 M_loadingAllNewData(editor) = False;
410 * Adding additional data, rather than replacing all of the contents.
412 * Mark that the contents have been modified since the last time the
413 * application requested a copy.
415 M_unreadChanges(editor) = True;
418 * First, account for any data which will be removed by the new data.
419 * If text is being deleted, then grab a copy for later undo's.
421 if(cb->endPos > cb->startPos)
422 SetUndoDeletionState(editor, cb);
425 * If text is being inserted, then change the undo insertion state.
427 if(cb->text->length > 0)
428 SetUndoInsertionState(editor, cb);
432 } /* end ModifyVerifyCB */