]> git.sesse.net Git - vlc/blob - modules/gui/macosx/StringUtility.m
4475d9dcdd6f2ba6e6ca4ccd5bd320ca80411365
[vlc] / modules / gui / macosx / StringUtility.m
1 /*****************************************************************************
2  * StringUtility.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2012 VLC authors and VideoLAN
5  * $Id$
6  *
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>
11  *
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.
16  *
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.
21  *
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  *****************************************************************************/
26
27 #import <vlc_input.h>
28 #import <vlc_keys.h>
29 #import "StringUtility.h"
30 #import "intf.h"
31
32 @implementation VLCStringUtility
33
34 static VLCStringUtility *_o_sharedInstance = nil;
35
36 + (VLCStringUtility *)sharedInstance
37 {
38     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
39 }
40
41 - (id)init
42 {
43     if (_o_sharedInstance)
44         [self dealloc];
45     else
46         _o_sharedInstance = [super init];
47
48     return _o_sharedInstance;
49 }
50
51 #pragma mark -
52 #pragma mark String utility
53
54 - (NSString *)localizedString:(const char *)psz
55 {
56     NSString * o_str = nil;
57
58     if (psz != NULL) {
59         o_str = [NSString stringWithCString: _(psz) encoding:NSUTF8StringEncoding];
60
61         if (o_str == NULL) {
62             msg_Err(VLCIntf, "could not translate: %s", psz);
63             return(@"");
64         }
65     } else {
66         msg_Warn(VLCIntf, "can't translate empty strings");
67         return(@"");
68     }
69
70     return(o_str);
71 }
72
73 /* i_width is in pixels */
74 - (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
75 {
76     NSMutableString *o_wrapped;
77     NSString *o_out_string;
78     NSRange glyphRange, effectiveRange, charRange;
79     NSRect lineFragmentRect;
80     unsigned glyphIndex, breaksInserted = 0;
81
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)];
88
89     [o_layout_manager addTextContainer: o_container];
90     [o_container release];
91     [o_storage addLayoutManager: o_layout_manager];
92     [o_layout_manager release];
93
94     o_wrapped = [o_in_string mutableCopy];
95     glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
96
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];
106             breaksInserted++;
107         }
108     }
109     o_out_string = [NSString stringWithString: o_wrapped];
110     [o_wrapped release];
111     [o_storage release];
112
113     return o_out_string;
114 }
115
116 - (NSString *)OSXStringKeyToString:(NSString *)theString
117 {
118     if (![theString isEqualToString:@""]) {
119         /* remove cruft */
120         if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
121             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
122         else {
123             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
124             theString = [NSString stringWithFormat:@"%@+", theString];
125         }
126         if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
127             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
128         else {
129             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
130             theString = [NSString stringWithFormat:@"%@-", theString];
131         }
132         /* modifiers */
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];
146     }
147     else
148         theString = [NSString stringWithString:_NS("Not Set")];
149     return theString;
150 }
151
152 - (NSString *)getCurrentTimeAsString:(input_thread_t *)p_input negative:(BOOL)b_negative
153 {
154     assert(p_input != nil);
155     
156     vlc_value_t time;
157     char psz_time[MSTRTIME_MAX_SIZE];
158     
159     var_Get(p_input, "time", &time);
160     
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))];
167     } else
168         return @(secstotimestr(psz_time, (time.i_time / 1000000)));
169 }
170
171 #pragma mark -
172 #pragma mark Key Shortcuts
173
174 static struct
175 {
176     unichar i_nskey;
177     unsigned int i_vlckey;
178 } nskeys_to_vlckeys[] =
179 {
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 },
207     {0,0}
208 };
209
210 unsigned int CocoaKeyToVLC(unichar i_key)
211 {
212     unsigned int i;
213
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;
217         }
218     }
219     return (unsigned int)i_key;
220 }
221
222 - (unsigned int)VLCModifiersToCocoa:(NSString *)theString
223 {
224     unsigned int new = 0;
225
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;
234     return new;
235 }
236
237 - (NSString *)VLCKeyToString:(NSString *)theString
238 {
239     if (![theString isEqualToString:@""]) {
240         if ([theString characterAtIndex:([theString length] - 1)] != 0x2b)
241             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
242         else {
243             theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
244             theString = [NSString stringWithFormat:@"%@+", theString];
245         }
246         if ([theString characterAtIndex:([theString length] - 1)] != 0x2d)
247             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
248         else {
249             theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
250             theString = [NSString stringWithFormat:@"%@-", theString];
251         }
252         theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString:@""];
253         theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString:@""];
254         theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString:@""];
255         theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString:@""];
256     }
257
258 #ifdef __clang__
259 #pragma GCC diagnostic ignored "-Wformat"
260 #endif
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         /* note that we don't support esc here, since it is reserved for leaving fullscreen */
315     }
316 #ifdef __clang__
317 #pragma GCC diagnostic warning "-Wformat"
318 #endif
319
320     return theString;
321 }
322
323 @end