Skip to content

Commit

Permalink
implemented undo support for typing.
Browse files Browse the repository at this point in the history
  • Loading branch information
odrobnik committed Dec 17, 2012
1 parent ed8bb14 commit 4c69ebd
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 125 deletions.
23 changes: 15 additions & 8 deletions Core/Source/DTRichTextEditorContentView.h
Expand Up @@ -8,17 +8,24 @@

#import "DTAttributedTextContentView.h"



/**
This class acts as the content view of DTRichTextEditorView which is a scroll view.
It is a subclass of DTAttributedTextContentView and adds mutability of the text and incremental layouting.
*/
@interface DTRichTextEditorContentView : DTAttributedTextContentView
{
BOOL _needsRemoveObsoleteAttachmentViews;
}

/**
Recalculates the layout for the paragraphs covered by the given range.
@param range The string strange to relayout.
*/
- (void)relayoutTextInRange:(NSRange)range;
- (void)replaceTextInRange:(NSRange)range withText:(NSAttributedString *)text;

// removes attachments after next layout
@property (nonatomic) BOOL needsRemoveObsoleteAttachmentViews;
/**
Replaces the attributed text in the given range.
@param range The string range to replace
@param text The replacement text
*/
- (void)replaceTextInRange:(NSRange)range withText:(NSAttributedString *)text;

@end
86 changes: 40 additions & 46 deletions Core/Source/DTRichTextEditorContentView.m
Expand Up @@ -24,38 +24,37 @@ - (void)removeAttachmentCustomViewsNoLongerInLayoutFrame;


@implementation DTRichTextEditorContentView
{
NSUndoManager *_undoManager;
}

- (void)relayoutText
{
//SYNCHRONIZE_START(self.selfLock)
// Make sure we actually have a superview before attempting to relayout the text.
if (self.superview)
{
// Make sure we actually have a superview before attempting to relayout the text.
if (self.superview)
// update the layout
//[(DTMutableCoreTextLayoutFrame*)self.layoutFrame relayoutText];

// remove all links because they might have merged or split
[self removeAllCustomViewsForLinks];

if (_attributedString)
{
// update the layout
//[(DTMutableCoreTextLayoutFrame*)self.layoutFrame relayoutText];

// remove all links because they might have merged or split
[self removeAllCustomViewsForLinks];
// triggers new layout
[self sizeToFit];
// CGSize neededSize = [self sizeThatFits:self.bounds.size];

if (_attributedString)
{
// triggers new layout
[self sizeToFit];
// CGSize neededSize = [self sizeThatFits:self.bounds.size];

// set frame to fit text preserving origin
// call super to avoid endless loop
// [self willChangeValueForKey:@"frame"];
// super.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, neededSize.width, neededSize.height);
// [self didChangeValueForKey:@"frame"];
}

[self setNeedsDisplay];
[self setNeedsLayout];
// set frame to fit text preserving origin
// call super to avoid endless loop
// [self willChangeValueForKey:@"frame"];
// super.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, neededSize.width, neededSize.height);
// [self didChangeValueForKey:@"frame"];
}

[self setNeedsDisplay];
[self setNeedsLayout];
}
//SYNCHRONIZE_END(self.selfLock)
}


Expand Down Expand Up @@ -97,6 +96,9 @@ - (void)setAttributedString:(NSAttributedString *)attributedString

_attributedString = layoutFrame.attributedStringFragment;

// remove old actions from the undo manager
[self.undoManager removeAllActions];

// new layout invalidates all positions for custom views
[self removeAllCustomViews];

Expand All @@ -111,16 +113,6 @@ - (void)setAttributedString:(NSAttributedString *)attributedString
}
}

- (void)layoutSubviews
{
if (_needsRemoveObsoleteAttachmentViews)
{
_needsRemoveObsoleteAttachmentViews = NO;
}

[super layoutSubviews];
}

- (void)setFrame:(CGRect)frame
{
[self willChangeValueForKey:@"frame"];
Expand All @@ -142,9 +134,6 @@ - (void)relayoutTextInRange:(NSRange)range
{
[layoutFrame relayoutTextInRange:range];

// remove attachment custom views that are no longer needed
[self setNeedsRemoveObsoleteAttachmentViews:YES];

// remove all link custom views
[self removeAllCustomViewsForLinks];
}
Expand All @@ -154,9 +143,9 @@ - (void)relayoutTextInRange:(NSRange)range
[self setNeedsDisplay];

// size might have changed
layoutFrame.shouldRebuildLines = NO;
layoutFrame.shouldRebuildLines = NO;
[self sizeToFit];
layoutFrame.shouldRebuildLines = YES;
layoutFrame.shouldRebuildLines = YES;
}

- (void)replaceTextInRange:(NSRange)range withText:(NSAttributedString *)text
Expand All @@ -167,9 +156,6 @@ - (void)replaceTextInRange:(NSRange)range withText:(NSAttributedString *)text
{
[layoutFrame replaceTextInRange:range withText:text];

// remove attachment custom views that are no longer needed
[self setNeedsRemoveObsoleteAttachmentViews:YES];

// remove all link custom views
[self removeAllCustomViewsForLinks];
}
Expand All @@ -179,9 +165,9 @@ - (void)replaceTextInRange:(NSRange)range withText:(NSAttributedString *)text
[self setNeedsDisplay];

// size might have changed
layoutFrame.shouldRebuildLines = NO;
layoutFrame.shouldRebuildLines = NO;
[self sizeToFit];
layoutFrame.shouldRebuildLines = YES;
layoutFrame.shouldRebuildLines = YES;
}

- (void)removeAttachmentCustomViewsNoLongerInLayoutFrame
Expand Down Expand Up @@ -215,8 +201,16 @@ - (void)removeAttachmentCustomViewsNoLongerInLayoutFrame

}

#pragma mark Properties
#pragma mark UIResponder

@synthesize needsRemoveObsoleteAttachmentViews = _needsRemoveObsoleteAttachmentViews;
- (NSUndoManager *)undoManager
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_undoManager = [[NSUndoManager alloc] init];
});

return _undoManager;
}

@end
73 changes: 9 additions & 64 deletions Core/Source/DTRichTextEditorView.h
Expand Up @@ -31,72 +31,17 @@ typedef enum
DTDragModeCursorInsideMarking
} DTDragMode;

/**
DTRichTextEditorView is a subclass of UIScrollView and offers rich text edtiting capabilities. It has a single content view of type DTRichTextEditorContentView which is repsonsible for displaying the rich text.
*/


@interface DTRichTextEditorView : DTAttributedTextView <UITextInputTraits, UITextInput, DTAttributedTextContentViewDelegate, UIGestureRecognizerDelegate>
{
// customization options available as properties
BOOL _editable;
BOOL _replaceParagraphsWithLineFeeds;
BOOL _canInteractWithPasteboard;

UIView *_inputView;
UIView *_inputAccessoryView;

// private stuff
// NSMutableAttributedString *_internalAttributedText;

id<UITextInputTokenizer> tokenizer;
__unsafe_unretained id<UITextInputDelegate> inputDelegate;
NSDictionary *markedTextStyle;

DTTextRange *_selectedTextRange;
DTTextRange *_markedTextRange;

UITextStorageDirection _selectionAffinity;

// UITextInputTraits
UITextAutocapitalizationType autocapitalizationType; // default is UITextAutocapitalizationTypeSentences
UITextAutocorrectionType autocorrectionType; // default is UITextAutocorrectionTypeDefault
BOOL enablesReturnKeyAutomatically; // default is NO
UIKeyboardAppearance keyboardAppearance; // default is UIKeyboardAppearanceDefault
UIKeyboardType keyboardType; // default is UIKeyboardTypeDefault
UIReturnKeyType returnKeyType; // default is UIReturnKeyDefault (See note under UIReturnKeyType enum)
BOOL secureTextEntry; // default is NO

// not enabled, that's new as of iOS5
// UITextSpellCheckingType spellCheckingType;

DTCursorView *_cursor;
DTTextSelectionView *_selectionView;


DTDragMode _dragMode;
BOOL _shouldReshowContextMenuAfterHide;
BOOL _shouldShowContextMenuAfterLoupeHide;
BOOL _shouldShowContextMenuAfterMovementEnded;

BOOL _showsKeyboardWhenBecomingFirstResponder;
BOOL _keyboardIsShowing;

CGPoint _dragCursorStartMidPoint;
CGPoint _touchDownPoint;
NSDictionary *_overrideInsertionAttributes;

UITapGestureRecognizer *tapGesture;
UITapGestureRecognizer *doubleTapGesture;
UILongPressGestureRecognizer *longPressGesture;
UIPanGestureRecognizer *panGesture;

BOOL _contextMenuVisible;
NSTimeInterval _lastCursorMovementTimestamp;

// overrides
CGSize _maxImageDisplaySize;
NSString *_defaultFontFamily;
NSURL *_baseURL;
CGFloat _textSizeMultiplier;
}

@interface DTRichTextEditorView : DTAttributedTextView <UITextInputTraits, UITextInput>

@property(nonatomic,getter=isEditable) BOOL editable;
@property(nonatomic, assign) BOOL replaceParagraphsWithLineFeeds;
Expand Down

0 comments on commit 4c69ebd

Please sign in to comment.