/*
   NSTextStorage.h

   Copyright (C) 1996,1999 Free Software Foundation, Inc.

   Author:  Daniel Bðhringer <boehring@biomed.ruhr-uni-bochum.de>
   Date: August 1998
   Source by Daniel Bðhringer integrated into GNUstep gui
   by Felipe A. Rodriguez <far@ix.netcom.com> 
   Update: Richard Frith-Macdonald <richard@brainstorm.co.uk>

   Documentation written from scratch by: Nicola Pero
   <nicola@brainstorm.co.uk>
   
   This file is part of the GNUstep GUI Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.  */

#ifndef _GNUstep_H_NSTextStorage
#define _GNUstep_H_NSTextStorage

#include <AppKit/NSStringDrawing.h>
#include <AppKit/AppKitDefines.h>

@class GSLayoutManager;

/*
 * When edit:range:changeInLength: is called, it takes a mask saying
 * what has been edited.  The mask is NSTextStorageEditedAttributes
 * if the attributes have been changed, NSTextStorageEditedCharacters
 * if the characters have been changed, and 
 * NSTextStorageEditedAttributes | NSTextStorageEditedCharacters if both
 * characters and attributes were edited.
 */
enum
{
  NSTextStorageEditedAttributes = 1,
  NSTextStorageEditedCharacters = 2
};

/* 
 * The NSTextStorage 
 */
@interface NSTextStorage : NSMutableAttributedString
{
  NSRange		_editedRange;
  int			_editedDelta;
  NSMutableArray	*_layoutManagers;
  id			_delegate;
  unsigned		_editedMask;
  unsigned		_editCount;
}

- (void) addLayoutManager: (GSLayoutManager*)obj;
- (void) removeLayoutManager: (GSLayoutManager*)obj;
- (NSArray*) layoutManagers;

/*
 * This method is normally called between a beginEditing and an
 * endEditing message to record any changes which were made to the
 * receiver.  It is automatically called by the NSTextStorage
 * primitives, so in other words, NSTextStorage calls it for you, and
 * you don't normally need to call this method.  You might (a more
 * theoretical than practical option) need to subclass it and override
 * this method to take into account changes done.
 *
 * If the method is called outside a beginEditing/endEditing calls, it
 * calls processEditing immediately.  As far as I understand, that would
 * happen if you modify the NSTextStorage without enclosing your changes
 * inside a beginEditing/endEditing calls.
 *
 * maks can be NSTextStorageEditedAttributes or
 * NSTextStorageEditedCharacters, or and | of the two.
 *
 * the old range is the range affected by the change in the string ... in the
 * original string.
 *
 * the changeInLength is, well, positive if you added characters, negative
 * if you removed characters.  */
- (void) edited: (unsigned)mask range: (NSRange)old changeInLength: (int)delta;

/*
 * This method is called to process the editing once it's finished.
 * Normally it is called by endEditing; but if you modify the NSTextStorage
 * without enclosing the modifications into a beginEditing/endEditing pair,
 * this method will be called directly by edited:range:changeInLength:.
 * 
 * But in practice, what does this method do ?  Well, it posts the
 * NSTextStorageWillProcessEditing notification.  Then, it calls
 * fixAttributesAfterEditingRange:.  Then, it posts the
 * NSTextStorageDidProcessEditing notification.  Finally, it tells the
 * layout manager(s) about this change in the text storage by calling
 * textStorage:edited:range:changeInLength:invalidatedRange:.  */
- (void) processEditing;

/*
 * Start a set of changes to the text storage.  All the changes are
 * recorded and merged - without any layout to be done.  When you call
 * endEditing, the layout will be done in one single operation.
 *
 * In practice, you should call beginEditing before starting to modify
 * the NSTextStorage.  When you are finished modifying it and you want
 * your changes to be propagated to the layout manager(s), you call
 * endEditing.
 *
 * If you don't enclose your changes into a beginEditing/endEditing pair,
 * it still works, but it's less efficient.
 */
- (void) beginEditing;

/* 
 * End a set of changes, and calls processEditing.
 */
- (void) endEditing;

/*
 * The delegate can use the following methods when it receives a
 * notification that a change was made.  The methods tell him what
 * kind of change was made.  */
- (unsigned) editedMask;
- (NSRange) editedRange;
- (int) changeInLength;

- (void) setDelegate: (id)delegate;
- (id) delegate;

#ifndef	STRICT_OPENSTEP
- (void) ensureAttributesAreFixedInRange: (NSRange)range;
- (BOOL) fixesAttributesLazily;
- (void) invalidateAttributesInRange: (NSRange)range;
#endif

@end


/****  NSTextStorage delegate methods ****/

@interface NSObject (NSTextStorageDelegate)

/*
 * The delegate is automatically registered to receive the
 * NSTextStorageWillProcessEditingNotification, and the
 * NSTextStorageDidProcessEditingNotification via these methods, so
 * once the notifications are sent, these methods of the delegate will
 * be invokes.  In these methods the delegate can use editedMask,
 * editedRange, changeInLength to figure out what the actual change
 * is.
 */
- (void) textStorageWillProcessEditing: (NSNotification*)notification;
- (void) textStorageDidProcessEditing: (NSNotification*)notification;

@end

/**** Notifications ****/

/* The object of the notification is the NSTextStorage itself.  */
APPKIT_EXPORT NSString *NSTextStorageWillProcessEditingNotification;
APPKIT_EXPORT NSString *NSTextStorageDidProcessEditingNotification;

#endif
