1 /*****************************************************************************
2 * StringUtility.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2002-2012 VLC authors and VideoLAN
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Derk-Jan Hartman <hartman at videolan dot org>
10 * Felix Paul Kühne <fkuehne at videolan dot org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
29 #import "StringUtility.h"
32 @implementation VLCStringUtility
34 static VLCStringUtility *_o_sharedInstance = nil;
36 + (VLCStringUtility *)sharedInstance
38 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
43 if (_o_sharedInstance)
46 _o_sharedInstance = [super init];
48 return _o_sharedInstance;
52 #pragma mark String utility
54 - (NSString *)localizedString:(const char *)psz
56 NSString * o_str = nil;
59 o_str = [NSString stringWithCString: _(psz) encoding:NSUTF8StringEncoding];
62 msg_Err(VLCIntf, "could not translate: %s", psz);
66 msg_Warn(VLCIntf, "can't translate empty strings");
75 - (char *)delocalizeString:(NSString *)id
77 NSData * o_data = [id dataUsingEncoding: NSUTF8StringEncoding
78 allowLossyConversion: NO];
82 o_data = [id dataUsingEncoding: NSUTF8StringEncoding
83 allowLossyConversion: YES];
84 psz_string = malloc([o_data length] + 1);
85 [o_data getBytes: psz_string];
86 psz_string[ [o_data length] ] = '\0';
87 msg_Err(VLCIntf, "cannot convert to the requested encoding: %s",
90 psz_string = malloc([o_data length] + 1);
91 [o_data getBytes: psz_string];
92 psz_string[ [o_data length] ] = '\0';
98 /* i_width is in pixels */
99 - (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
101 NSMutableString *o_wrapped;
102 NSString *o_out_string;
103 NSRange glyphRange, effectiveRange, charRange;
104 NSRect lineFragmentRect;
105 unsigned glyphIndex, breaksInserted = 0;
107 NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
108 attributes: [NSDictionary dictionaryWithObjectsAndKeys:
109 [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
110 NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
111 NSTextContainer *o_container = [[NSTextContainer alloc]
112 initWithContainerSize: NSMakeSize(i_width, 2000)];
114 [o_layout_manager addTextContainer: o_container];
115 [o_container release];
116 [o_storage addLayoutManager: o_layout_manager];
117 [o_layout_manager release];
119 o_wrapped = [o_in_string mutableCopy];
120 glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
122 for (glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
123 glyphIndex += effectiveRange.length) {
124 lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
125 effectiveRange: &effectiveRange];
126 charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
127 actualGlyphRange: &effectiveRange];
128 if ([o_wrapped lineRangeForRange:
129 NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
130 [o_wrapped insertString: @"\n" atIndex: NSMaxRange(charRange) + breaksInserted];
134 o_out_string = [NSString stringWithString: o_wrapped];
141 - (NSString *)OSXStringKeyToString:(NSString *)theString
143 if (![theString isEqualToString:@""]) {
145 if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
146 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
148 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
149 theString = [NSString stringWithFormat:@"%@+", theString];
151 if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
152 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
154 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
155 theString = [NSString stringWithFormat:@"%@-", theString];
158 theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString: [NSString stringWithUTF8String: "\xE2\x8C\x98"]];
159 theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString: [NSString stringWithUTF8String: "\xE2\x8C\xA5"]];
160 theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString: [NSString stringWithUTF8String: "\xE2\x87\xA7"]];
161 theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString: [NSString stringWithUTF8String: "\xE2\x8C\x83"]];
162 /* show non-character keys correctly */
163 theString = [theString stringByReplacingOccurrencesOfString:@"Right" withString:[NSString stringWithUTF8String:"\xE2\x86\x92"]];
164 theString = [theString stringByReplacingOccurrencesOfString:@"Left" withString:[NSString stringWithUTF8String:"\xE2\x86\x90"]];
165 theString = [theString stringByReplacingOccurrencesOfString:@"Up" withString:[NSString stringWithUTF8String:"\xE2\x86\x91"]];
166 theString = [theString stringByReplacingOccurrencesOfString:@"Down" withString:[NSString stringWithUTF8String:"\xE2\x86\x93"]];
167 theString = [theString stringByReplacingOccurrencesOfString:@"Enter" withString:[NSString stringWithUTF8String:"\xe2\x86\xb5"]];
168 theString = [theString stringByReplacingOccurrencesOfString:@"Tab" withString:[NSString stringWithUTF8String:"\xe2\x87\xa5"]];
169 theString = [theString stringByReplacingOccurrencesOfString:@"Delete" withString:[NSString stringWithUTF8String:"\xe2\x8c\xab"]]; /* capitalize plain characters to suit the menubar's look */
170 theString = [theString capitalizedString];
173 theString = [NSString stringWithString:_NS("Not Set")];
177 - (NSString *)getCurrentTimeAsString:(input_thread_t *)p_input negative:(BOOL)b_negative
179 assert(p_input != nil);
182 char psz_time[MSTRTIME_MAX_SIZE];
184 var_Get(p_input, "time", &time);
186 mtime_t dur = input_item_GetDuration(input_GetItem(p_input));
187 if (b_negative && dur > 0) {
188 mtime_t remaining = 0;
189 if (dur > time.i_time)
190 remaining = dur - time.i_time;
191 return [NSString stringWithFormat: @"-%s", secstotimestr(psz_time, (remaining / 1000000))];
193 return [NSString stringWithUTF8String: secstotimestr(psz_time, (time.i_time / 1000000))];
197 #pragma mark Key Shortcuts
202 unsigned int i_vlckey;
203 } nskeys_to_vlckeys[] =
205 { NSUpArrowFunctionKey, KEY_UP },
206 { NSDownArrowFunctionKey, KEY_DOWN },
207 { NSLeftArrowFunctionKey, KEY_LEFT },
208 { NSRightArrowFunctionKey, KEY_RIGHT },
209 { NSF1FunctionKey, KEY_F1 },
210 { NSF2FunctionKey, KEY_F2 },
211 { NSF3FunctionKey, KEY_F3 },
212 { NSF4FunctionKey, KEY_F4 },
213 { NSF5FunctionKey, KEY_F5 },
214 { NSF6FunctionKey, KEY_F6 },
215 { NSF7FunctionKey, KEY_F7 },
216 { NSF8FunctionKey, KEY_F8 },
217 { NSF9FunctionKey, KEY_F9 },
218 { NSF10FunctionKey, KEY_F10 },
219 { NSF11FunctionKey, KEY_F11 },
220 { NSF12FunctionKey, KEY_F12 },
221 { NSInsertFunctionKey, KEY_INSERT },
222 { NSHomeFunctionKey, KEY_HOME },
223 { NSEndFunctionKey, KEY_END },
224 { NSPageUpFunctionKey, KEY_PAGEUP },
225 { NSPageDownFunctionKey, KEY_PAGEDOWN },
226 { NSMenuFunctionKey, KEY_MENU },
227 { NSTabCharacter, KEY_TAB },
228 { NSCarriageReturnCharacter, KEY_ENTER },
229 { NSEnterCharacter, KEY_ENTER },
230 { NSBackspaceCharacter, KEY_BACKSPACE },
231 { NSDeleteCharacter, KEY_DELETE },
235 unsigned int CocoaKeyToVLC(unichar i_key)
239 for (i = 0; nskeys_to_vlckeys[i].i_nskey != 0; i++) {
240 if (nskeys_to_vlckeys[i].i_nskey == i_key) {
241 return nskeys_to_vlckeys[i].i_vlckey;
244 return (unsigned int)i_key;
247 - (unsigned int)VLCModifiersToCocoa:(NSString *)theString
249 unsigned int new = 0;
251 if ([theString rangeOfString:@"Command"].location != NSNotFound)
252 new |= NSCommandKeyMask;
253 if ([theString rangeOfString:@"Alt"].location != NSNotFound)
254 new |= NSAlternateKeyMask;
255 if ([theString rangeOfString:@"Shift"].location != NSNotFound)
256 new |= NSShiftKeyMask;
257 if ([theString rangeOfString:@"Ctrl"].location != NSNotFound)
258 new |= NSControlKeyMask;
262 - (NSString *)VLCKeyToString:(NSString *)theString
264 if (![theString isEqualToString:@""]) {
265 if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
266 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
268 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
269 theString = [NSString stringWithFormat:@"%@+", theString];
271 if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
272 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
274 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
275 theString = [NSString stringWithFormat:@"%@-", theString];
277 theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString:@""];
278 theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString:@""];
279 theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString:@""];
280 theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString:@""];
283 #pragma GCC diagnostic ignored "-Wformat"
284 if ([theString length] > 1) {
285 if ([theString rangeOfString:@"Up"].location != NSNotFound)
286 return [NSString stringWithFormat:@"%C", NSUpArrowFunctionKey];
287 else if ([theString rangeOfString:@"Down"].location != NSNotFound)
288 return [NSString stringWithFormat:@"%C", NSDownArrowFunctionKey];
289 else if ([theString rangeOfString:@"Right"].location != NSNotFound)
290 return [NSString stringWithFormat:@"%C", NSRightArrowFunctionKey];
291 else if ([theString rangeOfString:@"Left"].location != NSNotFound)
292 return [NSString stringWithFormat:@"%C", NSLeftArrowFunctionKey];
293 else if ([theString rangeOfString:@"Enter"].location != NSNotFound)
294 return [NSString stringWithFormat:@"%C", NSEnterCharacter]; // we treat NSCarriageReturnCharacter as aquivalent
295 else if ([theString rangeOfString:@"Insert"].location != NSNotFound)
296 return [NSString stringWithFormat:@"%C", NSInsertFunctionKey];
297 else if ([theString rangeOfString:@"Home"].location != NSNotFound)
298 return [NSString stringWithFormat:@"%C", NSHomeFunctionKey];
299 else if ([theString rangeOfString:@"End"].location != NSNotFound)
300 return [NSString stringWithFormat:@"%C", NSEndFunctionKey];
301 else if ([theString rangeOfString:@"Pageup"].location != NSNotFound)
302 return [NSString stringWithFormat:@"%C", NSPageUpFunctionKey];
303 else if ([theString rangeOfString:@"Pagedown"].location != NSNotFound)
304 return [NSString stringWithFormat:@"%C", NSPageDownFunctionKey];
305 else if ([theString rangeOfString:@"Menu"].location != NSNotFound)
306 return [NSString stringWithFormat:@"%C", NSMenuFunctionKey];
307 else if ([theString rangeOfString:@"Tab"].location != NSNotFound)
308 return [NSString stringWithFormat:@"%C", NSTabCharacter];
309 else if ([theString rangeOfString:@"Backspace"].location != NSNotFound)
310 return [NSString stringWithFormat:@"%C", NSBackspaceCharacter];
311 else if ([theString rangeOfString:@"Delete"].location != NSNotFound)
312 return [NSString stringWithFormat:@"%C", NSDeleteCharacter];
313 else if ([theString rangeOfString:@"F12"].location != NSNotFound)
314 return [NSString stringWithFormat:@"%C", NSF12FunctionKey];
315 else if ([theString rangeOfString:@"F11"].location != NSNotFound)
316 return [NSString stringWithFormat:@"%C", NSF11FunctionKey];
317 else if ([theString rangeOfString:@"F10"].location != NSNotFound)
318 return [NSString stringWithFormat:@"%C", NSF10FunctionKey];
319 else if ([theString rangeOfString:@"F9"].location != NSNotFound)
320 return [NSString stringWithFormat:@"%C", NSF9FunctionKey];
321 else if ([theString rangeOfString:@"F8"].location != NSNotFound)
322 return [NSString stringWithFormat:@"%C", NSF8FunctionKey];
323 else if ([theString rangeOfString:@"F7"].location != NSNotFound)
324 return [NSString stringWithFormat:@"%C", NSF7FunctionKey];
325 else if ([theString rangeOfString:@"F6"].location != NSNotFound)
326 return [NSString stringWithFormat:@"%C", NSF6FunctionKey];
327 else if ([theString rangeOfString:@"F5"].location != NSNotFound)
328 return [NSString stringWithFormat:@"%C", NSF5FunctionKey];
329 else if ([theString rangeOfString:@"F4"].location != NSNotFound)
330 return [NSString stringWithFormat:@"%C", NSF4FunctionKey];
331 else if ([theString rangeOfString:@"F3"].location != NSNotFound)
332 return [NSString stringWithFormat:@"%C", NSF3FunctionKey];
333 else if ([theString rangeOfString:@"F2"].location != NSNotFound)
334 return [NSString stringWithFormat:@"%C", NSF2FunctionKey];
335 else if ([theString rangeOfString:@"F1"].location != NSNotFound)
336 return [NSString stringWithFormat:@"%C", NSF1FunctionKey];
337 /* note that we don't support esc here, since it is reserved for leaving fullscreen */
339 #pragma GCC diagnostic warning "-Wformat"