Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 427 lines (348 sloc) 15.395 kB
720b0e7 @uliwitness Added licensing information to the source files.
authored
1 //
2 // UKFontMenuController.m
3 // UKFontMenuController
4 //
5 //
6 // Copyright 2004 Uli Kusterer.
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 //
21 // 2. Altered source versions must be plainly marked as such, and must not be
22 // misrepresented as being the original software.
23 //
24 // 3. This notice may not be removed or altered from any source
25 // distribution.
26 //
dc5be1c Initial check-in.
uli authored
27
28 // -----------------------------------------------------------------------------
29 // Headers:
30 // -----------------------------------------------------------------------------
31
32 #import "UKFontMenuController.h"
33
34
35 // -----------------------------------------------------------------------------
36 // UKFontMenuController:
37 // -----------------------------------------------------------------------------
38
39 @implementation UKFontMenuController
40
41 // -----------------------------------------------------------------------------
42 // awakeFromNib:
43 /// NIB has been loaded, set up font menu.
44 //
45 // REVISIONS:
46 // 2004-09-01 UK Created.
47 // -----------------------------------------------------------------------------
48
49 -(void) awakeFromNib
50 {
51 [self rebuildMenu: self];
52
53 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(collectionsMayHaveChangedNotification:) name: NSWindowWillCloseNotification object: [NSFontPanel sharedFontPanel]];
54 }
55
56
57 // -----------------------------------------------------------------------------
58 // dealloc:
59 // Clean up by getting rid of ssociated objects.
60 //
61 // REVISIONS:
62 // 2004-09-01 UK Created.
63 // -----------------------------------------------------------------------------
64
65 -(void) dealloc
66 {
67 [newFontFamily release];
68
69 [super dealloc];
70 }
71
72
73 // -----------------------------------------------------------------------------
74 // rebuildMenu:
75 /// Remove any old items we added to the menu and append new, updated and
76 /// more current ones.
77 //
78 // REVISIONS:
79 // 2004-09-02 UK Fixed bug in deleting items that would miss submenus.
80 // 2004-09-01 UK Created.
81 // -----------------------------------------------------------------------------
82
83 -(void) rebuildMenu: (id)sender
84 {
85 // Remove any old items:
86 id<NSMenuItem> item = [fontMenu itemAtIndex: [fontMenu numberOfItems] -1];
87 while( [item target] == self ) // All items we create have us as the target, even separator lines.
88 {
89 [fontMenu removeItemAtIndex: [fontMenu numberOfItems] -1];
90 item = [fontMenu itemAtIndex: [fontMenu numberOfItems] -1];
91 }
92
93 // Look for UKFontMenuCollectionName in user defaults:
94 NSString* collectionName = [[NSUserDefaults standardUserDefaults] objectForKey: @"UKFontMenuCollectionName"];
95
96 if( collectionName == nil ) // No user defaults? Maybe a collection with app's name?
97 {
98 NSArray* colls = [[NSFontManager sharedFontManager] collectionNames];
99 NSString* appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey: @"CFBundleName"];
100 if( [colls containsObject: appName] )
101 collectionName = appName;
102 if( !collectionName && [colls containsObject: NSLocalizedString(@"Font Menu",@"")] )
103 collectionName = NSLocalizedString(@"Font Menu",@"");
104 }
105
106 id<NSMenuItem> sep = nil;
107
108 // Add a separator item if there is none yet:
109 if( [fontMenu numberOfItems] > 0 && ![item isSeparatorItem] )
110 {
111 sep = [NSMenuItem separatorItem];
112 [fontMenu addItem: sep];
113 [sep setTarget: self]; // Put a separator in there to put it apart from the "Favorites".
114 }
115
116 [self addFavoritesCollection: @"com.apple.Favorites" name: NSLocalizedString(@"Favorites",@"")
117 toMenu: fontMenu]; // Add 'Favorites' submenu.
118 [self addFavoritesCollection: @"com.apple.Recents" name: NSLocalizedString(@"Recently Used",@"")
119 toMenu: fontMenu]; // Add 'Recently used' submenu.
120 //[fontMenu setDelegate: self];
121
122 if( collectionName ) // Have UKFontMenuCollectionName or app-specific collection? List it!
123 {
124 sep = [NSMenuItem separatorItem];
125 [fontMenu addItem: sep]; // Put a separator in there to put it apart from the "Favorites".
126 [sep setTarget: self];
127 [self addFontCollection: collectionName toMenu: fontMenu];
128 }
129 else // Otherwise, create submenus for *all* collections:
130 [self addAllFontCollectionsToMenu: fontMenu];
131 }
132
133
134 // -----------------------------------------------------------------------------
135 // collectionsMayHaveChangedNotification:
136 /// We got one of the notifications that *may* indicate the collections
137 /// have changed. Rebuild the menu to make sure it's halfway current.
138 //
139 // REVISIONS:
140 // 2004-09-01 UK Created.
141 // -----------------------------------------------------------------------------
142
143 -(void) collectionsMayHaveChangedNotification: (NSNotification*)notif
144 {
145 [self rebuildMenu: self];
146 }
147
148
149 // -----------------------------------------------------------------------------
150 // addFavoritesCollectionToMenu:
151 /// Build the "Favorites" menu.
152 /// Favorites need to be handled specially, as they include a size, and
153 /// don't preview their font.
154 //
155 // REVISIONS:
156 // 2004-09-01 UK Created.
157 // -----------------------------------------------------------------------------
158
159 -(void) addFavoritesCollection: (NSString*)collectionID name:(NSString*)collectionName toMenu: (NSMenu*)mnu
160 {
161 id <NSMenuItem> mainItem = [mnu addItemWithTitle: collectionName action: 0 keyEquivalent: @""];
162 NSMenu* submenu = [[[NSMenu alloc] initWithTitle: collectionName] autorelease];
163 [mainItem setSubmenu: submenu];
164 [mainItem setTarget: self];
165
166 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
167 NSFontManager* fm = [NSFontManager sharedFontManager];
168 NSArray* fontDescs = [fm fontDescriptorsInCollection: collectionID];
169 NSEnumerator* descEnny = [fontDescs objectEnumerator];
170 NSFontDescriptor* fdesc;
171 int x = 0;
172
173 while( (fdesc = [descEnny nextObject]) )
174 {
175 NSString* currFName = [[fdesc fontAttributes] objectForKey: NSFontVisibleNameAttribute];
176 if( currFName ) // Somehow we can get invalid names.
177 {
178 id <NSMenuItem> subitem = [submenu addItemWithTitle: currFName action:@selector(menuChoiceChangeFavoriteFont:) keyEquivalent: @""];
179 [subitem setTag: x++];
180 [subitem setTarget: self];
181 }
182 }
183 [pool release];
184
185 }
186
187
188 // -----------------------------------------------------------------------------
189 // addAllFontCollectionsToMenu:
190 /// Loop over all available font collections (except favorites and recently
191 /// used), create submenus and call addFontCollection:toMenu: for them.
192 //
193 // REVISIONS:
194 // 2004-09-01 UK Created.
195 // -----------------------------------------------------------------------------
196
197 -(void) addAllFontCollectionsToMenu: (NSMenu*)mnu
198 {
199 NSFontManager* fm = [NSFontManager sharedFontManager];
200 NSArray* collections = [fm collectionNames];
201 NSEnumerator* enny = [collections objectEnumerator];
202 NSString* collectionName;
203
204 while( (collectionName = [enny nextObject]) )
205 {
206 if( [collectionName isEqualToString: @"com.apple.Favorites"] ) // Skip favorites.
207 continue;
208
209 if( [collectionName isEqualToString: @"com.apple.Recents"] ) // Skip recents.
210 continue;
211
212 id <NSMenuItem> mainItem = [mnu addItemWithTitle: collectionName action: 0 keyEquivalent: @""];
213 NSMenu* submenu = [[[NSMenu alloc] initWithTitle: collectionName] autorelease];
214 [mainItem setSubmenu: submenu];
215 [mainItem setTarget: self];
216
217 [self addFontCollection: collectionName toMenu: submenu];
218 }
219 }
220
221
222 // -----------------------------------------------------------------------------
223 // addFontCollection:toMenu:
224 /// Add a list of the font families in the specified collection to a menu.
225 /// This will make each item display in its own font, if the charset for
226 /// name and font don't differ (they usually only do for dingbat-style
227 /// fonts).
228 //
229 // REVISIONS:
230 // 2004-09-01 UK Created.
231 // -----------------------------------------------------------------------------
232
233 -(void) addFontCollection: (NSString*)collectionName toMenu: (NSMenu*)mnu
234 {
235 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
236 NSFontManager* fm = [NSFontManager sharedFontManager];
237 NSArray* fontDescs = [fm fontDescriptorsInCollection: collectionName];
238 NSEnumerator* descEnny = [fontDescs objectEnumerator];
239 NSFontDescriptor* fdesc;
240 NSMutableArray* foundFonts = [NSMutableArray array]; // Here we keep track of families so we don't list them twice (the different styles show up in the collection as well).
241
242 while( (fdesc = [descEnny nextObject]) )
243 {
244 NSString* currFName = [[fdesc fontAttributes] objectForKey: NSFontFamilyAttribute];
245 if( currFName && ![foundFonts containsObject: currFName] ) // Don't already have that family name?
246 {
247 // Add menu item for it:
248 id<NSMenuItem> item = [mnu addItemWithTitle: currFName action:@selector(menuChoiceChangeFont:) keyEquivalent: @""];
249 [item setTarget: self];
250
251 // Now make the title a live preview of the font:
252 NSFont* theFont = [[NSFontManager sharedFontManager] convertFont: [NSFont systemFontOfSize: [NSFont systemFontSize]] toFamily: currFName];
253 NSAttributedString* astr = [[[NSAttributedString alloc] initWithString: currFName attributes: [NSDictionary dictionaryWithObjectsAndKeys: theFont, NSFontAttributeName, nil]] autorelease];
254 [item setAttributedTitle: astr];
255
256 [foundFonts addObject: currFName]; // Remember font family so we don't add another item for it.
257 }
258 }
259 [pool release];
260 }
261
262
263 // -----------------------------------------------------------------------------
264 // menuChoiceChangeFont:
265 /// Menu action for regular font menu items.
266 //
267 // REVISIONS:
268 // 2004-09-01 UK Created.
269 // -----------------------------------------------------------------------------
270
271 -(IBAction) menuChoiceChangeFont: (id)sender
272 {
273 // Keep new font family name in our member variable so convertAttributes can access it:
274 [newFontFamily autorelease];
275 newFontFamily = nil; // just being paranoid...
276 newFontFamily = [[sender title] retain];
277 newFontSize = 0; // 0 = don't change size.
278
279 // Send change message:
280 NSResponder* firstRep = [[NSApp keyWindow] firstResponder];
281
282 if( [firstRep respondsToSelector: @selector(changeAttributes:)] )
283 [(NSTextView*)firstRep changeAttributes: self]; // Causes call to changeAttributes.
284 }
285
286
287 // -----------------------------------------------------------------------------
288 // menuChoiceChangeFavoriteFont:
289 /// Menu action for 'favorites' menu items.
290 //
291 // REVISIONS:
292 // 2004-09-01 UK Created.
293 // -----------------------------------------------------------------------------
294
295 -(IBAction) menuChoiceChangeFavoriteFont: (id)sender
296 {
297 [newFontFamily autorelease];
298 newFontFamily = nil; // just being paranoid...
299
300 NSFontManager* fm = [NSFontManager sharedFontManager];
301 NSArray* fontDescs = [fm fontDescriptorsInCollection: @"com.apple.Favorites"];
302 NSFontDescriptor* fdesc = [fontDescs objectAtIndex: [sender tag]];
303 newFontFamily = [[[fdesc fontAttributes] objectForKey: NSFontFamilyAttribute] retain];
304 newFontSize = [[[fdesc fontAttributes] objectForKey: NSFontSizeAttribute] intValue];
305
306 // Send change message:
307 NSResponder* firstRep = [[NSApp keyWindow] firstResponder];
308
309 if( [firstRep respondsToSelector: @selector(changeAttributes:)] )
310 [(NSTextView*)firstRep changeAttributes: self]; // Causes call to changeAttributes.
311 }
312
313
314 // -----------------------------------------------------------------------------
315 // convertAttributes:
316 /// Called for each style run affected by the changeAttributes call we make
317 /// in our menu item actions.
318 //
319 // REVISIONS:
320 // 2004-09-01 UK Created.
321 // -----------------------------------------------------------------------------
322
323 -(NSDictionary*) convertAttributes: (NSDictionary*)attributes
324 {
325 NSMutableDictionary* muDic = [[attributes mutableCopy] autorelease];
326 NSFont* newFont = [[[attributes objectForKey: NSFontAttributeName] retain] autorelease];
327
328 if( newFontFamily )
329 newFont = [[NSFontManager sharedFontManager] convertFont: newFont toFamily: newFontFamily];
330 if( newFontSize > 0 )
331 newFont = [[NSFontManager sharedFontManager] convertFont: newFont toSize: newFontSize];
332
333 [muDic setObject: newFont forKey: NSFontAttributeName];
334
335 return muDic;
336 }
337
338
339 /*-(int) numberOfItemsInMenu: (NSMenu*)menu
340 {
341 return [menu numberOfItems];
342 }
343
344
345 -(BOOL) menu:(NSMenu*)menu updateItem:(NSMenuItem*)item atIndex:(int)index shouldCancel:(BOOL)shouldCancel
346 {
347 if( [item action] == @selector(menuChoiceChangeFont:) )
348 {
349 if( [item attributedTitle] == nil )
350 {
351 NSString* nme = [item title];
352 NSFont* theFont = [[NSFontManager sharedFontManager] convertFont: [NSFont systemFontOfSize: [NSFont systemFontSize]] toFamily: nme];
353 NSAttributedString* astr = [[[NSAttributedString alloc] initWithString: nme attributes: [NSDictionary dictionaryWithObjectsAndKeys: theFont, NSFontAttributeName, nil]] autorelease];
354 [item setAttributedTitle: astr];
355 }
356 }
357
358 return !shouldCancel;
359 }*/
360
361
362
363 // -----------------------------------------------------------------------------
364 // validateMenuItem:
365 // Enable/disable menu items we created and checkmark current font in
366 // menu.
367 //
368 // REVISIONS:
369 // 2004-09-01 UK Created.
370 // -----------------------------------------------------------------------------
371
372 -(BOOL) validateMenuItem: (id<NSMenuItem>)itm
373 {
374 if( ([itm action] == @selector(menuChoiceChangeFont:)
375 || [itm action] == @selector(menuChoiceChangeFavoriteFont:)) )
376 {
377 // create a fake "Bigger" menu item and ask the responder whether we can enable it:
378 NSMenuItem* tempItem = [[[NSMenuItem alloc] initWithTitle: @"Bigger (Fake)" action:@selector(modifyFont:) keyEquivalent:@""] autorelease];
379 [tempItem setTag: NSSizeUpFontAction];
380 BOOL doEnable = [[[NSApp keyWindow] firstResponder] validateMenuItem: tempItem];
381 if( doEnable )
382 {
383 NSResponder* firstRep = [[NSApp keyWindow] firstResponder];
384 BOOL editable = [firstRep respondsToSelector: @selector(isEditable)];
385 if( editable )
386 doEnable = [(NSTextView*)firstRep isEditable];
387
388 editable = [firstRep respondsToSelector: @selector(isRichText)];
389 if( editable )
390 doEnable = [(NSTextView*)firstRep isRichText];
391
392 if( doEnable )
393 doEnable = [(NSTextView*)firstRep respondsToSelector: @selector(changeAttributes:)];
394 }
395 if( doEnable && ([itm action] != @selector(menuChoiceChangeFavoriteFont:)) )
396 {
397 NSString* currFont = [[[NSFontManager sharedFontManager] selectedFont] familyName];
398 [itm setState: [[itm title] isEqualToString: currFont] ];
399 }
400
401 return doEnable;
402 }
403 else
404 return NO;
405 }
406
407
408 // ----------------------------------------------------------
409 // - fontMenu:
410 // ----------------------------------------------------------
411
412 -(NSMenu*) fontMenu
413 {
414 return fontMenu;
415 }
416
417 // ----------------------------------------------------------
418 // - setFontMenu:
419 // ----------------------------------------------------------
420 -(void) setFontMenu: (NSMenu*)theFontMenu
421 {
422 fontMenu = theFontMenu;
423 }
424
425
426 @end
Something went wrong with that request. Please try again.