Plugins/WebKit Message View/ESWebKitMessageViewPreferences.m
author Frank Dowsett <wixardy@adium.im>
Tue Mar 16 22:14:34 2010 -0400 (2010-03-16)
changeset 3158 d7fe2ee7d9b1
parent 3157 3629989a40f9
child 4021 f5412548f2f3
permissions -rw-r--r--
Enable the header control when there's a topic or a header and "Use regular chat style settings" is enabled. Fixes #13791
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.
wixardy@3158
   340
	BOOL useRegularPreferences = [[adium.preferenceController preferenceForKey:KEY_WEBKIT_USE_REGULAR_PREFERENCES
wixardy@3158
   341
																		 group:PREF_GROUP_WEBKIT_GROUP_MESSAGE_DISPLAY] boolValue];
wixardy@3158
   342
	BOOL anyControlsEnabled = (self.currentTab == AIWebkitRegularChat || !useRegularPreferences);
zacw@1214
   343
	
zacw@1214
   344
	// General controls with no other qualifiers.
zacw@1214
   345
	[popUp_styles setEnabled:anyControlsEnabled];
zacw@1214
   346
	[fontPreviewField_currentFont setEnabled:anyControlsEnabled];
zacw@1214
   347
	[checkBox_showMessageFonts setEnabled:anyControlsEnabled];
zacw@1214
   348
	[checkBox_showMessageColors setEnabled:anyControlsEnabled];
zacw@1214
   349
	[button_setFont setEnabled:anyControlsEnabled];
zacw@1214
   350
	[button_defaultFont setEnabled:anyControlsEnabled];
zacw@1214
   351
	
zacw@1214
   352
	//Only enable if there are multiple variant choices
zacw@1214
   353
	[popUp_variants setEnabled:[popUp_variants numberOfItems] > 0 && anyControlsEnabled];
zacw@1214
   354
	
zacw@1214
   355
	//Disable the custom background controls if the style doesn't support them
Peter@1642
   356
	AIWebkitMessageViewStyle *messageStyle = [previewController messageStyle];
Peter@1642
   357
	BOOL	allowCustomBackground = [messageStyle allowsCustomBackground] && anyControlsEnabled;
zacw@1214
   358
	[checkBox_useCustomBackground setEnabled:allowCustomBackground];
zacw@1215
   359
	
zacw@1215
   360
	allowCustomBackground = allowCustomBackground && checkBox_useCustomBackground.state;
zacw@1215
   361
	
zacw@1214
   362
	[colorWell_customBackgroundColor setEnabled:allowCustomBackground];
zacw@1214
   363
	[popUp_backgroundImageType setEnabled:allowCustomBackground];
zacw@1214
   364
	[imageView_backgroundImage setEnabled:allowCustomBackground];
zacw@1214
   365
	
zacw@1641
   366
	//Disable the header control if this style doesn't have a header or topic
wixardy@3157
   367
	if (self.currentTab == AIWebkitGroupChat)
wixardy@3157
   368
		[checkBox_showHeader setEnabled:[messageStyle hasTopic] && anyControlsEnabled];
wixardy@3157
   369
	else
wixardy@3158
   370
		[checkBox_showHeader setEnabled:[messageStyle hasHeader] || ([messageStyle hasTopic] && useRegularPreferences)];
zacw@1214
   371
	
zacw@1214
   372
	//Disable user icon toggling if the style doesn't support them
Peter@1642
   373
	[checkBox_showUserIcons setEnabled:[messageStyle allowsUserIcons] && anyControlsEnabled];
zacw@1214
   374
	
Peter@1642
   375
	[checkBox_showMessageColors setEnabled:[messageStyle allowsColors] && anyControlsEnabled];
David@0
   376
}
David@0
   377
David@0
   378
/*!
David@0
   379
 * @brief Save changes to the font field
David@0
   380
 */
David@0
   381
- (void)fontPreviewField:(JVFontPreviewField *)field didChangeToFont:(NSFont *)font
David@0
   382
{
David@0
   383
	[self _setDisplayFontFace:[font fontName] size:[NSNumber numberWithInteger:[font pointSize]]];
David@0
   384
}
David@0
   385
David@0
   386
- (IBAction)resetDisplayFontToDefault:(id)sender
David@0
   387
{
David@0
   388
	[self _setDisplayFontFace:nil size:0];
David@0
   389
}
David@0
   390
David@0
   391
/*!
David@0
   392
 * @brief Set the display font of the active style.
David@0
   393
 *
David@0
   394
 * @param face New font face, nil to remove custom font
David@0
   395
 * @param size New font size, nil to remove custom size
David@0
   396
 */
David@0
   397
- (void)_setDisplayFontFace:(NSString *)face size:(NSNumber *)size
David@0
   398
{
David@95
   399
	NSString *activeStyle = [adium.preferenceController preferenceForKey:KEY_WEBKIT_STYLE
zacw@1205
   400
																	group:self.preferenceGroupForCurrentTab];
David@0
   401
	
David@95
   402
	[adium.preferenceController setPreference:face
David@0
   403
										 forKey:[plugin styleSpecificKey:@"FontFamily" forStyle:activeStyle]
zacw@1205
   404
										  group:self.preferenceGroupForCurrentTab];
David@95
   405
	[adium.preferenceController setPreference:size
David@0
   406
										 forKey:[plugin styleSpecificKey:@"FontSize" forStyle:activeStyle]
zacw@1205
   407
										  group:self.preferenceGroupForCurrentTab];
David@0
   408
	
David@0
   409
}
David@0
   410
David@0
   411
/*!
David@0
   412
 * @brief Save changes to the background image
David@0
   413
 */
David@0
   414
- (void)imageViewWithImagePicker:(AIImageViewWithImagePicker *)picker didChangeToImage:(NSImage *)image
David@0
   415
{
David@0
   416
	[self _setBackgroundImage:image];
David@0
   417
}
David@0
   418
David@0
   419
/*!
David@0
   420
 * @brief Remove the background image
David@0
   421
 */
David@0
   422
- (void)deleteInImageViewWithImagePicker:(AIImageViewWithImagePicker *)picker
David@0
   423
{
David@0
   424
	[self _setBackgroundImage:nil];
David@0
   425
}
David@0
   426
David@0
   427
/*!
David@0
   428
 * @brief Set the background image of the active style.
David@0
   429
 *
David@0
   430
 * @param image New background image, nil to remove background image
David@0
   431
 */
David@0
   432
- (void)_setBackgroundImage:(NSImage *)image
David@0
   433
{
David@0
   434
	NSString	*style = [[popUp_styles selectedItem] representedObject];
David@0
   435
David@0
   436
	/* Save the new image.  We store the images in a separate preference group since they may get big.
David@0
   437
	 * This will let loading other groups not be affected by its presence.
David@0
   438
	 */
David@95
   439
	[adium.preferenceController setPreference:[image PNGRepresentation]
David@0
   440
										 forKey:[plugin styleSpecificKey:@"Background" forStyle:style]
David@0
   441
										  group:PREF_GROUP_WEBKIT_BACKGROUND_IMAGES];
David@0
   442
}
David@0
   443
David@0
   444
/*!
David@0
   445
 * @brief Builds and returns a menu of available styles
David@0
   446
 */
David@0
   447
- (NSMenu *)_stylesMenu
David@0
   448
{
David@0
   449
	NSMenu			*menu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@""];
David@0
   450
	NSMutableArray	*menuItemArray = [NSMutableArray array];
David@0
   451
	NSArray			*availableStyles = [[plugin availableMessageStyles] allValues];
David@0
   452
	NSMenuItem		*menuItem;
David@0
   453
	
David@75
   454
	for (NSBundle *style in availableStyles) {
David@0
   455
		menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[style name]
David@0
   456
																		target:nil
David@0
   457
																		action:nil
David@0
   458
																 keyEquivalent:@""];
David@0
   459
		[menuItem setRepresentedObject:[style bundleIdentifier]];
David@0
   460
		[menuItemArray addObject:menuItem];
David@0
   461
		[menuItem release];
David@0
   462
	}
David@0
   463
	
David@0
   464
	[menuItemArray sortUsingSelector:@selector(titleCompare:)];
David@0
   465
	
David@75
   466
	for (menuItem in menuItemArray) {
David@0
   467
		[menu addItem:menuItem];
David@0
   468
	}
David@0
   469
	
David@0
   470
	return [menu autorelease];
David@0
   471
}
David@0
   472
David@0
   473
/*! 
David@0
   474
 * @brief Build & return a menu of variants for the passed style
David@0
   475
 */
David@0
   476
- (NSMenu *)_variantsMenu
David@0
   477
{
David@0
   478
	NSMenu			*menu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@""];
David@0
   479
David@0
   480
	//Add a menu item for each variant
Evan@166
   481
	for (NSString *variant in previewController.messageStyle.availableVariants) {
David@0
   482
		[menu addItemWithTitle:variant
David@0
   483
						target:nil
David@0
   484
						action:nil
David@0
   485
				 keyEquivalent:@""
David@0
   486
			 representedObject:variant];
David@0
   487
	}
David@0
   488
David@0
   489
	return [menu autorelease];
David@0
   490
}
David@0
   491
David@0
   492
/*!
David@0
   493
 * @brief Build & return a menu of choices for background display
David@0
   494
 */
David@0
   495
- (NSMenu *)_backgroundImageTypeMenu
David@0
   496
{
David@0
   497
	NSMenu	*menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init];	
David@0
   498
David@0
   499
	[self _addBackgroundImageTypeChoice:BackgroundNormal toMenu:menu withTitle:AILocalizedString(@"Normal","Background image display preference: The image will be displayed normally")];
David@0
   500
	[self _addBackgroundImageTypeChoice:BackgroundCenter toMenu:menu withTitle:AILocalizedString(@"Centered","Background image display preference: The image will be centered in the window")];
David@0
   501
	[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
   502
	[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
   503
	[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
   504
			
David@0
   505
	return [menu autorelease];
David@0
   506
}
David@0
   507
- (void)_addBackgroundImageTypeChoice:(NSInteger)tag toMenu:(NSMenu *)menu withTitle:(NSString *)title
David@0
   508
{
David@0
   509
	NSMenuItem	*menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:title
David@0
   510
																				 action:nil
David@0
   511
																		  keyEquivalent:@""];
David@0
   512
	[menuItem setTag:tag];
David@0
   513
	[menu addItem:menuItem];
David@0
   514
	[menuItem release];
David@0
   515
}
David@0
   516
David@0
   517
David@0
   518
//Chat Preview ---------------------------------------------------------------------------------------------------------
David@0
   519
#pragma mark Chat Preview
David@0
   520
/*!
David@0
   521
 * @brief Configure our chat preview
David@0
   522
 */
David@0
   523
- (void)_configureChatPreview
David@0
   524
{
David@0
   525
	NSDictionary	*previewDict;
David@0
   526
	NSString		*previewFilePath;
David@0
   527
	NSString		*previewPath;
David@0
   528
	AIChat			*previewChat;
David@0
   529
David@0
   530
	//Create our fake chat and message controller for the live preview
David@0
   531
	previewFilePath = [[NSBundle bundleForClass:[self class]] pathForResource:WEBKIT_PREVIEW_CONVERSATION_FILE ofType:@"plist"];
David@0
   532
	previewDict = [[NSDictionary alloc] initWithContentsOfFile:previewFilePath];
David@0
   533
	previewPath = [previewFilePath stringByDeletingLastPathComponent];
David@0
   534
	
David@0
   535
	NSDictionary *listObjects;
David@0
   536
	previewChat = [self previewChatWithDictionary:previewDict fromPath:previewPath listObjects:&listObjects];
David@0
   537
	previewController = [[AIWebKitPreviewMessageViewController messageDisplayControllerForChat:previewChat
David@0
   538
																					withPlugin:plugin] retain];
David@0
   539
David@0
   540
	//Enable live refreshing of our preview
David@0
   541
	[previewController setShouldReflectPreferenceChanges:YES];	
David@0
   542
	[previewController setPreferencesChangedDelegate:self];
David@0
   543
	
David@0
   544
	//Add fake users and content to our chat
David@0
   545
	[self _fillContentOfChat:previewChat withDictionary:previewDict fromPath:previewPath listObjects:listObjects];
David@0
   546
	[previewDict release];
David@0
   547
	
David@0
   548
	//Place the preview chat in our view
David@0
   549
	preview = [[previewController messageView] retain];
David@0
   550
	[preview setFrame:[view_previewLocation frame]];
David@0
   551
	//Will be released in viewWillClose
David@0
   552
	[view_previewLocation retain];
David@0
   553
	[[view_previewLocation superview] replaceSubview:view_previewLocation with:preview];
David@0
   554
David@0
   555
	//Disable drag and drop onto the preview chat - Jeff doesn't need your porn :)
David@0
   556
	if ([preview respondsToSelector:@selector(setAllowsDragAndDrop:)]) {
David@0
   557
		[(ESWebView *)preview setAllowsDragAndDrop:NO];
David@0
   558
	}
David@0
   559
David@0
   560
	//Disable forwarding of events so the preferences responder chain works properly
David@0
   561
	if ([preview respondsToSelector:@selector(setShouldForwardEvents:)]) {
David@0
   562
		[(ESWebView *)preview setShouldForwardEvents:NO];		
David@0
   563
	}	
David@0
   564
}
David@0
   565
David@0
   566
- (AIChat *)previewChatWithDictionary:(NSDictionary *)previewDict fromPath:(NSString *)previewPath listObjects:(NSDictionary **)outListObjects
David@0
   567
{
David@0
   568
	AIPreviewChat *previewChat = [AIPreviewChat previewChat];
David@0
   569
	[previewChat setDisplayName:AILocalizedString(@"Sample Conversation", "Title for the sample conversation")];
David@0
   570
David@0
   571
	//Process and create all participants
David@0
   572
	*outListObjects = [self _addParticipants:[previewDict objectForKey:@"Participants"]
David@0
   573
									  toChat:previewChat fromPath:previewPath];
David@0
   574
David@0
   575
	//Setup the chat, and its source/destination
David@0
   576
	[self _applySettings:[previewDict objectForKey:@"Chat"]
David@0
   577
				  toChat:previewChat withParticipants:*outListObjects];
David@0
   578
	
David@0
   579
	return previewChat;
David@0
   580
}
David@0
   581
David@0
   582
/*!
David@0
   583
 * @brief Fill the content of the specified chat using content archived in the dictionary
David@0
   584
 */
David@0
   585
- (void)_fillContentOfChat:(AIChat *)inChat withDictionary:(NSDictionary *)previewDict fromPath:(NSString *)previewPath listObjects:(NSDictionary *)listObjects
David@0
   586
{
David@0
   587
	//Add the archived chat content
David@0
   588
	[self _addContent:[previewDict objectForKey:@"Preview Messages"]
David@0
   589
			   toChat:inChat withParticipants:listObjects];
David@0
   590
}
David@0
   591
David@0
   592
/*!
David@0
   593
 * @brief Add participants
David@0
   594
 */
David@0
   595
- (NSMutableDictionary *)_addParticipants:(NSDictionary *)participants toChat:(AIChat *)inChat fromPath:(NSString *)previewPath
David@0
   596
{
David@0
   597
	NSMutableDictionary	*listObjectDict = [NSMutableDictionary dictionary];
David@95
   598
	AIService			*aimService = [adium.accountController firstServiceWithServiceID:@"AIM"];
David@0
   599
	
Evan@166
   600
	for (NSDictionary *participant in participants) {
David@0
   601
		NSString		*UID, *alias, *userIconName;
David@0
   602
		AIListContact	*listContact;
David@0
   603
		
David@0
   604
		//Create object
David@0
   605
		UID = [participant objectForKey:@"UID"];
David@0
   606
		listContact = [[AIListContact alloc] initWithUID:UID service:aimService];
David@0
   607
		
David@0
   608
		//Display name
David@0
   609
		if ((alias = [participant objectForKey:@"Display Name"])) {
David@1109
   610
			[[NSNotificationCenter defaultCenter] postNotificationName:Contact_ApplyDisplayName
David@0
   611
													  object:listContact
David@0
   612
													userInfo:[NSDictionary dictionaryWithObject:alias forKey:@"Alias"]];
David@0
   613
		}
David@0
   614
		
David@0
   615
		//User icon
David@0
   616
		if ((userIconName = [participant objectForKey:@"UserIcon Name"])) {
David@0
   617
			[listContact setValue:[previewPath stringByAppendingPathComponent:userIconName]
David@0
   618
								  forProperty:@"UserIconPath"
David@0
   619
								  notify:YES];
David@0
   620
		}
David@0
   621
		
David@0
   622
		[listObjectDict setObject:listContact forKey:UID];
David@0
   623
		[listContact release];
David@0
   624
	}
David@0
   625
	
David@0
   626
	return listObjectDict;
David@0
   627
}
David@0
   628
David@0
   629
/*!
David@0
   630
 * @brief Chat settings
David@0
   631
 */
David@0
   632
- (void)_applySettings:(NSDictionary *)chatDict toChat:(AIPreviewChat *)inChat withParticipants:(NSDictionary *)participants
David@0
   633
{
David@0
   634
	NSString			*dateOpened, *type, *name, *UID;
David@0
   635
	
David@0
   636
	//Date opened
David@0
   637
	if ((dateOpened = [chatDict objectForKey:@"Date Opened"])) {
David@0
   638
		[inChat setDateOpened:[NSDate dateWithNaturalLanguageString:dateOpened]];
David@0
   639
	}
David@0
   640
	
David@0
   641
	//Source/Destination
David@0
   642
	type = [chatDict objectForKey:@"Type"];
David@0
   643
	if ([type isEqualToString:@"IM"]) {
David@0
   644
		if ((UID = [chatDict objectForKey:@"Destination UID"])) {
David@950
   645
			[inChat addParticipatingListObject:[participants objectForKey:UID] notify:YES];
David@0
   646
		}
David@0
   647
		if ((UID = [chatDict objectForKey:@"Source UID"])) {
David@0
   648
			[inChat setAccount:(AIAccount *)[participants objectForKey:UID]];
David@0
   649
		}
David@0
   650
	} else {
David@0
   651
		if ((name = [chatDict objectForKey:@"Name"])) {
David@0
   652
			[inChat setName:name];
David@0
   653
		}
David@0
   654
	}
David@0
   655
	
David@0
   656
	//We don't want the interface controller to try to open this fake chat
David@0
   657
	[inChat setIsOpen:YES];
David@0
   658
}
David@0
   659
David@0
   660
/*!
David@0
   661
 * @brief Chat content
David@0
   662
 */
David@0
   663
- (void)_addContent:(NSArray *)chatArray toChat:(AIChat *)inChat withParticipants:(NSDictionary *)participants
David@0
   664
{
David@0
   665
	NSDictionary		*messageDict;
David@0
   666
	
David@75
   667
	for (messageDict in chatArray) {
David@0
   668
		AIContentObject		*content = nil;
David@0
   669
		AIListObject		*source;
David@0
   670
		NSString			*from, *msgType;
David@0
   671
		NSAttributedString  *message;
David@0
   672
		
David@0
   673
		msgType = [messageDict objectForKey:@"Type"];
David@0
   674
		from = [messageDict objectForKey:@"From"];
David@0
   675
David@0
   676
		source = (from ? [participants objectForKey:from] : nil);
David@0
   677
David@0
   678
		if ([msgType isEqualToString:CONTENT_MESSAGE_TYPE]) {
David@0
   679
			//Create message content object
David@0
   680
			AIListObject		*dest;
David@0
   681
			NSString			*to;
David@0
   682
			BOOL				outgoing;
David@0
   683
David@0
   684
			message = [AIHTMLDecoder decodeHTML:[messageDict objectForKey:@"Message"]];
David@0
   685
			to = [messageDict objectForKey:@"To"];
David@0
   686
			outgoing = [[messageDict objectForKey:@"Outgoing"] boolValue];
David@0
   687
David@0
   688
			//The other person is always the one we're chatting with right now
David@0
   689
			dest = [participants objectForKey:to];
David@0
   690
			content = [AIPreviewContentMessage messageInChat:inChat
David@0
   691
												  withSource:source
David@0
   692
												 destination:dest
David@0
   693
														date:[NSDate dateWithNaturalLanguageString:[messageDict objectForKey:@"Date"]]
David@0
   694
													 message:message
David@0
   695
												   autoreply:[[messageDict objectForKey:@"Autoreply"] boolValue]];
David@0
   696
David@0
   697
			//AIContentMessage won't know whether the message is outgoing unless we tell it since neither our source
David@0
   698
			//nor our destination are AIAccount objects.
David@0
   699
			[(AIPreviewContentMessage *)content setIsOutgoing:outgoing];
David@0
   700
David@0
   701
		} else if ([msgType isEqualToString:CONTENT_STATUS_TYPE]) {
David@0
   702
			//Create status content object
David@0
   703
			NSString			*statusMessageType;
David@0
   704
			
David@0
   705
			message = [AIHTMLDecoder decodeHTML:[messageDict objectForKey:@"Message"]];
David@0
   706
			statusMessageType = [messageDict objectForKey:@"Status Message Type"];
David@0
   707
			
David@0
   708
			//Create our content object
zacw@1305
   709
			content = [AIContentEvent eventInChat:inChat
zacw@1305
   710
									   withSource:source
zacw@1305
   711
									  destination:nil
zacw@1305
   712
											 date:[NSDate dateWithNaturalLanguageString:[messageDict objectForKey:@"Date"]]
zacw@1305
   713
										  message:message
zacw@1305
   714
										 withType:statusMessageType];
David@0
   715
		}
David@0
   716
David@0
   717
		if (content) {			
David@0
   718
			[content setTrackContent:NO];
David@0
   719
			[content setPostProcessContent:NO];
David@0
   720
			[content setDisplayContentImmediately:NO];
David@0
   721
			
David@95
   722
			[adium.contentController displayContentObject:content
David@0
   723
										usingContentFilters:YES
David@0
   724
												immediately:YES];
David@0
   725
		}
David@0
   726
	}
David@0
   727
David@0
   728
	//We finished adding untracked content
David@1109
   729
	[[NSNotificationCenter defaultCenter] postNotificationName:Content_ChatDidFinishAddingUntrackedContent
David@0
   730
											  object:inChat];
David@0
   731
}
David@0
   732
David@0
   733
@end