EditGroupImpl.mesa; written by Bill Paxton, July 1983
edited by Bill Paxton, July 21, 1983 4:00 pm
DIRECTORY
EditGroup,
EditNotify,
NodeProps,
Rope,
UndoEvent,
TextEdit,
TreeSlice,
TiogaLooks,
TiogaNode,
TiogaNodeOps,
TiogaTreeOps;
EditGroupImpl: CEDAR PROGRAM
IMPORTS NodeProps, TextEdit, TiogaNodeOps, TiogaTreeOps, UndoEvent, TreeSlice, EditNotify
EXPORTS EditGroup
SHARES TiogaNode =
BEGIN OPEN EditGroup;
DeleteGroup: PUBLIC PROC [
root: RefBranchNode, start, end: Ref, saveForPaste: BOOLEANTRUE, event: Event ← NIL] = {
ReplaceGroup: PUBLIC PROC [
destRoot, sourceRoot: RefBranchNode, destStart, destEnd: Ref,
sourceStart, sourceEnd: Ref, saveForPaste: BOOLEANTRUE, event: Event ← NIL] = {
Copies the source group after the dest group and then deletes the dest group.
Takes care of overlap between source and dest.
CopyGroup: PUBLIC PROC [
destRoot, sourceRoot: RefBranchNode, dest: Ref, contents: BOOL,
sourceStart, sourceEnd: Ref, event: Event ← NIL] = {
If contents is true, copy the group to start of the contents list of dest.
Otherwise, copy the group to immediately after dest.
MoveGroup: PUBLIC PROC [
destRoot, sourceRoot: RefBranchNode, dest: Ref, contents: BOOL,
sourceStart, sourceEnd: Ref, event: Event ← NIL] = {
If contents is true, move the group to start of the contents list of dest.
Otherwise, move the group to immediately after dest.
IF sourceEnd # sibling* of sourceStart THEN ERROR;
sourceParent ← TiogaTreeOps.Parent[sourceEnd];
IF (beforeSource ← TiogaTreeOps.Previous[sourceStart, sourceParent])=NIL THEN beforeSource ← sourceParent;
afterSource ← TiogaTreeOps.Next[sourceEnd];
IF contents THEN { IF TiogaTreeOps.Contents[dest]=sourceStart THEN RETURN } -- already in position
ELSE IF dest=beforeSource THEN RETURN; -- already in position
IF dest # NIL AND dest in [sourceStart..LastWithin[sourceEnd]] THEN ERROR cannot; -- dest inside source
IF ~contents AND (TiogaNodeOps.IsBranch[dest]#TiogaNodeOps.IsBranch[sourceStart]) THEN
ERROR cannot; -- cannot mix branch and nonbranch
IF contents AND TiogaNodeOps.IsBranch[dest] AND TiogaNodeOps.IsBasic[sourceStart]) THEN ERROR cannot;
IF contents AND (TiogaNodeOps.IsBasic[dest] OR TiogaNodeOps.IsText[dest]) THEN ERROR cannot;
IF dest=NIL THEN -- moving to limbo -- { dest ← create list node as dest; contents ← TRUE };
beforeLoc ← [TiogaTreeOps.StepBackwardNode[sourceStart].back,0];
afterLoc ← [TiogaTreeOps.StepForwardNode[TiogaTreeOps.LastWithin[sourceEnd]],0];
notify ← NEW[MovingGroup Change ← [MovingGroup[
destRoot,sourceRoot,dest,sourceStart,sourceEnd,beforeSource,(beforeSource=sourceParent)]]];
IF beforeSource=NIL THEN { notify.from ← sourceParent; notify.contents ← TRUE };
Notify[notify, before];
First remove the source from its old location.
IF beforeSource=sourceParent THEN { -- moving the initial part of the contents/children list
WITH sourceParent SELECT FROM
br: RefBranchNode => {
IF sourceStart=br.child THEN -- moving children rather than contents
IF sourceEnd.last THEN br.child ← NIL -- moving all the children
ELSE { -- leaving some of the children
nxt: RefBranchNode = TiogaNodeOps.NarrowToBranchNode[sourceEnd.next];
IF nxt=NIL THEN ERROR;
br.child ← nxt }
ELSE IF sourceStart=br.contents THEN -- moving contents rather than children
IF sourceEnd.last THEN br.contents ← NIL -- moving all the contents
ELSE { -- leaving some of the contents
nxt: RefItemNode = TiogaNodeOps.NarrowToItemNode[sourceEnd.next];
IF nxt=NIL THEN ERROR;
br.contents ← nxt }
ELSE ERROR };
bx: RefBoxNode => bx.contents ← afterSource;
ls: RefListNode => ls.contents ← afterSource;
ENDCASE => ERROR }
ELSE { -- not moving the initial part of the contents list
beforeSource.next ← sourceEnd.next;
beforeSource.last ← sourceEnd.last };
Now insert source in its new location.
IF contents THEN { -- it moves to front of contents/children of dest
WITH dest SELECT FROM
br: RefBranchNode => {
WITH sourceStart SELECT FROM
br1: RefBranchNode => { -- insert as children rather than contents
IF br.child=NIL THEN { sourceEnd.next ← br; sourceEnd.last ← TRUE }
ELSE { sourceEnd.next ← br.child; sourceEnd.last ← FALSE };
br.child ← br1 };
itm: RefItemNode => { -- insert as contents rather than as children
IF br.contents=NIL THEN { sourceEnd.next ← br; sourceEnd.last ← TRUE }
ELSE { sourceEnd.next ← br.contents; sourceEnd.last ← FALSE };
br.contents ← itm };
ENDCASE => ERROR };
bx: RefBoxNode => {
IF bx.contents=NIL THEN { sourceEnd.next ← bx; sourceEnd.last ← TRUE }
ELSE { sourceEnd.next ← bx.contents; sourceEnd.last ← FALSE };
bx.contents ← sourceStart };
ls: RefListNode =>
IF ls.contents=NIL THEN { sourceEnd.next ← ls; sourceEnd.last ← TRUE }
ELSE { sourceEnd.next ← ls.contents; sourceEnd.last ← FALSE };
ls.contents ← sourceStart };
ENDCASE => ERROR }
ELSE { -- moving to after dest as sibling
sourceEnd.next ← dest.next; sourceEnd.last ← dest.last;
dest.next ← sourceStart; dest.last ← FALSE };
Notify[notify, after];
UndoEvent.Note[event, UndoMoveGroup, notify] };
afterMoved2 ← afterMoved1; -- save previous hint
afterMoved1 ← IF afterLoc.node # NIL THEN afterLoc ELSE beforeLoc; -- hint for repaint
};
UndoMoveGroup: PROC [undoRef: REF, currentEvent: Event] = TRUSTED {
saved: REF Change ← NARROW[undoRef];
WITH x:saved SELECT FROM
MovingGroup => {
[] ← MoveGroup[x.sourceRoot, x.destRoot,
x.from, x.contents, x.sourceStart, x.sourceEnd, currentEvent] };
ENDCASE => ERROR };
MoveGroupOnto: PUBLIC PROC [
destRoot, sourceRoot: RefBranchNode, destStart, destEnd: Ref,
sourceStart, sourceEnd: Ref, saveForPaste: BOOLEANTRUE, event: Event ← NIL] = {
Moves the source group after the dest group and then deletes the dest group.
Takes care of overlap between source and dest.
TransposeGroups: PUBLIC PROC [
alphaRoot, betaRoot: RefBranchNode, alphaStart, alphaEnd: Ref,
betaStart, betaEnd: Ref, event: Event ← NIL] = {
Transposes the alpha group and the beta group.
Takes care of overlap between alpha and beta.
END...