Plugins/WebKit Message View/ESWebKitMessageViewPreferences.m
author Frank Dowsett <wixardy@adium.im>
Tue Mar 16 06:35:39 2010 -0400 (2010-03-16)
changeset 2910 1bcb24fe3222
parent 1642 95ded294145e
child 2911 f211430a455e
permissions -rw-r--r--
Don't enable the header control if there isn't a header or topic for regular or group chats respectively. Fixes #13791
(transplanted from 3629989a40f9c22595d5a7569d41e369729b3160)
David@0
     1
/* 
David@0
     2
 * Adium is the legal property of its developers, whose names are listed in the copyright file included
David@0
     3
 * with this source distribution.
David@0
     4
 * 
David@0
     5
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
David@0
     6
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
David@0
     7
 * or (at your option) any later version.
David@0
     8
 * 
David@0
     9
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
David@0
    10
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
David@0
    11
 * Public License for more details.
David@0
    12
 * 
David@0
    13
 * You should have received a copy of the GNU General Public License along with this program; if not,
David@0
    14
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
David@0
    15
 */
David@0
    16
David@0
    17
#import "ESWebKitMessageViewPreferences.h"
David@0
    18
#import "AIWebKitMessageViewPlugin.h"
David@0
    19
#import "AIWebkitMessageViewStyle.h"
David@0
    20
#import "AIWebKitPreviewMessageViewController.h"
David@0
    21
#import "AIPreviewChat.h"
David@0
    22
#import "ESWebView.h"
David@0
    23
#import <Adium/AIAccountControllerProtocol.h>
David@0
    24
#import <Adium/AIContactControllerProtocol.h>
David@0
    25
#import <Adium/AIContentControllerProtocol.h>
David@0
    26
#import <Adium/AIInterfaceControllerProtocol.h>
David@0
    27
#import <Adium/AIAccount.h>
David@0
    28
#import <Adium/AIChat.h>
David@0
    29
#import <Adium/AIContentMessage.h>
David@0
    30
#import <Adium/AIContentObject.h>
zacw@1305
    31
#import <Adium/AIContentEvent.h>
David@0
    32
#import <Adium/AIListContact.h>
David@0
    33
#import <Adium/AIHTMLDecoder.h>
David@0
    34
#import <Adium/AIService.h>
David@0
    35
#import <Adium/JVFontPreviewField.h>
David@0
    36
#import <AIUtilities/AIAttributedStringAdditions.h>
David@0
    37
#import <AIUtilities/AIColorAdditions.h>
David@0
    38
#import <AIUtilities/AIFontAdditions.h>
David@0
    39
#import <AIUtilities/AIMenuAdditions.h>
David@0
    40
#import <AIUtilities/AIPopUpButtonAdditions.h>
David@0
    41
#import <AIUtilities/AIBundleAdditions.h>
David@0
    42
#import <AIUtilities/AIDateFormatterAdditions.h>
David@0
    43
#import <AIUtilities/AIImageAdditions.h>
David@0
    44
#import <AIUtilities/AIImageViewWithImagePicker.h>
David@0
    45
David@0
    46
#import "AIPreviewContentMessage.h"
David@0
    47
David@0
    48
#define WEBKIT_PREVIEW_CONVERSATION_FILE	@"Preview"
David@0
    49
#define	PREF_GROUP_DISPLAYFORMAT			@"Display Format"  //To watch when the contact name display format changes
David@0
    50
David@84
    51
@interface ESWebKitMessageViewPreferences ()
zacw@1205
    52
- (void)configurePreferencesForTab;
David@0
    53
- (void)_setBackgroundImage:(NSImage *)image;
David@0
    54
- (NSMenu *)_stylesMenu;
David@0
    55
- (NSMenu *)_variantsMenu;
David@0
    56
- (NSMenu *)_backgroundImageTypeMenu;
David@0
    57
- (void)_addBackgroundImageTypeChoice:(NSInteger)tag toMenu:(NSMenu *)menu withTitle:(NSString *)title;
David@0
    58
- (void)_configureChatPreview;
David@0
    59
- (AIChat *)previewChatWithDictionary:(NSDictionary *)previewDict fromPath:(NSString *)previewPath listObjects:(NSDictionary **)outListObjects;
David@0
    60
- (void)_fillContentOfChat:(AIChat *)inChat withDictionary:(NSDictionary *)previewDict fromPath:(NSString *)previewPath listObjects:(NSDictionary *)listObjects;
David@0
    61
- (NSMutableDictionary *)_addParticipants:(NSDictionary *)participants toChat:(AIChat *)inChat fromPath:(NSString *)previewPath;
David@0
    62
- (void)_applySettings:(NSDictionary *)chatDict toChat:(AIPreviewChat *)inChat withParticipants:(NSDictionary *)participants;
David@0
    63
- (void)_addContent:(NSArray *)chatArray toChat:(AIChat *)inChat withParticipants:(NSDictionary *)participants;
David@0
    64
- (void)_setDisplayFontFace:(NSString *)face size:(NSNumber *)size;
David@0
    65
@end
David@0
    66
David@0
    67
@class AIPreviewChat;
David@0
    68
David@0
    69
@implementation ESWebKitMessageViewPreferences
David@0
    70
David@0
    71
- (NSString *)paneIdentifier
David@0
    72
{
David@0
    73
	return @"Messages";
David@0
    74
}
David@0
    75
- (NSString *)paneName{
David@0
    76
	return AILocalizedString(@"Messages", "Title of the messages preferences");
David@0
    77
}
David@0
    78
- (NSString *)nibName{
David@0
    79
    return @"WebKitPreferencesView";
David@0
    80
}
David@0
    81
- (NSImage *)paneIcon
David@0
    82
{
David@0
    83
	return [NSImage imageNamed:@"pref-messages"];
David@0
    84
}
David@0
    85
David@0
    86
/*!
David@0
    87
 * @brief Configure the preference view
David@0
    88
 */
David@0
    89
- (void)viewDidLoad
David@0
    90
{
David@0
    91
	viewIsOpen = YES;
David@0
    92
	previewListObjectsDict = nil;
David@0
    93
David@0
    94
	//Configure our menus
David@0
    95
	[popUp_backgroundImageType setMenu:[self _backgroundImageTypeMenu]];
David@0
    96
	[popUp_styles setMenu:[self _stylesMenu]];
David@0
    97
	
David@0
    98
	//Other controls
David@0
    99
	[fontPreviewField_currentFont setShowFontFace:YES];
David@0
   100
	[fontPreviewField_currentFont setShowPointSize:YES];
David@0
   101
David@0
   102
	//We want to be able to obtain bigger images than the image picker will feed us
David@0
   103
	[imageView_backgroundImage setUsePictureTaker:NO];
David@0
   104
		
David@0
   105
	//Configure the chat preview
David@0
   106
	[self _configureChatPreview];
zacw@1217
   107
	
zacw@1217
   108
	[tabView_messageType selectTabViewItem:tabViewItem_regularChat];
David@0
   109
zacw@1205
   110
	[self configurePreferencesForTab];
David@0
   111
}
David@0
   112
David@0
   113
/*!
David@0
   114
 * @brief Close the preference view
David@0
   115
 */
David@0
   116
- (void)viewWillClose
David@0
   117
{
David@0
   118
	//Hide the alpha component
David@0
   119
	[[NSColorPanel sharedColorPanel] setShowsAlpha:NO];
David@0
   120
David@1109
   121
	[[NSNotificationCenter defaultCenter] removeObserver:self];
David@0
   122
	[previewListObjectsDict release]; previewListObjectsDict = nil;
David@0
   123
David@0
   124
	[previewController release]; previewController = nil;
David@0
   125
	[view_previewLocation setFrame:[preview frame]];
David@0
   126
	[[preview superview] replaceSubview:preview with:view_previewLocation];	
David@0
   127
	[preview release]; preview = nil;
David@0
   128
	//Matches the retain performed in -[ESWebKitMessageViewPreferences _configureChatPreview]
David@0
   129
	[view_previewLocation release];
David@0
   130
David@0
   131
	viewIsOpen = NO;
David@0
   132
}
David@0
   133
David@0
   134
- (void)messageStyleXtrasDidChange
David@0
   135
{
David@0
   136
	if (viewIsOpen) {
zacw@1205
   137
		NSDictionary *prefDict = [adium.preferenceController preferencesForGroup:self.preferenceGroupForCurrentTab];
David@0
   138
		
David@0
   139
		[popUp_styles setMenu:[self _stylesMenu]];
David@0
   140
		[popUp_styles selectItemWithRepresentedObject:[prefDict objectForKey:KEY_WEBKIT_STYLE]];
David@0
   141
	}
David@0
   142
}
David@0
   143
David@0
   144
//Preferences ----------------------------------------------------------------------------------------------------------
David@0
   145
#pragma mark Preferences
zacw@1205
   146
- (AIWebkitStyleType)currentTab
zacw@1205
   147
{
zacw@1205
   148
	if (tabView_messageType.selectedTabViewItem == tabViewItem_regularChat) {
zacw@1205
   149
		return AIWebkitRegularChat;
zacw@1205
   150
	} else {
zacw@1205
   151
		return AIWebkitGroupChat;
zacw@1205
   152
	}
zacw@1205
   153
}
zacw@1205
   154
zacw@1205
   155
- (NSString *)preferenceGroupForCurrentTab
zacw@1205
   156
{
zacw@1205
   157
	NSString *prefGroup = nil;
zacw@1205
   158
	
zacw@1205
   159
	switch(self.currentTab) {
zacw@1205
   160
		case AIWebkitRegularChat:
zacw@1205
   161
			prefGroup = PREF_GROUP_WEBKIT_REGULAR_MESSAGE_DISPLAY;
zacw@1205
   162
			break;
zacw@1205
   163
			
zacw@1205
   164
		case AIWebkitGroupChat:
zacw@1205
   165
			prefGroup = PREF_GROUP_WEBKIT_GROUP_MESSAGE_DISPLAY;
zacw@1205
   166
			break;		
zacw@1205
   167
	}
zacw@1205
   168
	
zacw@1205
   169
	return prefGroup;
zacw@1205
   170
}
zacw@1205
   171
zacw@1205
   172
- (void)configurePreferencesForTab
zacw@1205
   173
{
zacw@1205
   174
	//Configure our controls to represent the global preferences
zacw@1205
   175
zacw@1205
   176
	NSDictionary *prefDict = [adium.preferenceController preferencesForGroup:self.preferenceGroupForCurrentTab];
zacw@1205
   177
	
zacw@1205
   178
	[checkBox_showUserIcons setState:([[previewController messageStyle] allowsUserIcons] ?
zacw@1205
   179
									  [[prefDict objectForKey:KEY_WEBKIT_SHOW_USER_ICONS] boolValue] :
zacw@1205
   180
									  NSOffState)];
zacw@1205
   181
	[checkBox_showHeader setState:[[prefDict objectForKey:KEY_WEBKIT_SHOW_HEADER] boolValue]];
zacw@1205
   182
	[checkBox_showMessageColors setState:([[previewController messageStyle] allowsColors] ?
zacw@1205
   183
										  [[prefDict objectForKey:KEY_WEBKIT_SHOW_MESSAGE_COLORS] boolValue] :
zacw@1205
   184
										  NSOffState)];
zacw@1205
   185
	[checkBox_showMessageFonts setState:[[prefDict objectForKey:KEY_WEBKIT_SHOW_MESSAGE_FONTS] boolValue]];
zacw@1205
   186
	
zacw@1210
   187
	[checkBox_useRegularChatForGroup setState:[[adium.preferenceController preferenceForKey:KEY_WEBKIT_USE_REGULAR_PREFERENCES
zacw@1212
   188
																					  group:self.preferenceGroupForCurrentTab] boolValue]];
zacw@1210
   189
	
zacw@1205
   190
	//Allow the alpha component to be set for our background color
zacw@1205
   191
	[[NSColorPanel sharedColorPanel] setShowsAlpha:YES];
zacw@1205
   192
	
zacw@1205
   193
	[previewController setIsGroupChat:(self.currentTab == AIWebkitGroupChat)];
zacw@1210
   194
	
zacw@1210
   195
	// The preview controller will send us a preferences changed message also.
zacw@1210
   196
	[previewController preferencesChangedForGroup:self.preferenceGroupForCurrentTab
zacw@1213
   197
											  key:nil
zacw@1210
   198
										   object:nil
zacw@1210
   199
								   preferenceDict:[adium.preferenceController preferencesForGroup:self.preferenceGroupForCurrentTab]
zacw@1210
   200
										firstTime:NO];
zacw@1205
   201
}
zacw@1205
   202
zacw@1205
   203
- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
zacw@1205
   204
{
zacw@1205
   205
	[self configurePreferencesForTab];
zacw@1205
   206
}
zacw@1205
   207
David@0
   208
/*!
David@0
   209
 * @brief Update our preference view to reflect changed preferences
David@0
   210
 */
David@0
   211
- (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key object:(AIListObject *)object
David@0
   212
					preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
David@0
   213
{
David@0
   214
	if (!viewIsOpen) return;
David@0
   215
zacw@1205
   216
	if ([group isEqualToString:self.preferenceGroupForCurrentTab]) {
David@0
   217
		NSString	*style;
David@0
   218
		NSString	*variant;
David@0
   219
David@0
   220
		//Ensure our style/variant menus are showing the correct selection
David@0
   221
		style = [prefDict objectForKey:KEY_WEBKIT_STYLE];
David@0
   222
		if (!style || ![popUp_styles selectItemWithRepresentedObject:style]) {
David@0
   223
			style = [[plugin messageStyleBundleWithIdentifier:style] bundleIdentifier];
David@0
   224
			[popUp_styles selectItemWithRepresentedObject:style];
David@0
   225
		}
David@0
   226
David@0
   227
		//When the active style changes, rebuild our variant menu for the new style
David@0
   228
		if (!key || [key isEqualToString:KEY_WEBKIT_STYLE]) {
David@0
   229
			[popUp_variants setMenu:[self _variantsMenu]];
David@0
   230
		}
David@0
   231
David@0
   232
		variant = [prefDict objectForKey:[plugin styleSpecificKey:@"Variant" forStyle:style]];
David@0
   233
		if (!variant || ![popUp_variants selectItemWithRepresentedObject:variant]) {
David@0
   234
			variant = [AIWebkitMessageViewStyle defaultVariantForBundle:[plugin messageStyleBundleWithIdentifier:style]];
David@0
   235
			[popUp_variants selectItemWithRepresentedObject:variant];
David@0
   236
		}
David@0
   237
		
zacw@1216
   238
		[popUp_variants synchronizeTitleAndSelectedItem];
zacw@1216
   239
		
David@0
   240
		//Configure our style-specific controls to represent the current style
David@0
   241
		NSString	*fontFamily = [prefDict objectForKey:[plugin styleSpecificKey:@"FontFamily" forStyle:style]];
David@0
   242
		if (!fontFamily) fontFamily = [[plugin messageStyleBundleWithIdentifier:style] objectForInfoDictionaryKey:KEY_WEBKIT_DEFAULT_FONT_FAMILY];
David@0
   243
		if (!fontFamily) fontFamily = [[NSFont systemFontOfSize:0] familyName];
David@0
   244
		
David@0
   245
		NSNumber	*fontSize = [prefDict objectForKey:[plugin styleSpecificKey:@"FontSize" forStyle:style]];
David@0
   246
		if (!fontSize) fontSize = [[plugin messageStyleBundleWithIdentifier:style] objectForInfoDictionaryKey:KEY_WEBKIT_DEFAULT_FONT_SIZE];
David@0
   247
		if (!fontSize) fontSize = [NSNumber numberWithInteger:[[NSFont systemFontOfSize:0] pointSize]];
David@0
   248
David@0
   249
		NSFont	*defaultFont = [NSFont cachedFontWithName:fontFamily size:[fontSize integerValue]];
David@0
   250
		[fontPreviewField_currentFont setFont:defaultFont];
David@0
   251
David@0
   252
		//Style-specific background prefs
David@95
   253
		NSData	*backgroundImage = [adium.preferenceController preferenceForKey:[plugin styleSpecificKey:@"Background" forStyle:style]
David@0
   254
																		   group:PREF_GROUP_WEBKIT_BACKGROUND_IMAGES];
David@0
   255
		if (backgroundImage) {
David@0
   256
			[imageView_backgroundImage setImage:[[[NSImage alloc] initWithData:backgroundImage] autorelease]];
David@0
   257
		} else {
David@0
   258
			[imageView_backgroundImage setImage:nil];
David@0
   259
		}
David@0
   260
David@0
   261
		NSColor	*backgroundColor = [[prefDict objectForKey:[plugin styleSpecificKey:@"BackgroundColor" forStyle:style]] representedColor];
David@0
   262
		[colorWell_customBackgroundColor setColor:(backgroundColor ? backgroundColor : [NSColor whiteColor])] ;
David@0
   263
David@0
   264
		[checkBox_useCustomBackground setState:[[prefDict objectForKey:[plugin styleSpecificKey:@"UseCustomBackground" forStyle:style]] boolValue]];
David@413
   265
		[popUp_backgroundImageType selectItemWithTag:[[prefDict objectForKey:[plugin styleSpecificKey:@"BackgroundType" forStyle:style]] integerValue]];
zacw@1207
   266
		
zacw@1207
   267
		[self configureControlDimming];
David@0
   268
	}
David@0
   269
}
David@0
   270
David@0
   271
/*!
David@0
   272
 * @brief Save changed preferences
David@0
   273
 */
David@0
   274
- (IBAction)changePreference:(id)sender
David@0
   275
{
David@0
   276
	if (viewIsOpen) {
David@0
   277
		if (sender == checkBox_showUserIcons) {
David@95
   278
			[adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
David@0
   279
												 forKey:KEY_WEBKIT_SHOW_USER_ICONS
zacw@1205
   280
												  group:self.preferenceGroupForCurrentTab];
David@0
   281
			
David@0
   282
		} else if (sender == checkBox_showHeader) {
David@95
   283
			[adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
David@0
   284
												 forKey:KEY_WEBKIT_SHOW_HEADER
zacw@1205
   285
												  group:self.preferenceGroupForCurrentTab];
David@0
   286
			
David@0
   287
		} else if (sender == checkBox_showMessageColors) {
David@95
   288
			[adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
David@0
   289
												 forKey:KEY_WEBKIT_SHOW_MESSAGE_COLORS
zacw@1205
   290
												  group:self.preferenceGroupForCurrentTab];
David@0
   291
			
David@0
   292
		} else if (sender == checkBox_showMessageFonts) {
David@95
   293
			[adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
David@0
   294
												 forKey:KEY_WEBKIT_SHOW_MESSAGE_FONTS
zacw@1205
   295
												  group:self.preferenceGroupForCurrentTab];
David@0
   296
		} else if (sender == checkBox_useCustomBackground) {
David@95
   297
			[adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
David@0
   298
												 forKey:[plugin styleSpecificKey:@"UseCustomBackground" 
David@0
   299
																		forStyle:[[popUp_styles selectedItem] representedObject]]
zacw@1205
   300
												  group:self.preferenceGroupForCurrentTab];
zacw@1210
   301
		} else if (sender == checkBox_useRegularChatForGroup) {
zacw@1210
   302
			[adium.preferenceController setPreference:[NSNumber numberWithBool:[sender state]]
zacw@1210
   303
												 forKey:KEY_WEBKIT_USE_REGULAR_PREFERENCES
zacw@1212
   304
												  group:self.preferenceGroupForCurrentTab];		
David@0
   305
			
zacw@1210
   306
			[self configurePreferencesForTab];
David@0
   307
		} else if (sender == colorWell_customBackgroundColor) {
David@95
   308
			[adium.preferenceController setPreference:[[colorWell_customBackgroundColor color] stringRepresentation]
David@0
   309
												 forKey:[plugin styleSpecificKey:@"BackgroundColor"
David@0
   310
																		forStyle:[[popUp_styles selectedItem] representedObject]]
zacw@1205
   311
												  group:self.preferenceGroupForCurrentTab];
David@0
   312
			
David@0
   313
		} else if (sender == popUp_backgroundImageType) {
David@95
   314
			[adium.preferenceController setPreference:[NSNumber numberWithInteger:[[popUp_backgroundImageType selectedItem] tag]]
David@0
   315
												 forKey:[plugin styleSpecificKey:@"BackgroundType"
David@0
   316
																		forStyle:[[popUp_styles selectedItem] representedObject]]
zacw@1205
   317
												  group:self.preferenceGroupForCurrentTab];	
David@0
   318
			
David@0
   319
		} else if (sender == popUp_styles) {
David@95
   320
			[adium.preferenceController setPreference:[[sender selectedItem] representedObject]
David@0
   321
												 forKey:KEY_WEBKIT_STYLE
zacw@1205
   322
												  group:self.preferenceGroupForCurrentTab];
David@0
   323
			
David@0
   324
		} else if (sender == popUp_variants) {
David@95
   325
			NSString *activeStyle = [adium.preferenceController preferenceForKey:KEY_WEBKIT_STYLE
zacw@1205
   326
																		   group:self.preferenceGroupForCurrentTab];
David@0
   327
			
David@95
   328
			[adium.preferenceController setPreference:[[sender selectedItem] representedObject]
David@0
   329
												 forKey:[plugin styleSpecificKey:@"Variant" forStyle:activeStyle]
zacw@1205
   330
												  group:self.preferenceGroupForCurrentTab];
David@0
   331
		}
David@0
   332
		
David@0
   333
		[self configureControlDimming];
David@0
   334
	}
David@0
   335
}
David@0
   336
David@0
   337
- (void)configureControlDimming
zacw@1210
   338
{	
zacw@1214
   339
	// Controls are enabled if we're the regular chat tab, or we're not using regular preferences.
zacw@1214
   340
	BOOL anyControlsEnabled = (self.currentTab == AIWebkitRegularChat || ![[adium.preferenceController preferenceForKey:KEY_WEBKIT_USE_REGULAR_PREFERENCES
zacw@1214
   341
																			group:self.preferenceGroupForCurrentTab] boolValue]);
zacw@1214
   342
	
zacw@1214
   343
	// General controls with no other qualifiers.
zacw@1214
   344
	[popUp_styles setEnabled:anyControlsEnabled];
zacw@1214
   345
	[fontPreviewField_currentFont setEnabled:anyControlsEnabled];
zacw@1214
   346
	[checkBox_showMessageFonts setEnabled:anyControlsEnabled];
zacw@1214
   347
	[checkBox_showMessageColors setEnabled:anyControlsEnabled];
zacw@1214
   348
	[button_setFont setEnabled:anyControlsEnabled];
zacw@1214
   349
	[button_defaultFont setEnabled:anyControlsEnabled];
zacw@1214
   350
	
zacw@1214
   351
	//Only enable if there are multiple variant choices
zacw@1214
   352
	[popUp_variants setEnabled:[popUp_variants numberOfItems] > 0 && anyControlsEnabled];
zacw@1214
   353
	
zacw@1214
   354
	//Disable the custom background controls if the style doesn't support them
Peter@1642
   355
	AIWebkitMessageViewStyle *messageStyle = [previewController messageStyle];
Peter@1642
   356
	BOOL	allowCustomBackground = [messageStyle allowsCustomBackground] && anyControlsEnabled;
zacw@1214
   357
	[checkBox_useCustomBackground setEnabled:allowCustomBackground];
zacw@1215
   358
	
zacw@1215
   359
	allowCustomBackground = allowCustomBackground && checkBox_useCustomBackground.state;
zacw@1215
   360
	
zacw@1214
   361
	[colorWell_customBackgroundColor setEnabled:allowCustomBackground];
zacw@1214
   362
	[popUp_backgroundImageType setEnabled:allowCustomBackground];
zacw@1214
   363
	[imageView_backgroundImage setEnabled:allowCustomBackground];
zacw@1214
   364
	
zacw@1641
   365
	//Disable the header control if this style doesn't have a header or topic
wixardy@2910
   366
	if (self.currentTab == AIWebkitGroupChat)
wixardy@2910
   367
		[checkBox_showHeader setEnabled:[messageStyle hasTopic] && anyControlsEnabled];
wixardy@2910
   368
	else
wixardy@2910
   369
		[checkBox_showHeader setEnabled:[messageStyle hasHeader] && anyControlsEnabled];
zacw@1214
   370
	
zacw@1214
   371
	//Disable user icon toggling if the style doesn't support them
Peter@1642
   372
	[checkBox_showUserIcons setEnabled:[messageStyle allowsUserIcons] && anyControlsEnabled];
zacw@1214
   373
	
Peter@1642
   374
	[checkBox_showMessageColors setEnabled:[messageStyle allowsColors] && anyControlsEnabled];
David@0
   375
}
David@0
   376
David@0
   377
/*!
David@0
   378
 * @brief Save changes to the font field
David@0
   379
 */
David@0
   380
- (void)fontPreviewField:(JVFontPreviewField *)field didChangeToFont:(NSFont *)font
David@0
   381
{
David@0
   382
	[self _setDisplayFontFace:[font fontName] size:[NSNumber numberWithInteger:[font pointSize]]];
David@0
   383
}
David@0
   384
David@0
   385
- (IBAction)resetDisplayFontToDefault:(id)sender
David@0
   386
{
David@0
   387
	[self _setDisplayFontFace:nil size:0];
David@0
   388
}
David@0
   389
David@0
   390
/*!
David@0
   391
 * @brief Set the display font of the active style.
David@0
   392
 *
David@0
   393
 * @param face New font face, nil to remove custom font
David@0
   394
 * @param size New font size, nil to remove custom size
David@0
   395
 */
David@0
   396
- (void)_setDisplayFontFace:(NSString *)face size:(NSNumber *)size
David@0
   397
{
David@95
   398
	NSString *activeStyle = [adium.preferenceController preferenceForKey:KEY_WEBKIT_STYLE
zacw@1205
   399
																	group:self.preferenceGroupForCurrentTab];
David@0
   400
	
David@95
   401
	[adium.preferenceController setPreference:face
David@0
   402
										 forKey:[plugin styleSpecificKey:@"FontFamily" forStyle:activeStyle]
zacw@1205
   403
										  group:self.preferenceGroupForCurrentTab];
David@95
   404
	[adium.preferenceController setPreference:size
David@0
   405
										 forKey:[plugin styleSpecificKey:@"FontSize" forStyle:activeStyle]
zacw@1205
   406
										  group:self.preferenceGroupForCurrentTab];
David@0
   407
	
David@0
   408
}
David@0
   409
David@0
   410
/*!
David@0
   411
 * @brief Save changes to the background image
David@0
   412
 */
David@0
   413
- (void)imageViewWithImagePicker:(AIImageViewWithImagePicker *)picker didChangeToImage:(NSImage *)image
David@0
   414
{
David@0
   415
	[self _setBackgroundImage:image];
David@0
   416
}
David@0
   417
David@0
   418
/*!
David@0
   419
 * @brief Remove the background image
David@0
   420
 */
David@0
   421
- (void)deleteInImageViewWithImagePicker:(AIImageViewWithImagePicker *)picker
David@0
   422
{
David@0
   423
	[self _setBackgroundImage:nil];
David@0
   424
}
David@0
   425
David@0
   426
/*!
David@0
   427
 * @brief Set the background image of the active style.
David@0
   428
 *
David@0
   429
 * @param image New background image, nil to remove background image
David@0
   430
 */
David@0
   431
- (void)_setBackgroundImage:(NSImage *)image
David@0
   432
{
David@0
   433
	NSString	*style = [[popUp_styles selectedItem] representedObject];
David@0
   434
David@0
   435
	/* Save the new image.  We store the images in a separate preference group since they may get big.
David@0
   436
	 * This will let loading other groups not be affected by its presence.
David@0
   437
	 */
David@95
   438
	[adium.preferenceController setPreference:[image PNGRepresentation]
David@0
   439
										 forKey:[plugin styleSpecificKey:@"Background" forStyle:style]
David@0
   440
										  group:PREF_GROUP_WEBKIT_BACKGROUND_IMAGES];
David@0
   441
}
David@0
   442
David@0
   443
/*!
David@0
   444
 * @brief Builds and returns a menu of available styles
David@0
   445
 */
David@0
   446
- (NSMenu *)_stylesMenu
David@0
   447
{
David@0
   448
	NSMenu			*menu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@""];
David@0
   449
	NSMutableArray	*menuItemArray = [NSMutableArray array];
David@0
   450
	NSArray			*availableStyles = [[plugin availableMessageStyles] allValues];
David@0
   451
	NSMenuItem		*menuItem;
David@0
   452
	
David@75
   453
	for (NSBundle *style in availableStyles) {
David@0
   454
		menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[style name]
David@0
   455
																		target:nil
David@0
   456
																		action:nil
David@0
   457
																 keyEquivalent:@""];
David@0
   458
		[menuItem setRepresentedObject:[style bundleIdentifier]];
David@0
   459
		[menuItemArray addObject:menuItem];
David@0
   460
		[menuItem release];
David@0
   461
	}
David@0
   462
	
David@0
   463
	[menuItemArray sortUsingSelector:@selector(titleCompare:)];
David@0
   464
	
David@75
   465
	for (menuItem in menuItemArray) {
David@0
   466
		[menu addItem:menuItem];
David@0
   467
	}
David@0
   468
	
David@0
   469
	return [menu autorelease];
David@0
   470
}
David@0
   471
David@0
   472
/*! 
David@0
   473
 * @brief Build & return a menu of variants for the passed style
David@0
   474
 */
David@0
   475
- (NSMenu *)_variantsMenu
David@0
   476
{
David@0
   477
	NSMenu			*menu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@""];
David@0
   478
David@0
   479
	//Add a menu item for each variant
Evan@166
   480
	for (NSString *variant in previewController.messageStyle.availableVariants) {
David@0
   481
		[menu addItemWithTitle:variant
David@0
   482
						target:nil
David@0
   483
						action:nil
David@0
   484
				 keyEquivalent:@""
David@0
   485
			 representedObject:variant];
David@0
   486
	}
David@0
   487
David@0
   488
	return [menu autorelease];
David@0
   489
}
David@0
   490
David@0
   491
/*!
David@0
   492
 * @brief Build & return a menu of choices for background display
David@0
   493
 */
David@0
   494
- (NSMenu *)_backgroundImageTypeMenu
David@0
   495
{
David@0
   496
	NSMenu	*menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];	
David@0
   497
David@0
   498
	[self _addBackgroundImageTypeChoice:BackgroundNormal toMenu:menu withTitle:AILocalizedString(@"Normal","Background image display preference: The image will be displayed normally")];
David@0
   499
	[self _addBackgroundImageTypeChoice:BackgroundCenter toMenu:menu withTitle:AILocalizedString(@"Centered","Background image display preference: The image will be centered in the window")];
David@0
   500
	[self _addBackgroundImageTypeChoice:BackgroundTile toMenu:menu withTitle:AILocalizedString(@"Tiled","Background image display preference: The image will be tiled (repeated) in the window to fill available space")];
David@0
   501
	[self _addBackgroundImageTypeChoice:BackgroundTileCenter toMenu:menu withTitle:AILocalizedString(@"Tiled (Centered)","Background image display preference: The image will be tiled and centered in the window")];
David@0
   502
	[self _addBackgroundImageTypeChoice:BackgroundScale toMenu:menu withTitle:AILocalizedString(@"Scaled", "Background image display preference: The image will be increased or decreased in size to fit the window")];
David@0
   503
			
David@0
   504
	return [menu autorelease];
David@0
   505
}
David@0
   506
- (void)_addBackgroundImageTypeChoice:(NSInteger)tag toMenu:(NSMenu *)menu withTitle:(NSString *)title
David@0
   507
{
David@0
   508
	NSMenuItem	*menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:title
David@0
   509
																				 action:nil
David@0
   510
																		  keyEquivalent:@""];
David@0
   511
	[menuItem setTag:tag];
David@0
   512
	[menu addItem:menuItem];
David@0
   513
	[menuItem release];
David@0
   514
}
David@0
   515
David@0
   516
David@0
   517
//Chat Preview ---------------------------------------------------------------------------------------------------------
David@0
   518
#pragma mark Chat Preview
David@0
   519
/*!
David@0
   520
 * @brief Configure our chat preview
David@0
   521
 */
David@0
   522
- (void)_configureChatPreview
David@0
   523
{
David@0
   524
	NSDictionary	*previewDict;
David@0
   525
	NSString		*previewFilePath;
David@0
   526
	NSString		*previewPath;
David@0
   527
	AIChat			*previewChat;
David@0
   528
David@0
   529
	//Create our fake chat and message controller for the live preview
David@0
   530
	previewFilePath = [[NSBundle bundleForClass:[self class]] pathForResource:WEBKIT_PREVIEW_CONVERSATION_FILE ofType:@"plist"];
David@0
   531
	previewDict = [[NSDictionary alloc] initWithContentsOfFile:previewFilePath];
David@0
   532
	previewPath = [previewFilePath stringByDeletingLastPathComponent];
David@0
   533
	
David@0
   534
	NSDictionary *listObjects;
David@0
   535
	previewChat = [self previewChatWithDictionary:previewDict fromPath:previewPath listObjects:&listObjects];
David@0
   536
	previewController = [[AIWebKitPreviewMessageViewController messageDisplayControllerForChat:previewChat
David@0
   537
																					withPlugin:plugin] retain];
David@0
   538
David@0
   539
	//Enable live refreshing of our preview
David@0
   540
	[previewController setShouldReflectPreferenceChanges:YES];	
David@0
   541
	[previewController setPreferencesChangedDelegate:self];
David@0
   542
	
David@0
   543
	//Add fake users and content to our chat
David@0
   544
	[self _fillContentOfChat:previewChat withDictionary:previewDict fromPath:previewPath listObjects:listObjects];
David@0
   545
	[previewDict release];
David@0
   546
	
David@0
   547
	//Place the preview chat in our view
David@0
   548
	preview = [[previewController messageView] retain];
David@0
   549
	[preview setFrame:[view_previewLocation frame]];
David@0
   550
	//Will be released in viewWillClose
David@0
   551
	[view_previewLocation retain];
David@0
   552
	[[view_previewLocation superview] replaceSubview:view_previewLocation with:preview];
David@0
   553
David@0
   554
	//Disable drag and drop onto the preview chat - Jeff doesn't need your porn :)
David@0
   555
	if ([preview respondsToSelector:@selector(setAllowsDragAndDrop:)]) {
David@0
   556
		[(ESWebView *)preview setAllowsDragAndDrop:NO];
David@0
   557
	}
David@0
   558
David@0
   559
	//Disable forwarding of events so the preferences responder chain works properly
David@0
   560
	if ([preview respondsToSelector:@selector(setShouldForwardEvents:)]) {
David@0
   561
		[(ESWebView *)preview setShouldForwardEvents:NO];		
David@0
   562
	}	
David@0
   563
}
David@0
   564
David@0
   565
- (AIChat *)previewChatWithDictionary:(NSDictionary *)previewDict fromPath:(NSString *)previewPath listObjects:(NSDictionary **)outListObjects
David@0
   566
{
David@0
   567
	AIPreviewChat *previewChat = [AIPreviewChat previewChat];
David@0
   568
	[previewChat setDisplayName:AILocalizedString(@"Sample Conversation", "Title for the sample conversation")];
David@0
   569
David@0
   570
	//Process and create all participants
David@0
   571
	*outListObjects = [self _addParticipants:[previewDict objectForKey:@"Participants"]
David@0
   572
									  toChat:previewChat fromPath:previewPath];
David@0
   573
David@0
   574
	//Setup the chat, and its source/destination
David@0
   575
	[self _applySettings:[previewDict objectForKey:@"Chat"]
David@0
   576
				  toChat:previewChat withParticipants:*outListObjects];
David@0
   577
	
David@0
   578
	return previewChat;
David@0
   579
}
David@0
   580
David@0
   581
/*!
David@0
   582
 * @brief Fill the content of the specified chat using content archived in the dictionary
David@0
   583
 */
David@0
   584
- (void)_fillContentOfChat:(AIChat *)inChat withDictionary:(NSDictionary *)previewDict fromPath:(NSString *)previewPath listObjects:(NSDictionary *)listObjects
David@0
   585
{
David@0
   586
	//Add the archived chat content
David@0
   587
	[self _addContent:[previewDict objectForKey:@"Preview Messages"]
David@0
   588
			   toChat:inChat withParticipants:listObjects];
David@0
   589
}
David@0
   590
David@0
   591
/*!
David@0
   592
 * @brief Add participants
David@0
   593
 */
David@0
   594
- (NSMutableDictionary *)_addParticipants:(NSDictionary *)participants toChat:(AIChat *)inChat fromPath:(NSString *)previewPath
David@0
   595
{
David@0
   596
	NSMutableDictionary	*listObjectDict = [NSMutableDictionary dictionary];
David@95
   597
	AIService			*aimService = [adium.accountController firstServiceWithServiceID:@"AIM"];
David@0
   598
	
Evan@166
   599
	for (NSDictionary *participant in participants) {
David@0
   600
		NSString		*UID, *alias, *userIconName;
David@0
   601
		AIListContact	*listContact;
David@0
   602
		
David@0
   603
		//Create object
David@0
   604
		UID = [participant objectForKey:@"UID"];
David@0
   605
		listContact = [[AIListContact alloc] initWithUID:UID service:aimService];
David@0
   606
		
David@0
   607
		//Display name
David@0
   608
		if ((alias = [participant objectForKey:@"Display Name"])) {
David@1109
   609
			[[NSNotificationCenter defaultCenter] postNotificationName:Contact_ApplyDisplayName
David@0
   610
													  object:listContact
David@0
   611
													userInfo:[NSDictionary dictionaryWithObject:alias forKey:@"Alias"]];
David@0
   612
		}
David@0
   613
		
David@0
   614
		//User icon
David@0
   615
		if ((userIconName = [participant objectForKey:@"UserIcon Name"])) {
David@0
   616
			[listContact setValue:[previewPath stringByAppendingPathComponent:userIconName]
David@0
   617
								  forProperty:@"UserIconPath"
David@0
   618
								  notify:YES];
David@0
   619
		}
David@0
   620
		
David@0
   621
		[listObjectDict setObject:listContact forKey:UID];
David@0
   622
		[listContact release];
David@0
   623
	}
David@0
   624
	
David@0
   625
	return listObjectDict;
David@0
   626
}
David@0
   627
David@0
   628
/*!
David@0
   629
 * @brief Chat settings
David@0
   630
 */
David@0
   631
- (void)_applySettings:(NSDictionary *)chatDict toChat:(AIPreviewChat *)inChat withParticipants:(NSDictionary *)participants
David@0
   632
{
David@0
   633
	NSString			*dateOpened, *type, *name, *UID;
David@0
   634
	
David@0
   635
	//Date opened
David@0
   636
	if ((dateOpened = [chatDict objectForKey:@"Date Opened"])) {
David@0
   637
		[inChat setDateOpened:[NSDate dateWithNaturalLanguageString:dateOpened]];
David@0
   638
	}
David@0
   639
	
David@0
   640
	//Source/Destination
David@0
   641
	type = [chatDict objectForKey:@"Type"];
David@0
   642
	if ([type isEqualToString:@"IM"]) {
David@0
   643
		if ((UID = [chatDict objectForKey:@"Destination UID"])) {
David@950
   644
			[inChat addParticipatingListObject:[participants objectForKey:UID] notify:YES];
David@0
   645
		}
David@0
   646
		if ((UID = [chatDict objectForKey:@"Source UID"])) {
David@0
   647
			[inChat setAccount:(AIAccount *)[participants objectForKey:UID]];
David@0
   648
		}
David@0
   649
	} else {
David@0
   650
		if ((name = [chatDict objectForKey:@"Name"])) {
David@0
   651
			[inChat setName:name];
David@0
   652
		}
David@0
   653
	}
David@0
   654
	
David@0
   655
	//We don't want the interface controller to try to open this fake chat
David@0
   656
	[inChat setIsOpen:YES];
David@0
   657
}
David@0
   658
David@0
   659
/*!
David@0
   660
 * @brief Chat content
David@0
   661
 */
David@0
   662
- (void)_addContent:(NSArray *)chatArray toChat:(AIChat *)inChat withParticipants:(NSDictionary *)participants
David@0
   663
{
David@0
   664
	NSDictionary		*messageDict;
David@0
   665
	
David@75
   666
	for (messageDict in chatArray) {
David@0
   667
		AIContentObject		*content = nil;
David@0
   668
		AIListObject		*source;
David@0
   669
		NSString			*from, *msgType;
David@0
   670
		NSAttributedString  *message;
David@0
   671
		
David@0
   672
		msgType = [messageDict objectForKey:@"Type"];
David@0
   673
		from = [messageDict objectForKey:@"From"];
David@0
   674
David@0
   675
		source = (from ? [participants objectForKey:from] : nil);
David@0
   676
David@0
   677
		if ([msgType isEqualToString:CONTENT_MESSAGE_TYPE]) {
David@0
   678
			//Create message content object
David@0
   679
			AIListObject		*dest;
David@0
   680
			NSString			*to;
David@0
   681
			BOOL				outgoing;
David@0
   682
David@0
   683
			message = [AIHTMLDecoder decodeHTML:[messageDict objectForKey:@"Message"]];
David@0
   684
			to = [messageDict objectForKey:@"To"];
David@0
   685
			outgoing = [[messageDict objectForKey:@"Outgoing"] boolValue];
David@0
   686
David@0
   687
			//The other person is always the one we're chatting with right now
David@0
   688
			dest = [participants objectForKey:to];
David@0
   689
			content = [AIPreviewContentMessage messageInChat:inChat
David@0
   690
												  withSource:source
David@0
   691
												 destination:dest
David@0
   692
														date:[NSDate dateWithNaturalLanguageString:[messageDict objectForKey:@"Date"]]
David@0
   693
													 message:message
David@0
   694
												   autoreply:[[messageDict objectForKey:@"Autoreply"] boolValue]];
David@0
   695
David@0
   696
			//AIContentMessage won't know whether the message is outgoing unless we tell it since neither our source
David@0
   697
			//nor our destination are AIAccount objects.
David@0
   698
			[(AIPreviewContentMessage *)content setIsOutgoing:outgoing];
David@0
   699
David@0
   700
		} else if ([msgType isEqualToString:CONTENT_STATUS_TYPE]) {
David@0
   701
			//Create status content object
David@0
   702
			NSString			*statusMessageType;
David@0
   703
			
David@0
   704
			message = [AIHTMLDecoder decodeHTML:[messageDict objectForKey:@"Message"]];
David@0
   705
			statusMessageType = [messageDict objectForKey:@"Status Message Type"];
David@0
   706
			
David@0
   707
			//Create our content object
zacw@1305
   708
			content = [AIContentEvent eventInChat:inChat
zacw@1305
   709
									   withSource:source
zacw@1305
   710
									  destination:nil
zacw@1305
   711
											 date:[NSDate dateWithNaturalLanguageString:[messageDict objectForKey:@"Date"]]
zacw@1305
   712
										  message:message
zacw@1305
   713
										 withType:statusMessageType];
David@0
   714
		}
David@0
   715
David@0
   716
		if (content) {			
David@0
   717
			[content setTrackContent:NO];
David@0
   718
			[content setPostProcessContent:NO];
David@0
   719
			[content setDisplayContentImmediately:NO];
David@0
   720
			
David@95
   721
			[adium.contentController displayContentObject:content
David@0
   722
										usingContentFilters:YES
David@0
   723
												immediately:YES];
David@0
   724
		}
David@0
   725
	}
David@0
   726
David@0
   727
	//We finished adding untracked content
David@1109
   728
	[[NSNotificationCenter defaultCenter] postNotificationName:Content_ChatDidFinishAddingUntrackedContent
David@0
   729
											  object:inChat];
David@0
   730
}
David@0
   731
David@0
   732
@end