2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #import "AIMenuController.h"
20 #import <Adium/AIAccount.h>
21 #import <Adium/AIChat.h>
22 #import <Adium/AIListContact.h>
23 #import <Adium/AIListObject.h>
24 #import <Adium/AIMetaContact.h>
25 #import <AIUtilities/AIMenuAdditions.h>
26 #import <AIUtilities/AIStringAdditions.h>
28 @interface AIMenuController (PRIVATE)
29 - (void)localizeMenuTitles;
30 - (NSMenu *)contextualMenuWithLocations:(NSArray *)inLocationArray usingMenu:(NSMenu *)inMenu;
31 - (void)addMenuItemsForContact:(AIListContact *)inContact toMenu:(NSMenu *)workingMenu separatorItem:(BOOL *)separatorItem;
34 @implementation AIMenuController
37 - (void)initController
39 //Build the array of menu locations
40 locationArray = [[NSMutableArray alloc] initWithObjects:menu_Adium_About, menu_Adium_Preferences,
41 menu_File_New, menu_File_Close, menu_File_Save, menu_File_Additions,
42 menu_Edit_Bottom, menu_Edit_Additions,
43 menu_View_General, menu_View_Unnamed_A, menu_View_Unnamed_B, menu_View_Unnamed_C,
44 menu_Contact_Manage, menu_Contact_Info, menu_Contact_Action, menu_Contact_NegativeAction, menu_Contact_Additions,
45 menu_Status_State, menu_Status_Accounts, menu_Status_Additions,
46 menu_Format_Styles, menu_Format_Palettes, menu_Format_Additions,
47 menu_Window_Top, menu_Window_Commands, menu_Window_Auxiliary, menu_Window_Fixed,
48 menu_Help_Local, menu_Help_Web, menu_Help_Additions,
49 menu_Dock_Status, nil];
51 //Set up our contextual menu stuff
52 contextualMenu = [[NSMenu alloc] init];
53 contextualMenuItemDict = [[NSMutableDictionary alloc] init];
54 currentContextMenuObject = nil;
55 textViewContextualMenu = [[NSMenu alloc] init];
56 contextualMenu_TextView = nil;
58 [self localizeMenuTitles];
62 - (void)closeController
64 //There's no need to remove the menu items, the system will take them out for us.
68 - (void)addMenuItem:(NSMenuItem *)newItem toLocation:(MENU_LOCATION)location
71 NSMenu *targetMenu = nil;
75 //Find the menu item (or the closest one above it)
76 destination = location;
77 menuItem = [locationArray objectAtIndex:destination];
78 while((menuItem == nilMenuItem) && (destination > 0)) {
80 menuItem = [locationArray objectAtIndex:destination];
82 if([menuItem isKindOfClass:[NSMenuItem class]]) {
83 //If attached to a menu item, insert below that item
84 targetMenu = [menuItem menu];
85 targetIndex = [targetMenu indexOfItem:menuItem];
87 //If it's attached to an NSMenu (and not an NSMenuItem), insert at the top of the menu
88 targetMenu = (NSMenu *)menuItem;
92 //Insert the new item and a divider (if necessary)
93 if(location != destination) {
94 [targetMenu insertItem:[NSMenuItem separatorItem] atIndex:++targetIndex];
96 [targetMenu insertItem:newItem atIndex:targetIndex+1];
98 //update the location array
99 [locationArray replaceObjectAtIndex:location withObject:newItem];
101 [[adium notificationCenter] postNotificationName:Menu_didChange object:[newItem menu] userInfo:nil];
105 - (void)removeMenuItem:(NSMenuItem *)targetItem
107 NSMenu *targetMenu = [targetItem menu];
108 int targetIndex = [targetMenu indexOfItem:targetItem];
109 unsigned loop, maxLoop;
111 //Fix the pointer if this is one
112 for(loop = 0, maxLoop = [locationArray count]; loop < maxLoop; loop++) {
113 NSMenuItem *menuItem = [locationArray objectAtIndex:loop];
115 //Move to the item above it, nil if a divider
116 if(menuItem == targetItem) {
117 if(targetIndex != 0) {
118 NSMenuItem *previousItem = [targetMenu itemAtIndex:(targetIndex - 1)];
120 if([previousItem isSeparatorItem]) {
121 [locationArray replaceObjectAtIndex:loop withObject:nilMenuItem];
123 [locationArray replaceObjectAtIndex:loop withObject:previousItem];
126 //If there are no more items, attach to the menu
127 [locationArray replaceObjectAtIndex:loop withObject:targetMenu];
133 [targetMenu removeItem:targetItem];
135 //Remove any double dividers (And dividers at the bottom)
136 for(loop = 0; loop < [targetMenu numberOfItems]; loop++) {
137 if(([[targetMenu itemAtIndex:loop] isSeparatorItem]) &&
138 (loop == [targetMenu numberOfItems]-1 || [[targetMenu itemAtIndex:loop+1] isSeparatorItem])) {
139 [targetMenu removeItemAtIndex:loop];
140 loop--;//re-search the location
144 [[adium notificationCenter] postNotificationName:Menu_didChange object:targetMenu userInfo:nil];
147 - (void)addContextualMenuItem:(NSMenuItem *)newItem toLocation:(CONTEXT_MENU_LOCATION)location
150 NSMutableArray *itemArray;
152 //Search for an existing item array for menu items in this location
153 key = [NSNumber numberWithInt:location];
154 itemArray = [contextualMenuItemDict objectForKey:key];
156 //If one is not found, create it
158 itemArray = [[NSMutableArray alloc] init];
159 [contextualMenuItemDict setObject:itemArray forKey:key];
162 //Add the passed menu item to the array
163 [itemArray addObject:newItem];
166 //Pass an array of NSNumbers corresponding to the desired contextual menu locations
167 - (NSMenu *)contextualMenuWithLocations:(NSArray *)inLocationArray forListObject:(AIListObject *)inObject
172 //Remember what our menu is configured for
173 [currentContextMenuObject release];
174 currentContextMenuObject = [inObject retain];
176 //Get the pre-created contextual menu items
177 workingMenu = [self contextualMenuWithLocations:inLocationArray usingMenu:contextualMenu];
179 //Add any account-specific menu items
181 if([inObject isKindOfClass:[AIMetaContact class]]) {
182 NSEnumerator *enumerator;
183 AIListContact *aListContact;
184 enumerator = [[(AIMetaContact *)inObject listContacts] objectEnumerator];
186 while(aListContact = [enumerator nextObject]) {
187 [self addMenuItemsForContact:aListContact
189 separatorItem:&separatorItem];
192 } else if([inObject isKindOfClass:[AIListContact class]]) {
193 [self addMenuItemsForContact:(AIListContact *)inObject
195 separatorItem:&separatorItem];
201 - (NSMenu *)contextualMenuWithLocations:(NSArray *)inLocationArray forListObject:(AIListObject *)inObject inChat:(AIChat *)inChat
203 [currentContextMenuChat release];
204 currentContextMenuChat = [inChat retain];
206 return [self contextualMenuWithLocations:inLocationArray forListObject:inObject];
209 //Add menuItems for a passed contact to a specified menu. *seperatorItem can be YES to indicate that a
210 //separator item should be inserted before the menu items if desired. It will then be set to NO.
211 - (void)addMenuItemsForContact:(AIListContact *)inContact toMenu:(NSMenu *)workingMenu separatorItem:(BOOL *)separatorItem
213 NSArray *itemArray = [[inContact account] menuItemsForContact:inContact];
215 if(itemArray && [itemArray count]) {
216 NSEnumerator *enumerator;
217 NSMenuItem *menuItem;
219 if(*separatorItem == YES) {
220 [workingMenu addItem:[NSMenuItem separatorItem]];
224 enumerator = [itemArray objectEnumerator];
225 while(menuItem = [enumerator nextObject]) {
226 [workingMenu addItem:menuItem];
231 - (NSMenu *)contextualMenuWithLocations:(NSArray *)inLocationArray forTextView:(NSTextView *)inTextView
233 //remember menu config
234 [contextualMenu_TextView release];
235 contextualMenu_TextView = [inTextView retain];
237 return([self contextualMenuWithLocations:inLocationArray usingMenu:textViewContextualMenu]);
240 - (NSMenu *)contextualMenuWithLocations:(NSArray *)inLocationArray usingMenu:(NSMenu *)inMenu
242 NSEnumerator *enumerator;
244 NSMenuItem *menuItem;
245 BOOL itemsAbove = NO;
247 //Remove all items from the existing menu
248 [inMenu removeAllItems];
250 //Process each specified location
251 enumerator = [inLocationArray objectEnumerator];
252 while((location = [enumerator nextObject])) {
253 NSArray *menuItems = [contextualMenuItemDict objectForKey:location];
254 NSEnumerator *itemEnumerator;
257 if(itemsAbove && [menuItems count]) {
258 [inMenu addItem:[NSMenuItem separatorItem]];
262 //Add each menu item in the location
263 itemEnumerator = [menuItems objectEnumerator];
264 while((menuItem = [itemEnumerator nextObject])) {
266 [inMenu addItem:menuItem];
274 - (AIListObject *)currentContextMenuObject
276 return(currentContextMenuObject);
279 - (AIChat *)currentContextMenuChat
281 return(currentContextMenuChat);
284 - (NSTextView *)contextualMenuTextView
286 return(contextualMenu_TextView);
289 - (void)removeItalicsKeyEquivalent
291 [menuItem_Format_Italics setKeyEquivalent:@""];
294 - (void)restoreItalicsKeyEquivalent
296 [menuItem_Format_Italics setKeyEquivalent:@"i"];
299 - (void)localizeMenuTitles
301 //Menu items in MainMenu.nib for localization purposes
302 [menuItem_file setTitle:AILocalizedString(@"File",nil)];
303 [menuItem_edit setTitle:AILocalizedString(@"Edit",nil)];
304 [menuItem_view setTitle:AILocalizedString(@"View",nil)];
305 [menuItem_status setTitle:AILocalizedString(@"Status",nil)];
306 [menuItem_contact setTitle:AILocalizedString(@"Contact",nil)];
307 [menuItem_format setTitle:AILocalizedString(@"Format",nil)];
308 [menuItem_window setTitle:AILocalizedString(@"Window",nil)];
309 [menuItem_help setTitle:AILocalizedString(@"Help",nil)];
312 [menuItem_aboutAdium setTitle:AILocalizedString(@"About Adium",nil)];
313 [menuItem_adiumXtras setTitle:AILocalizedString(@"Adium Xtras",nil)];
314 [menuItem_preferences setTitle:AILocalizedString(@"Preferences...",nil)];
315 [menuItem_services setTitle:AILocalizedString(@"Services","Services menu item in the Adium menu")];
316 [menuItem_hideAdium setTitle:AILocalizedString(@"Hide Adium",nil)];
317 [menuItem_hideOthers setTitle:AILocalizedString(@"Hide Others",nil)];
318 [menuItem_showAll setTitle:AILocalizedString(@"Show All",nil)];
319 [menuItem_quitAdium setTitle:AILocalizedString(@"Quit Adium",nil)];
322 [menuItem_close setTitle:AILocalizedString(@"Close",nil)];
323 [menuItem_closeChat setTitle:AILocalizedString(@"Close Chat",nil)];
324 [menuItem_saveAs setTitle:AILocalizedString(@"Save As...",nil)];
325 [menuItem_pageSetup setTitle:AILocalizedString(@"Page Setup...",nil)];
326 [menuItem_print setTitle:AILocalizedString(@"Print...",nil)];
329 [menuItem_cut setTitle:AILocalizedString(@"Cut",nil)];
330 [menuItem_copy setTitle:AILocalizedString(@"Copy",nil)];
331 [menuItem_paste setTitle:AILocalizedString(@"Paste",nil)];
332 [menuItem_pasteFormatted setTitle:AILocalizedString(@"Paste Formatted",nil)];
333 [menuItem_clear setTitle:AILocalizedString(@"Clear",nil)];
334 [menuItem_selectAll setTitle:AILocalizedString(@"Select All",nil)];
336 #define TITLE_FIND AILocalizedString(@"Find",nil)
337 [menuItem_find setTitle:TITLE_FIND];
338 [menuItem_findCommand setTitle:[TITLE_FIND stringByAppendingEllipsis]];
339 [menuItem_findNext setTitle:AILocalizedString(@"Find Next",nil)];
340 [menuItem_findPrevious setTitle:AILocalizedString(@"Find Previous",nil)];
341 [menuItem_findUseSelectionForFind setTitle:AILocalizedString(@"Use Selection for Find",nil)];
342 [menuItem_findJumpToSelection setTitle:AILocalizedString(@"Jump to Selection",nil)];
344 #define TITLE_SPELLING AILocalizedString(@"Spelling",nil)
345 [menuItem_spelling setTitle:TITLE_SPELLING];
346 [menuItem_spellingCommand setTitle:[TITLE_SPELLING stringByAppendingEllipsis]];
347 [menuItem_spellingCheckSpelling setTitle:AILocalizedString(@"Check Spelling",nil)];
348 [menuItem_spellingCheckSpellingAsYouType setTitle:AILocalizedString(@"Check Spelling As You Type",nil)];
350 [menuItem_speech setTitle:AILocalizedString(@"Speech",nil)];
351 [menuItem_startSpeaking setTitle:AILocalizedString(@"Start Speaking",nil)];
352 [menuItem_stopSpeaking setTitle:AILocalizedString(@"Stop Speaking",nil)];
355 [menuItem_customizeToolbar setTitle:AILocalizedString(@"Customize Toolbar...",nil)];
358 [menuItem_bold setTitle:AILocalizedString(@"Bold",nil)];
359 [menuItem_italic setTitle:AILocalizedString(@"Italic",nil)];
360 [menuItem_underline setTitle:AILocalizedString(@"Underline",nil)];
361 [menuItem_showFonts setTitle:AILocalizedString(@"Show Fonts",nil)];
362 [menuItem_showColors setTitle:AILocalizedString(@"Show Colors",nil)];
365 [menuItem_minimize setTitle:AILocalizedString(@"Minimize",nil)];
366 [menuItem_bringAllToFront setTitle:AILocalizedString(@"Bring All to Front",nil)];
369 [menuItem_adiumHelp setTitle:AILocalizedString(@"Adium Help",nil)];
370 [menuItem_reportABug setTitle:AILocalizedString(@"Report a Bug",nil)];
371 [menuItem_sendFeedback setTitle:AILocalizedString(@"Send Feedback",nil)];
372 [menuItem_adiumForums setTitle:AILocalizedString(@"Adium Forums",nil)];