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");
73 /* i_width is in pixels */
74 - (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
76 NSMutableString *o_wrapped;
77 NSString *o_out_string;
78 NSRange glyphRange, effectiveRange, charRange;
79 NSRect lineFragmentRect;
80 unsigned glyphIndex, breaksInserted = 0;
82 NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
83 attributes: [NSDictionary dictionaryWithObjectsAndKeys:
84 [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
85 NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
86 NSTextContainer *o_container = [[NSTextContainer alloc]
87 initWithContainerSize: NSMakeSize(i_width, 2000)];
89 [o_layout_manager addTextContainer: o_container];
90 [o_container release];
91 [o_storage addLayoutManager: o_layout_manager];
92 [o_layout_manager release];
94 o_wrapped = [o_in_string mutableCopy];
95 glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
97 for (glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
98 glyphIndex += effectiveRange.length) {
99 lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
100 effectiveRange: &effectiveRange];
101 charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
102 actualGlyphRange: &effectiveRange];
103 if ([o_wrapped lineRangeForRange:
104 NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
105 [o_wrapped insertString: @"\n" atIndex: NSMaxRange(charRange) + breaksInserted];
109 o_out_string = [NSString stringWithString: o_wrapped];
116 - (NSString *)OSXStringKeyToString:(NSString *)theString
118 if (![theString isEqualToString:@""]) {
120 if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
121 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
123 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
124 theString = [NSString stringWithFormat:@"%@+", theString];
126 if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
127 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
129 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
130 theString = [NSString stringWithFormat:@"%@-", theString];
133 theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString: @("\xE2\x8C\x98")];
134 theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString: @("\xE2\x8C\xA5")];
135 theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString: @("\xE2\x87\xA7")];
136 theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString: @("\xE2\x8C\x83")];
137 /* show non-character keys correctly */
138 theString = [theString stringByReplacingOccurrencesOfString:@"Right" withString:@("\xE2\x86\x92")];
139 theString = [theString stringByReplacingOccurrencesOfString:@"Left" withString:@("\xE2\x86\x90")];
140 theString = [theString stringByReplacingOccurrencesOfString:@"Up" withString:@("\xE2\x86\x91")];
141 theString = [theString stringByReplacingOccurrencesOfString:@"Down" withString:@("\xE2\x86\x93")];
142 theString = [theString stringByReplacingOccurrencesOfString:@"Enter" withString:@("\xe2\x86\xb5")];
143 theString = [theString stringByReplacingOccurrencesOfString:@"Tab" withString:@("\xe2\x87\xa5")];
144 theString = [theString stringByReplacingOccurrencesOfString:@"Delete" withString:@("\xe2\x8c\xab")]; /* capitalize plain characters to suit the menubar's look */
145 theString = [theString capitalizedString];
148 theString = [NSString stringWithString:_NS("Not Set")];
152 - (NSString *)getCurrentTimeAsString:(input_thread_t *)p_input negative:(BOOL)b_negative
154 assert(p_input != nil);
157 char psz_time[MSTRTIME_MAX_SIZE];
159 var_Get(p_input, "time", &time);
161 mtime_t dur = input_item_GetDuration(input_GetItem(p_input));
162 if (b_negative && dur > 0) {
163 mtime_t remaining = 0;
164 if (dur > time.i_time)
165 remaining = dur - time.i_time;
166 return [NSString stringWithFormat: @"-%s", secstotimestr(psz_time, (remaining / 1000000))];
168 return @(secstotimestr(psz_time, (time.i_time / 1000000)));
172 #pragma mark Key Shortcuts
177 unsigned int i_vlckey;
178 } nskeys_to_vlckeys[] =
180 { NSUpArrowFunctionKey, KEY_UP },
181 { NSDownArrowFunctionKey, KEY_DOWN },
182 { NSLeftArrowFunctionKey, KEY_LEFT },
183 { NSRightArrowFunctionKey, KEY_RIGHT },
184 { NSF1FunctionKey, KEY_F1 },
185 { NSF2FunctionKey, KEY_F2 },
186 { NSF3FunctionKey, KEY_F3 },
187 { NSF4FunctionKey, KEY_F4 },
188 { NSF5FunctionKey, KEY_F5 },
189 { NSF6FunctionKey, KEY_F6 },
190 { NSF7FunctionKey, KEY_F7 },
191 { NSF8FunctionKey, KEY_F8 },
192 { NSF9FunctionKey, KEY_F9 },
193 { NSF10FunctionKey, KEY_F10 },
194 { NSF11FunctionKey, KEY_F11 },
195 { NSF12FunctionKey, KEY_F12 },
196 { NSInsertFunctionKey, KEY_INSERT },
197 { NSHomeFunctionKey, KEY_HOME },
198 { NSEndFunctionKey, KEY_END },
199 { NSPageUpFunctionKey, KEY_PAGEUP },
200 { NSPageDownFunctionKey, KEY_PAGEDOWN },
201 { NSMenuFunctionKey, KEY_MENU },
202 { NSTabCharacter, KEY_TAB },
203 { NSCarriageReturnCharacter, KEY_ENTER },
204 { NSEnterCharacter, KEY_ENTER },
205 { NSBackspaceCharacter, KEY_BACKSPACE },
206 { NSDeleteCharacter, KEY_DELETE },
210 unsigned int CocoaKeyToVLC(unichar i_key)
214 for (i = 0; nskeys_to_vlckeys[i].i_nskey != 0; i++) {
215 if (nskeys_to_vlckeys[i].i_nskey == i_key) {
216 return nskeys_to_vlckeys[i].i_vlckey;
219 return (unsigned int)i_key;
222 - (unsigned int)VLCModifiersToCocoa:(NSString *)theString
224 unsigned int new = 0;
226 if ([theString rangeOfString:@"Command"].location != NSNotFound)
227 new |= NSCommandKeyMask;
228 if ([theString rangeOfString:@"Alt"].location != NSNotFound)
229 new |= NSAlternateKeyMask;
230 if ([theString rangeOfString:@"Shift"].location != NSNotFound)
231 new |= NSShiftKeyMask;
232 if ([theString rangeOfString:@"Ctrl"].location != NSNotFound)
233 new |= NSControlKeyMask;
237 - (NSString *)VLCKeyToString:(NSString *)theString
239 if (![theString isEqualToString:@""]) {
240 if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
241 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
243 theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
244 theString = [NSString stringWithFormat:@"%@+", theString];
246 if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
247 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
249 theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
250 theString = [NSString stringWithFormat:@"%@-", theString];
252 theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString:@""];
253 theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString:@""];
254 theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString:@""];
255 theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString:@""];
259 #pragma GCC diagnostic ignored "-Wformat"
261 if ([theString length] > 1) {
262 if ([theString rangeOfString:@"Up"].location != NSNotFound)
263 return [NSString stringWithFormat:@"%C", NSUpArrowFunctionKey];
264 else if ([theString rangeOfString:@"Down"].location != NSNotFound)
265 return [NSString stringWithFormat:@"%C", NSDownArrowFunctionKey];
266 else if ([theString rangeOfString:@"Right"].location != NSNotFound)
267 return [NSString stringWithFormat:@"%C", NSRightArrowFunctionKey];
268 else if ([theString rangeOfString:@"Left"].location != NSNotFound)
269 return [NSString stringWithFormat:@"%C", NSLeftArrowFunctionKey];
270 else if ([theString rangeOfString:@"Enter"].location != NSNotFound)
271 return [NSString stringWithFormat:@"%C", NSEnterCharacter]; // we treat NSCarriageReturnCharacter as aquivalent
272 else if ([theString rangeOfString:@"Insert"].location != NSNotFound)
273 return [NSString stringWithFormat:@"%C", NSInsertFunctionKey];
274 else if ([theString rangeOfString:@"Home"].location != NSNotFound)
275 return [NSString stringWithFormat:@"%C", NSHomeFunctionKey];
276 else if ([theString rangeOfString:@"End"].location != NSNotFound)
277 return [NSString stringWithFormat:@"%C", NSEndFunctionKey];
278 else if ([theString rangeOfString:@"Pageup"].location != NSNotFound)
279 return [NSString stringWithFormat:@"%C", NSPageUpFunctionKey];
280 else if ([theString rangeOfString:@"Pagedown"].location != NSNotFound)
281 return [NSString stringWithFormat:@"%C", NSPageDownFunctionKey];
282 else if ([theString rangeOfString:@"Menu"].location != NSNotFound)
283 return [NSString stringWithFormat:@"%C", NSMenuFunctionKey];
284 else if ([theString rangeOfString:@"Tab"].location != NSNotFound)
285 return [NSString stringWithFormat:@"%C", NSTabCharacter];
286 else if ([theString rangeOfString:@"Backspace"].location != NSNotFound)
287 return [NSString stringWithFormat:@"%C", NSBackspaceCharacter];
288 else if ([theString rangeOfString:@"Delete"].location != NSNotFound)
289 return [NSString stringWithFormat:@"%C", NSDeleteCharacter];
290 else if ([theString rangeOfString:@"F12"].location != NSNotFound)
291 return [NSString stringWithFormat:@"%C", NSF12FunctionKey];
292 else if ([theString rangeOfString:@"F11"].location != NSNotFound)
293 return [NSString stringWithFormat:@"%C", NSF11FunctionKey];
294 else if ([theString rangeOfString:@"F10"].location != NSNotFound)
295 return [NSString stringWithFormat:@"%C", NSF10FunctionKey];
296 else if ([theString rangeOfString:@"F9"].location != NSNotFound)
297 return [NSString stringWithFormat:@"%C", NSF9FunctionKey];
298 else if ([theString rangeOfString:@"F8"].location != NSNotFound)
299 return [NSString stringWithFormat:@"%C", NSF8FunctionKey];
300 else if ([theString rangeOfString:@"F7"].location != NSNotFound)
301 return [NSString stringWithFormat:@"%C", NSF7FunctionKey];
302 else if ([theString rangeOfString:@"F6"].location != NSNotFound)
303 return [NSString stringWithFormat:@"%C", NSF6FunctionKey];
304 else if ([theString rangeOfString:@"F5"].location != NSNotFound)
305 return [NSString stringWithFormat:@"%C", NSF5FunctionKey];
306 else if ([theString rangeOfString:@"F4"].location != NSNotFound)
307 return [NSString stringWithFormat:@"%C", NSF4FunctionKey];
308 else if ([theString rangeOfString:@"F3"].location != NSNotFound)
309 return [NSString stringWithFormat:@"%C", NSF3FunctionKey];
310 else if ([theString rangeOfString:@"F2"].location != NSNotFound)
311 return [NSString stringWithFormat:@"%C", NSF2FunctionKey];
312 else if ([theString rangeOfString:@"F1"].location != NSNotFound)
313 return [NSString stringWithFormat:@"%C", NSF1FunctionKey];
314 else if ([theString rangeOfString:@"Space"].location != NSNotFound)
316 /* note that we don't support esc here, since it is reserved for leaving fullscreen */
319 #pragma GCC diagnostic warning "-Wformat"