diff --git a/Classes/Headers/TVCLogController.h b/Classes/Headers/TVCLogController.h index 6d66ce7ac5..efc6be98e6 100755 --- a/Classes/Headers/TVCLogController.h +++ b/Classes/Headers/TVCLogController.h @@ -37,10 +37,9 @@ #import "TextualApplication.h" -typedef BOOL (^TVCLogMessageBlock)(void); +typedef id (^TVCLogMessageBlock)(void); @interface TVCLogController : NSObject -@property (nonatomic, strong) NSString *html; @property (nonatomic, weak) IRCWorld *world; @property (nonatomic, weak) IRCClient *client; @property (nonatomic, weak) IRCChannel *channel; @@ -69,7 +68,8 @@ typedef BOOL (^TVCLogMessageBlock)(void); @property (nonatomic, assign) NSInteger lastVisitedHighlight; @property (nonatomic, strong) NSMutableArray *highlightedLineNumbers; -@property (strong) NSMutableArray *messageQueue; +@property (strong) NSMutableArray *normalMessageQueue; // Priority: Low +@property (strong) NSMutableArray *specialMessageQueue; // Priority: High @property (assign) BOOL queueInProgress; - (void)setUp; @@ -93,8 +93,9 @@ typedef BOOL (^TVCLogMessageBlock)(void); - (void)unmark; - (void)goToMark; +- (void)clear TEXTUAL_DEPRECATED; // See IRCWorld.h for replacements. + - (void)reloadTheme; -- (void)clear; - (void)changeTextSize:(BOOL)bigger; diff --git a/Classes/IRC/IRCWorld.m b/Classes/IRC/IRCWorld.m index 198e4a2473..f2da32b8d8 100755 --- a/Classes/IRC/IRCWorld.m +++ b/Classes/IRC/IRCWorld.m @@ -156,7 +156,9 @@ - (void)setChannelMenuItem:(NSMenuItem *)item - (void)fireMessageQueue:(TVCLogController *)log { - if (log.messageQueue.count >= 25) { + if (log.normalMessageQueue.count >= 25 || + log.specialMessageQueue.count >= 25) { + static dispatch_once_t once; /* Not 100% sure dispatch_once is diff --git a/Classes/Views/Channel View/TVCLogController.m b/Classes/Views/Channel View/TVCLogController.m index 5ef9e6b7fc..e5326df877 100755 --- a/Classes/Views/Channel View/TVCLogController.m +++ b/Classes/Views/Channel View/TVCLogController.m @@ -50,8 +50,9 @@ - (id)init if ((self = [super init])) { self.bottom = YES; self.maxLines = 300; - - self.messageQueue = [NSMutableArray new]; + + self.normalMessageQueue = [NSMutableArray new]; + self.specialMessageQueue = [NSMutableArray new]; self.highlightedLineNumbers = [NSMutableArray new]; [[WebPreferences standardPreferences] setCacheModel:WebCacheModelDocumentViewer]; @@ -135,28 +136,97 @@ - (void)setUp - (void)runMessageQueueLoop { self.queueInProgress = YES; + + [self runMessageQueueLoop:self.specialMessageQueue honorLoopDelay:NO]; + [self runMessageQueueLoop:self.normalMessageQueue honorLoopDelay:YES]; + + self.queueInProgress = NO; +} + +- (void)runMessageQueueLoop:(NSMutableArray *)messageQueue honorLoopDelay:(BOOL)delayLoop +{ + NSMutableString *result; + + if (delayLoop == NO) { + result = [NSMutableString string]; + } - while (NSObjectIsNotEmpty(self.messageQueue)) { + while (NSObjectIsNotEmpty(messageQueue)) { dispatch_async(dispatch_get_main_queue(), ^{ - if ([self.view isLoading] == NO) { - if (NSObjectIsNotEmpty(self.messageQueue)) { - BOOL srslt = ((TVCLogMessageBlock)(self.messageQueue)[0])(); + if (NSObjectIsNotEmpty(messageQueue)) { + if ([self.view isLoading] == NO) { + // Internally, TVCLogMessageBlock should only return a + // BOOL as NSValue or NSString absolute value. + + BOOL rrslt = NO; + + // ---- // + + id stslt = ((TVCLogMessageBlock)messageQueue[0])(); + + // ---- // - if (srslt) { - [self.messageQueue removeObjectAtIndex:0]; + if ([stslt isKindOfClass:NSString.class]) { + if (PointerIsNotEmpty(stslt)) { + if (delayLoop == NO) { + [result appendString:stslt]; + } else { + [self appendToDocumentBody:stslt]; + } + + rrslt = YES; + } + } else { + rrslt = [stslt boolValue]; + } + + // ---- // + + if (rrslt) { + [messageQueue removeObjectAtIndex:0]; } } } }); - if (self.channel) { - [NSThread sleepForTimeInterval:[TPCPreferences viewLoopChannelDelay]]; - } else { - [NSThread sleepForTimeInterval:[TPCPreferences viewLoopConsoleDelay]]; + // ---- // + + if (delayLoop) { + if (self.channel) { + [NSThread sleepForTimeInterval:[TPCPreferences viewLoopChannelDelay]]; + } else { + [NSThread sleepForTimeInterval:[TPCPreferences viewLoopConsoleDelay]]; + } } } - self.queueInProgress = NO; + // ---- // + + if (delayLoop == NO && NSObjectIsNotEmpty(result)) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self appendToDocumentBody:result]; + }); + } +} + +#pragma mark - + +- (void)appendToDocumentBody:(NSString *)html +{ + DOMDocument *doc = [self mainFrameDocument]; + if (PointerIsEmpty(doc)) return; + + DOMElement *body = [self body:doc]; + if (PointerIsEmpty(body)) return; + + // ---- // + + DOMDocumentFragment *frag = [(id)doc createDocumentFragmentWithMarkupString:html + baseURL:self.theme.baseUrl]; + + // ---- // + + [body appendChild:frag]; } - (void)loadAlternateHTML:(NSString *)newHTML @@ -248,20 +318,20 @@ - (void)setTopic:(NSString *)topic resultInfo:NULL]; DOMDocument *doc = [self mainFrameDocument]; - if (PointerIsEmpty(doc)) return NO; + if (PointerIsEmpty(doc)) return @(NO); DOMElement *topic_body = [self topic:doc]; - if (PointerIsEmpty(topic_body)) return NO; + if (PointerIsEmpty(topic_body)) return @(NO); [(id)topic_body setInnerHTML:body]; [self executeScriptCommand:@"topicBarValueChanged" withArguments:@[topic]]; } - return YES; + return @(YES); } copy]; - - [self.messageQueue safeAddObject:messageBlock]; + + [self.normalMessageQueue safeAddObject:messageBlock]; [self.world runMessageQueueLoop:self]; } @@ -343,12 +413,12 @@ - (void)restorePosition - (void)mark { TVCLogMessageBlock (^messageBlock)(void) = [^{ - if (self.loaded == NO) return NO; + if (self.loaded == NO) return @(NO); [self savePosition]; DOMDocument *doc = [self mainFrameDocument]; - if (PointerIsEmpty(doc)) return NO; + if (PointerIsEmpty(doc)) return @(NO); DOMElement *body = [self body:doc]; @@ -366,10 +436,10 @@ - (void)mark [self executeScriptCommand:@"historyIndicatorAddedToView" withArguments:@[]]; - return YES; + return @(YES); } copy]; - [self.messageQueue safeAddObject:messageBlock]; + [self.normalMessageQueue safeAddObject:messageBlock]; [self.world runMessageQueueLoop:self]; } @@ -377,10 +447,10 @@ - (void)mark - (void)unmark { TVCLogMessageBlock (^messageBlock)(void) = [^{ - if (self.loaded == NO) return NO; + if (self.loaded == NO) return @(NO); DOMDocument *doc = [self mainFrameDocument]; - if (PointerIsEmpty(doc)) return NO; + if (PointerIsEmpty(doc)) return @(NO); DOMElement *e = [doc getElementById:@"mark"]; @@ -392,10 +462,10 @@ - (void)unmark [self executeScriptCommand:@"historyIndicatorRemovedFromView" withArguments:@[]]; - return YES; + return @(YES); } copy]; - [self.messageQueue safeAddObject:messageBlock]; + [self.normalMessageQueue safeAddObject:messageBlock]; [self.world runMessageQueueLoop:self]; } @@ -429,31 +499,31 @@ - (void)goToMark - (void)reloadTheme { - DOMDocument *doc = [self mainFrameDocument]; - if (PointerIsEmpty(doc)) return; - - DOMElement *body = [self body:doc]; - if (PointerIsEmpty(body)) return; + [self loadAlternateHTML:[self initialDocument:[self topicValue]]]; - self.html = [(id)body innerHTML]; + // ---- // + + NSDictionary *oldLines = self.logFile.data; - self.scrollBottom = [self viewingBottom]; - self.scrollTop = [[[doc body] valueForKey:@"scrollTop"] integerValue]; + if (NSObjectIsNotEmpty(oldLines)) { + NSArray *keys = oldLines.sortedDictionaryKeys; + + for (NSString *key in keys) { + NSDictionary *lineDic = [oldLines objectForKey:key]; - [self loadAlternateHTML:[self initialDocument:[self topicValue]]]; -} + TVCLogLine *line = [TVCLogLine.alloc initWithDictionary:lineDic]; -- (void)clear -{ - self.html = nil; - self.loaded = NO; - self.count = 0; + if (PointerIsNotEmpty(line)) { + BOOL rawHTML = (line.lineType == TVCLogLineRawHTMLType); + + [self print:line withHTML:rawHTML specialWrite:YES]; + } + } + } - [self.logFile reset]; + // ---- // - [self executeScriptCommand:@"viewContentsBeingCleared" withArguments:@[]]; - - [self loadAlternateHTML:[self initialDocument:[self topicValue]]]; + [self moveToBottom]; } - (void)changeTextSize:(BOOL)bigger @@ -660,7 +730,7 @@ - (NSString *)renderedBodyForTranscriptLog:(TVCLogLine *)line [s appendString:time]; } - + if (NSObjectIsNotEmpty(line.nick)) { NSString *nick = [line formattedNickname:self.channel]; @@ -679,7 +749,12 @@ - (BOOL)print:(TVCLogLine *)line return [self print:line withHTML:NO]; } -- (BOOL)print:(TVCLogLine *)line withHTML:(BOOL)rawHTML +- (BOOL)print:(TVCLogLine *)line withHTML:(BOOL)stripHTML +{ + return [self print:line withHTML:stripHTML specialWrite:NO]; +} + +- (BOOL)print:(TVCLogLine *)line withHTML:(BOOL)rawHTML specialWrite:(BOOL)isSpecial { if (NSObjectIsEmpty(line.body)) { return NO; @@ -801,7 +876,7 @@ - (BOOL)print:(TVCLogLine *)line withHTML:(BOOL)rawHTML // ---- // - if (line.nick) { + if (NSObjectIsNotEmpty(line.nick)) { attributes[@"isNicknameAvailable"] = @(YES); attributes[@"nicknameColorNumber"] = @(line.nickColorNumber); @@ -830,13 +905,13 @@ - (BOOL)print:(TVCLogLine *)line withHTML:(BOOL)rawHTML id templateRaw = [self.theme.other templateWithLineType:line.lineType]; - [self writeLine:templateRaw attributes:attributes contextInfo:line]; + [self writeLine:templateRaw attributes:attributes contextInfo:line specialWrite:isSpecial]; // ************************************************************************** / // Log highlight (if any). / // ************************************************************************** / - if (highlighted) { + if (highlighted && isSpecial == NO) { NSString *messageBody; NSString *nicknameBody = [line formattedNickname:self.channel]; @@ -856,7 +931,10 @@ - (BOOL)print:(TVCLogLine *)line withHTML:(BOOL)rawHTML return highlighted; } -- (void)writeLine:(id)line attributes:(NSMutableDictionary *)attrs contextInfo:(TVCLogLine *)context +- (void)writeLine:(id)line + attributes:(NSMutableDictionary *)attrs + contextInfo:(TVCLogLine *)context + specialWrite:(BOOL)isSpecial { TVCLogMessageBlock (^messageBlock)(void) = [^{ [self savePosition]; @@ -867,10 +945,10 @@ - (void)writeLine:(id)line attributes:(NSMutableDictionary *)attrs contextInfo:( // ---- // DOMDocument *doc = [self mainFrameDocument]; - if (PointerIsEmpty(doc)) return NO; + if (PointerIsEmpty(doc)) return nil; DOMElement *body = [self body:doc]; - if (PointerIsEmpty(body)) return NO; + if (PointerIsEmpty(body)) return nil; // ---- // @@ -879,43 +957,46 @@ - (void)writeLine:(id)line attributes:(NSMutableDictionary *)attrs contextInfo:( // ---- // - NSString *aHtml = [line renderObject:attrs]; + NSString *html = [line renderObject:attrs]; - if (NSObjectIsEmpty(aHtml)) { - return NO; + if (NSObjectIsEmpty(html)) { + return nil; } // ---- // - DOMDocumentFragment *frag = [(id)doc createDocumentFragmentWithMarkupString:aHtml - baseURL:self.theme.baseUrl]; - - [body appendChild:frag]; - } + if (self.maxLines > 0 && (self.count - 10) > self.maxLines) { + [self setNeedsLimitNumberOfLines]; + } - // ---- // - - if (self.maxLines > 0 && (self.count - 10) > self.maxLines) { - [self setNeedsLimitNumberOfLines]; - } - - if ([attrs[@"highlightAttributeRepresentation"] isEqualToString:@"true"]) { - [self.highlightedLineNumbers safeAddObject:@(self.lineNumber)]; - } - - [self executeScriptCommand:@"newMessagePostedToDisplay" withArguments:@[@(self.lineNumber)]]; + if ([attrs[@"highlightAttributeRepresentation"] isEqualToString:@"true"]) { + [self.highlightedLineNumbers safeAddObject:@(self.lineNumber)]; + } - // ---- // + [self executeScriptCommand:@"newMessagePostedToDisplay" withArguments:@[@(self.lineNumber)]]; - [self.logFile writePropertyListEntry:[context dictionaryValue] - toKey:[NSNumberWithInteger(self.lineNumber) integerWithLeadingZero:10]]; + // ---- // + if (isSpecial == NO) { + [self.logFile writePropertyListEntry:[context dictionaryValue] + toKey:[NSNumberWithInteger(self.lineNumber) integerWithLeadingZero:10]]; + } + + return (__bridge void *)html; + } + // ---- // - return YES; + return nil; } copy]; - - [self.messageQueue safeAddObject:messageBlock]; + + // ---- // + + if (isSpecial) { + [self.specialMessageQueue safeAddObject:messageBlock]; + } else { + [self.normalMessageQueue safeAddObject:messageBlock]; + } [self.world runMessageQueueLoop:self]; } @@ -933,8 +1014,6 @@ - (NSString *)initialDocument:(NSString *)topic templateTokens[@"activeStyleAbsolutePath"] = self.theme.other.path; templateTokens[@"applicationResourcePath"] = [TPCPreferences whereResourcePath]; - templateTokens[@"existingBody"] = NSStringNilValueSubstitute(self.html); - // ---- // if (self.channel) { @@ -1184,4 +1263,12 @@ - (void)logViewDidResize [self restorePosition]; } +#pragma mark - +#pragma mark Deprecated + +- (void)clear +{ + // ---- // +} + @end diff --git a/Resources/Info.plist b/Resources/Info.plist index 4b65bac6bb..829e711822 100755 --- a/Resources/Info.plist +++ b/Resources/Info.plist @@ -47,8 +47,8 @@ TXBundleBuildCodeName Turtle Soup TXBundleBuildNumber - 12269 + 12291 TXBundleBuildReference - 2.1.1-275-g410ffa5-debug + 2.1.1-276-g6e71f93-debug