1 /*****************************************************************************
2 * VLCDebugMessageWindowController.m: Mac OS X interface crash reporter
3 *****************************************************************************
4 * Copyright (C) 2004-2013 VLC authors and VideoLAN
7 * Authors: Felix Paul Kühne <fkuehne at videolan dot org>
8 * Pierre d'Herbemont <pdherbemont # videolan org>
9 * Derk-Jan Hartman <hartman at videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 #import "VLCDebugMessageWindowController.h"
28 #import <vlc_common.h>
30 static void MsgCallback(void *data, int type, const vlc_log_t *item, const char *format, va_list ap);
32 /*****************************************************************************
33 * MsgCallback: Callback triggered by the core once a new debug message is
34 * ready to be displayed. We store everything in a NSArray in our Cocoa part
36 *****************************************************************************/
38 @interface VLCDebugMessageWindowController () <NSWindowDelegate>
40 NSMutableArray * _messageArray;
42 - (void)appendMessage:(NSMutableAttributedString *) message;
46 static void MsgCallback(void *data, int type, const vlc_log_t *item, const char *format, va_list ap)
50 VLCDebugMessageWindowController *visualizer = (__bridge VLCDebugMessageWindowController*)data;
52 int canc = vlc_savecancel();
54 if (vasprintf(&str, format, ap) == -1) {
55 vlc_restorecancel(canc);
59 if (!item->psz_module)
64 NSColor *_white = [NSColor whiteColor];
65 NSColor *_red = [NSColor redColor];
66 NSColor *_yellow = [NSColor yellowColor];
67 NSColor *_gray = [NSColor grayColor];
69 NSColor * pp_color[4] = { _white, _red, _yellow, _gray };
70 static const char * ppsz_type[4] = { ": ", " error: ", " warning: ", " debug: " };
73 NSString *firstString = [NSString stringWithFormat:@"%s%s", item->psz_module, ppsz_type[type]];
74 NSString *secondString = [NSString stringWithFormat:@"%@%s\n", firstString, str];
76 NSDictionary *colorAttrib = [NSDictionary dictionaryWithObject: pp_color[type] forKey: NSForegroundColorAttributeName];
77 NSMutableAttributedString *coloredMsg = [[NSMutableAttributedString alloc] initWithString: secondString attributes: colorAttrib];
78 colorAttrib = [NSDictionary dictionaryWithObject: pp_color[3] forKey: NSForegroundColorAttributeName];
79 [coloredMsg setAttributes: colorAttrib range: NSMakeRange(0, [firstString length])];
81 [visualizer performSelectorOnMainThread:@selector(appendMessage:) withObject:coloredMsg waitUntilDone:NO];
83 vlc_restorecancel(canc);
88 @implementation VLCDebugMessageWindowController
92 self = [super initWithWindowNibName:@"DebugMessageVisualizer"];
94 _messageArray = [NSMutableArray arrayWithCapacity:600];
101 vlc_LogSet( getIntf()->obj.libvlc, NULL, NULL );
104 - (void)windowDidLoad
106 [self.window setExcludedFromWindowsMenu: YES];
107 [self.window setDelegate: self];
108 [self.window setTitle: _NS("Messages")];
109 [_saveButton setTitle: _NS("Save this Log...")];
110 [_clearButton setTitle:_NS("Clear")];
111 [_refreshButton setImage: [NSImage imageNamed: NSImageNameRefreshTemplate]];
114 #pragma mark - UI interaction
116 - (void)showWindow:(id)sender
118 /* subscribe to LibVLCCore's messages */
119 vlc_LogSet(getIntf()->obj.libvlc, MsgCallback, (__bridge void*)self);
121 [super showWindow:sender];
124 - (IBAction)updateMessagesPanel:(id)sender
126 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidBecomeKeyNotification object:self.window];
129 - (void)windowDidBecomeKey:(NSNotification *)notification
131 [_messageTable reloadData];
132 [_messageTable scrollRowToVisible: [_messageArray count] - 1];
135 - (void)windowWillClose:(NSNotification *)notification
137 /* unsubscribe from LibVLCCore's messages */
138 vlc_LogSet( getIntf()->obj.libvlc, NULL, NULL );
139 [_messageArray removeAllObjects];
142 - (IBAction)saveDebugLog:(id)sender
144 NSSavePanel * saveFolderPanel = [[NSSavePanel alloc] init];
146 [saveFolderPanel setCanSelectHiddenExtension: NO];
147 [saveFolderPanel setCanCreateDirectories: YES];
148 [saveFolderPanel setAllowedFileTypes: [NSArray arrayWithObject:@"txt"]];
149 [saveFolderPanel setNameFieldStringValue:[NSString stringWithFormat: _NS("VLC Debug Log (%s).txt"), VERSION_MESSAGE]];
150 [saveFolderPanel beginSheetModalForWindow: self.window completionHandler:^(NSInteger returnCode) {
151 if (returnCode == NSOKButton) {
152 NSUInteger count = [_messageArray count];
153 NSMutableString *string = [[NSMutableString alloc] init];
154 for (NSUInteger i = 0; i < count; i++)
155 [string appendString: [[_messageArray objectAtIndex:i] string]];
157 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
158 if ([data writeToFile: [[saveFolderPanel URL] path] atomically: YES] == NO)
159 msg_Warn(getIntf(), "Error while saving the debug log");
164 - (IBAction)clearLog:(id)sender
166 [_messageArray removeAllObjects];
168 // Reregister handler, to write new header to log
169 vlc_LogSet(getIntf()->obj.libvlc, NULL, NULL);
170 vlc_LogSet(getIntf()->obj.libvlc, MsgCallback, (__bridge void*)self);
172 [_messageTable reloadData];
175 #pragma mark - data handling
177 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
179 return [_messageArray count];
182 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
184 return [_messageArray objectAtIndex:rowIndex];
187 - (void)appendMessage:(NSMutableAttributedString *) message
189 if ([_messageArray count] > 1000000) {
190 [_messageArray removeObjectAtIndex: 0];
191 [_messageArray removeObjectAtIndex: 1];
194 [_messageArray addObject:message];