Fixed a bunch of unit tests to restore state after they complete.
[adiumx.git] / Source / AIAccountListPreferences.m
blobae9dfac99838ae971dc365bc2d1b87b13886fbe0
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
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.
8  * 
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.
12  * 
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.
15  */
17 #import <Adium/AIAccountControllerProtocol.h>
18 #import "AIAccountListPreferences.h"
19 #import <Adium/AIContactControllerProtocol.h>
20 #import "AIStatusController.h"
21 #import "AIEditAccountWindowController.h"
22 #import <AIUtilities/AIAutoScrollView.h>
23 #import <AIUtilities/AIImageTextCell.h>
24 #import <AIUtilities/AIVerticallyCenteredTextCell.h>
25 #import <AIUtilities/AITableViewAdditions.h>
26 #import <AIUtilities/AIImageAdditions.h>
27 #import <AIUtilities/AIMutableStringAdditions.h>
28 #import <Adium/AIAccount.h>
29 #import <Adium/AIListObject.h>
30 #import <Adium/AIService.h>
31 #import <Adium/AIServiceIcons.h>
32 #import <Adium/AIServiceMenu.h>
33 #import <Adium/AIStatusIcons.h>
34 #import <AIUtilities/AIAttributedStringAdditions.h>
35 #import "KFTypeSelectTableView.h"
37 #define MINIMUM_ROW_HEIGHT                              34
38 #define MINIMUM_CELL_SPACING                     4
40 #define ACCOUNT_DRAG_TYPE                               @"AIAccount"                            //ID for an account drag
42 #define NEW_ACCOUNT_DISPLAY_TEXT                AILocalizedString(@"<New Account>", "Placeholder displayed as the name of a new account")
44 @interface AIAccountListPreferences (PRIVATE)
45 - (void)configureAccountList;
46 - (void)accountListChanged:(NSNotification *)notification;
48 - (void)calculateHeightForRow:(int)row;
49 - (void)calculateAllHeights;
50 @end
52 /*!
53  * @class AIAccountListPreferences
54  * @brief Shows a list of accounts and provides for management of them
55  */
56 @implementation AIAccountListPreferences
58 /*!
59  * @brief Preference pane properties
60  */
61 - (NSString *)paneIdentifier
63         return @"Accounts";
65 - (NSString *)paneName{
66     return AILocalizedString(@"Accounts","Accounts preferences label");
68 - (NSString *)nibName{
69     return @"AccountListPreferences";
71 - (NSImage *)paneIcon
73         return [NSImage imageNamed:@"pref-accounts" forClass:[self class]];
76 /*!
77  * @brief Configure the view initially
78  */
79 - (void)viewDidLoad
81         //Configure the account list
82         [self configureAccountList];
83         [self updateAccountOverview];
84         
85         [requiredHeightDict release]; requiredHeightDict = [[NSMutableDictionary alloc] init];
86         
87         //Build the 'add account' menu of each available service
88         NSMenu  *serviceMenu = [AIServiceMenu menuOfServicesWithTarget:self 
89                                                                                                 activeServicesOnly:NO
90                                                                                                    longDescription:YES
91                                                                                                                         format:AILocalizedString(@"%@",nil)];
92         [serviceMenu setAutoenablesItems:YES];
93         
94         //Indent each item in the service menu one level
95         NSEnumerator    *enumerator = [[serviceMenu itemArray] objectEnumerator];
96         NSMenuItem              *menuItem;
97         while ((menuItem = [enumerator nextObject])) {
98                 [menuItem setIndentationLevel:[menuItem indentationLevel]+1];
99         }
101         //Add a label to the top of the menu to clarify why we're showing this list of services
102         [serviceMenu insertItemWithTitle:AILocalizedString(@"Add an account for:",nil)
103                                                           action:NULL
104                                            keyEquivalent:@""
105                                                          atIndex:0];
106         
107         //Assign the menu
108         [button_newAccount setMenu:serviceMenu];
110         //Observe status icon pack changes
111         [[adium notificationCenter] addObserver:self
112                                                                    selector:@selector(iconPackDidChange:)
113                                                                            name:AIStatusIconSetDidChangeNotification
114                                                                          object:nil];
115         
116         //Observe service icon pack changes
117         [[adium notificationCenter] addObserver:self
118                                                                    selector:@selector(iconPackDidChange:)
119                                                                            name:AIServiceIconSetDidChangeNotification
120                                                                          object:nil];
124  * @brief Perform actions before the view closes
125  */
126 - (void)viewWillClose
128         [[adium contactController] unregisterListObjectObserver:self];
129         [[adium notificationCenter] removeObserver:self];
130         
131         [accountArray release]; accountArray = nil;
132         [requiredHeightDict release]; requiredHeightDict = nil;
135 - (void)dealloc
137         [accountArray release];
139         [super dealloc];
143  * @brief Account status changed.
145  * Disable the service menu and user name field for connected accounts
146  */
147 - (NSSet *)updateListObject:(AIListObject *)inObject keys:(NSSet *)inModifiedKeys silent:(BOOL)silent
149         if ([inObject isKindOfClass:[AIAccount class]]) {
150                 if ([inModifiedKeys containsObject:@"Online"] ||
151                         [inModifiedKeys containsObject:@"Enabled"] ||
152                    [inModifiedKeys containsObject:@"Connecting"] ||
153                    [inModifiedKeys containsObject:@"Waiting to Reconnect"] ||
154                    [inModifiedKeys containsObject:@"Disconnecting"] ||
155                    [inModifiedKeys containsObject:@"ConnectionProgressString"] ||
156                    [inModifiedKeys containsObject:@"ConnectionProgressPercent"] ||
157                    [inModifiedKeys containsObject:@"IdleSince"] ||
158                    [inModifiedKeys containsObject:@"StatusState"]) {
160                         //Refresh this account in our list
161                         int accountRow = [accountArray indexOfObject:inObject];
162                         if (accountRow >= 0 && accountRow < [accountArray count]) {
163                                 [tableView_accountList setNeedsDisplayInRect:[tableView_accountList rectOfRow:accountRow]];
164                                 // Update the height of the row.
165                                 [self calculateHeightForRow:accountRow];
166                                 [tableView_accountList noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndex:accountRow]];
167                         }
168                         
169                         //Update our account overview
170                         [self updateAccountOverview];
171                 }
172         }
173     
174     return nil;
177 //Actions --------------------------------------------------------------------------------------------------------------
178 #pragma mark Actions
180  * @brief Create a new account
182  * Called when a service type is selected from the Add menu
183  */
184 - (IBAction)selectServiceType:(id)sender
186         AIService       *service = [sender representedObject];
187         AIAccount       *account = [[adium accountController] createAccountWithService:service
188                                                                                                                                                    UID:[service defaultUserName]];
190         [AIEditAccountWindowController editAccount:account
191                                                                           onWindow:[[self view] window]
192                                                            notifyingTarget:self];
195 - (void)editAccount:(AIAccount *)inAccount
197         [AIEditAccountWindowController editAccount:inAccount
198                                                                           onWindow:[[self view] window]
199                                                            notifyingTarget:self];       
203  * @brief Edit the currently selected account using <tt>AIEditAccountWindowController</tt>
204  */
205 - (IBAction)editSelectedAccount:(id)sender
207     int selectedRow = [tableView_accountList selectedRow];
208         if (selectedRow >= 0 && selectedRow < [accountArray count]) {
209                 [self editAccount:[accountArray objectAtIndex:selectedRow]];
210     }
214  * @brief Handle a double click within our table
216  * Ignore double clicks on the enable/disable checkbox
217  */
218 - (void)doubleClickInTableView:(id)sender
220         if (!(NSPointInRect([tableView_accountList convertPoint:[[NSApp currentEvent] locationInWindow] fromView:nil],
221                                                 [tableView_accountList rectOfColumn:[tableView_accountList columnWithIdentifier:@"enabled"]]))) {
222                 [self editSelectedAccount:sender];
223         }
227  * @brief Editing of an account completed
228  */
229 - (void)editAccountSheetDidEndForAccount:(AIAccount *)inAccount withSuccess:(BOOL)successful
231         BOOL existingAccount = ([[[adium accountController] accounts] containsObject:inAccount]);
232         
233         if (!existingAccount && successful) {
234                 //New accounts need to be added to our account list once they're configured
235                 [[adium accountController] addAccount:inAccount];
237                 //Scroll the new account visible so that the user can see we added it
238                 [tableView_accountList scrollRowToVisible:[accountArray indexOfObject:inAccount]];
239                 
240                 //Put new accounts online by default
241                 [inAccount setPreference:[NSNumber numberWithBool:YES] forKey:@"Online" group:GROUP_ACCOUNT_STATUS];
242         }
246  * @brief Delete the selected account
248  * Prompts for confirmation first
249  */
250 - (IBAction)deleteAccount:(id)sender
252     int index = [tableView_accountList selectedRow];
254     if (index >= 0 && index < [accountArray count])
255                 [[[adium accountController] deleteAccount:[accountArray objectAtIndex:index]] beginSheetModalForWindow:[[self view] window]];
258 //Account List ---------------------------------------------------------------------------------------------------------
259 #pragma mark Account List
261  * @brief Configure the account list table
262  */
263 - (void)configureAccountList
265     AIImageTextCell             *cell;
266         NSRect                          oldFrame, newFrame;
267         
268         //Setup our edit button, keeping its right side in the same location
269         oldFrame = [button_editAccount frame];
270         [button_editAccount setTitle:AILocalizedStringFromTable(@"Edit", @"Buttons", "Verb 'edit' on a button")];
271         [button_editAccount sizeToFit];
272         newFrame = [button_editAccount frame];
273         if (newFrame.size.width < oldFrame.size.width) newFrame.size.width = oldFrame.size.width;
274         newFrame.origin.x = oldFrame.origin.x + oldFrame.size.width - newFrame.size.width;
275         [button_editAccount setFrame:newFrame];
277         //Configure our table view
278         [tableView_accountList setTarget:self];
279         [tableView_accountList setDoubleAction:@selector(doubleClickInTableView:)];
280         [tableView_accountList setIntercellSpacing:NSMakeSize(MINIMUM_CELL_SPACING, MINIMUM_CELL_SPACING)];
282         //Enable dragging of accounts
283         [tableView_accountList registerForDraggedTypes:[NSArray arrayWithObjects:ACCOUNT_DRAG_TYPE,nil]];
284         
285     //Custom vertically-centered text cell for account names
286     cell = [[AIImageTextCell alloc] init];
287     [cell setFont:[NSFont boldSystemFontOfSize:13]];
288     [[tableView_accountList tableColumnWithIdentifier:@"name"] setDataCell:cell];
289         [cell setLineBreakMode:NSLineBreakByWordWrapping];
290         [cell release];
292     cell = [[AIVerticallyCenteredTextCell alloc] init];
293     [cell setFont:[NSFont systemFontOfSize:13]];
294     [cell setAlignment:NSRightTextAlignment];
295     [[tableView_accountList tableColumnWithIdentifier:@"status"] setDataCell:cell];
296         [cell release];
297     
298         [tableView_accountList sizeToFit];
300         //Observe changes to the account list
301     [[adium notificationCenter] addObserver:self
302                                                                    selector:@selector(accountListChanged:) 
303                                                                            name:Account_ListChanged 
304                                                                          object:nil];
305         [self accountListChanged:nil];
306         
307         //Observe accounts so we can display accurate status
308     [[adium contactController] registerListObjectObserver:self];
312  * @brief Account list changed, refresh our table
313  */
314 - (void)accountListChanged:(NSNotification *)notification
316     //Update our list of accounts
317     [accountArray release];
318         accountArray = [[[adium accountController] accounts] retain];
320         //Refresh the account table
321         [tableView_accountList reloadData];
322         [self updateControlAvailability];
323         [self updateAccountOverview];
324         [self calculateAllHeights];
328  * @brief Status icons changed, refresh our table
329  */
330 - (void)iconPackDidChange:(NSNotification *)notification
332         [tableView_accountList reloadData];
336  * @brief Update our account overview
338  * The overview indicates the total number of accounts and the number which are online.
339  */
340 - (void)updateAccountOverview
342         NSString        *accountOverview;
343         int                     accountArrayCount = [accountArray count];
345         if (accountArrayCount == 0) {
346                 accountOverview = AILocalizedString(@"Click the + to add a new account","Instructions on how to add an account when none are present");
348         } else {
349                 NSEnumerator    *enumerator = [accountArray objectEnumerator];
350                 AIAccount               *account;
351                 int                             online = 0, enabled = 0;
352                 
353                 //Count online accounts
354                 while ((account = [enumerator nextObject])) {
355                         if ([account online]) online++;
356                         if ([account enabled]) enabled++;
357                 }
358                 
359                 if (enabled) {
360                         if ((accountArrayCount == enabled) ||
361                                 (online == enabled)){
362                                 accountOverview = [NSString stringWithFormat:AILocalizedString(@"%i accounts, %i online","Overview of total and online accounts"),
363                                         accountArrayCount,
364                                         online];
365                         } else {
366                                 accountOverview = [NSString stringWithFormat:AILocalizedString(@"%i accounts, %i enabled, %i online","Overview of total, enabled, and online accounts"),
367                                         accountArrayCount,
368                                         enabled,
369                                         online];                        
370                         }
371                 } else {
372                         accountOverview = AILocalizedString(@"Check a box to enable an account","Instructions for enabling an account");
373                 }
374         }
376         [textField_overview setStringValue:accountOverview];
380  * @brief Update control availability based on list selection
381  */
382 - (void)updateControlAvailability
384         BOOL    selection = ([tableView_accountList selectedRow] != -1);
386         [button_editAccount setEnabled:selection];
387         [button_deleteAccount setEnabled:selection];
391 * @brief Returns the status string associated with the account
393  * Returns a connection status if connecting, or an error if disconnected with an error
394  */
395 - (NSString *)statusMessageForAccount:(AIAccount *)account
397         NSString *statusMessage = nil;
398         
399         if ([account statusObjectForKey:@"ConnectionProgressString"] && [[account statusObjectForKey:@"Connecting"] boolValue]) {
400                 // Connection status if we're currently connecting, with the percent at the end
401                 statusMessage = [[account statusObjectForKey:@"ConnectionProgressString"] stringByAppendingFormat:@" (%2.f%%)", [[account statusObjectForKey:@"ConnectionProgressPercent"] floatValue]*100.0];
402         } else if ([account lastDisconnectionError] && ![[account statusObjectForKey:@"Online"] boolValue] && ![[account statusObjectForKey:@"Connecting"] boolValue]) {
403                 // If there's an error and we're not online and not connecting
404                 NSMutableString *returnedMessage = [[[account lastDisconnectionError] mutableCopy] autorelease];
405                 
406                 // Replace the LibPurple error prefix
407                 [returnedMessage replaceOccurrencesOfString:@"Could not establish a connection with the server:\n"
408                                                                                  withString:@"Error: "
409                                                                                         options:NSLiteralSearch
410                                                                                           range:NSMakeRange(0, [returnedMessage length])];
411                 // Remove newlines from the error message
412                 [returnedMessage convertNewlinesToSlashes];
413                 
414                 statusMessage = returnedMessage;
415         }
416         
417         return statusMessage;
421 * @brief Calculates the height of a given row and stores it
422  */
423 - (void)calculateHeightForRow:(int)row
424 {       
425         // Make sure this is a valid row.
426         if (row < 0 || row >= [accountArray count]) {
427                 return;
428         }
429         
430         AIAccount               *account = [accountArray objectAtIndex:row];
431         float                   necessaryHeight = MINIMUM_ROW_HEIGHT;
432         
433         // If there's a status message, let's try size to fit it.
434         if ([self statusMessageForAccount:account]) {
435                 NSTableColumn           *tableColumn = [tableView_accountList tableColumnWithIdentifier:@"name"];
436                 
437                 [self tableView:tableView_accountList willDisplayCell:[tableColumn dataCell] forTableColumn:tableColumn row:row];
438                 
439                 // Main string (account name)
440                 NSDictionary            *mainStringAttributes   = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont boldSystemFontOfSize:13], NSFontAttributeName, nil];
441                 NSAttributedString      *mainTitle = [[NSAttributedString alloc] initWithString:([[account formattedUID] length] ? [account formattedUID] : NEW_ACCOUNT_DISPLAY_TEXT)
442                                                                                                                                                  attributes:mainStringAttributes];
443                 
444                 // Substring (the status message)
445                 NSDictionary            *subStringAttributes    = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont systemFontOfSize:10], NSFontAttributeName, nil];
446                 NSAttributedString      *subStringTitle = [[NSAttributedString alloc] initWithString:[self statusMessageForAccount:account]
447                                                                                                                                                           attributes:subStringAttributes];
448                 
449                 // Both heights combined, with spacing in-between
450                 float combinedHeight = [mainTitle heightWithWidth:[tableColumn width]] + [subStringTitle heightWithWidth:[tableColumn width]] + MINIMUM_CELL_SPACING;
451                 
452                 // Make sure we're not down-sizing
453                 if (combinedHeight > necessaryHeight) {
454                         necessaryHeight = combinedHeight;
455                 }
456                 
457                 [subStringTitle release];
458                 [mainTitle release];
459         }
460         
461         // Cache the height value
462         [requiredHeightDict setObject:[NSNumber numberWithFloat:necessaryHeight]
463                                                    forKey:[NSNumber numberWithInt:row]];
467 * @brief Calculates the height of all rows
468  */
469 - (void)calculateAllHeights
471         int accountNumber;
473         [requiredHeightDict removeAllObjects];
475         for (accountNumber = 0; accountNumber < [accountArray count]; accountNumber++) {
476                 [self calculateHeightForRow:accountNumber];
477         }
481 //Account List Table Delegate ------------------------------------------------------------------------------------------
482 #pragma mark Account List (Table Delegate)
484  * @brief Delete the selected row
485  */
486 - (void)tableViewDeleteSelectedRows:(NSTableView *)tableView
488     [self deleteAccount:nil];
492  * @brief Number of rows in the table
493  */
494 - (int)numberOfRowsInTableView:(NSTableView *)tableView
496         return [accountArray count];
500  * @brief Table values
501  */
502 - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
504         if (row < 0 || row >= [accountArray count]) {
505                 return nil;
506         }
507         
508         NSString        *identifier = [tableColumn identifier];
509         AIAccount       *account = [accountArray objectAtIndex:row];
510         
511         if ([identifier isEqualToString:@"service"]) {
512                 return [[AIServiceIcons serviceIconForObject:account
513                                                                                                 type:AIServiceIconLarge
514                                                                                    direction:AIIconNormal] imageByScalingToSize:NSMakeSize(MINIMUM_ROW_HEIGHT-2, MINIMUM_ROW_HEIGHT-2)
515                                                                                                                                                            fraction:([account enabled] ?
516                                                                                                                                                                                  1.0 :
517                                                                                                                                                                                  0.75)];
519         } else if ([identifier isEqualToString:@"name"]) {
520                 return [[account formattedUID] length] ? [account formattedUID] : NEW_ACCOUNT_DISPLAY_TEXT;
521                 
522         } else if ([identifier isEqualToString:@"status"]) {
523                 NSString        *title;
524                 
525                 if ([account enabled]) {
526                         if ([[account statusObjectForKey:@"Connecting"] boolValue]) {
527                                 title = AILocalizedString(@"Connecting",nil);
528                         } else if ([[account statusObjectForKey:@"Disconnecting"] boolValue]) {
529                                 title = AILocalizedString(@"Disconnecting",nil);
530                         } else if ([[account statusObjectForKey:@"Online"] boolValue]) {
531                                 title = AILocalizedString(@"Online",nil);
532                         } else if ([account statusObjectForKey:@"Waiting to Reconnect"]) {
533                                 title = AILocalizedString(@"Reconnecting", @"Used when the account will perform an automatic reconnection after a certain period of time.");
534                         } else {
535                                 title = [[adium statusController] localizedDescriptionForCoreStatusName:STATUS_NAME_OFFLINE];
536                         }
538                 } else {
539                         title = AILocalizedString(@"Disabled",nil);
540                 }
542                 return title;
543                 
544         } else if ([identifier isEqualToString:@"statusicon"]) {
546                 return [AIStatusIcons statusIconForListObject:account type:AIStatusIconList direction:AIIconNormal];
547                 
548         } else if ([identifier isEqualToString:@"enabled"]) {
549                 return nil;
551         }
553         return nil;
556  * @brief Configure the height of each account for error messages if necessary
557  */
558 - (float)tableView:(NSTableView *)tableView heightOfRow:(int)row
560         // We should probably have this value cached.
561         float necessaryHeight = MINIMUM_ROW_HEIGHT;
562         
563         NSNumber *cachedHeight = [requiredHeightDict objectForKey:[NSNumber numberWithInt:row]];
564         if (cachedHeight) {
565                 necessaryHeight = [cachedHeight floatValue];
566         }
567         
568         return necessaryHeight;
572  * @brief Configure cells before display
573  */
574 - (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row
576         // Make sure this row actually exists
577         if (row < 0 || row >= [accountArray count]) {
578                 return;
579         }
581         NSString        *identifier = [tableColumn identifier];
582         AIAccount       *account = [accountArray objectAtIndex:row];
583         
584         if ([identifier isEqualToString:@"enabled"]) {
585                 [cell setState:([account enabled] ? NSOnState : NSOffState)];
587         } else if ([identifier isEqualToString:@"name"]) {
588                 [cell setEnabled:[account enabled]];
590                 // Update the subString with our current status message (if it exists);
591                 [cell setSubString:[self statusMessageForAccount:account]];
592                 
593         } else if ([identifier isEqualToString:@"status"]) {
594                 [cell setEnabled:([[account statusObjectForKey:@"Connecting"] boolValue] ||
595                                                   [account statusObjectForKey:@"Waiting to Reconnect"] ||
596                                                   [[account statusObjectForKey:@"Disconnecting"] boolValue] ||
597                                                   [[account statusObjectForKey:@"Online"] boolValue])];
598         }
599         
603  * @brief Handle a clicked active/inactive checkbox
605  * Checking the box both takes the account online and sets it to autoconnect. Unchecking it does the opposite.
606  */
607 - (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
609         if (row >= 0 && row < [accountArray count] && [[tableColumn identifier] isEqualToString:@"enabled"]) {
610                 [[accountArray objectAtIndex:row] setEnabled:[(NSNumber *)object boolValue]];
611         }
615  * @brief Drag start
616  */
617 - (BOOL)tableView:(NSTableView *)tv writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard
619     tempDragAccount = [accountArray objectAtIndex:[[rows objectAtIndex:0] intValue]];
620         
621     [pboard declareTypes:[NSArray arrayWithObject:ACCOUNT_DRAG_TYPE] owner:self];
622     [pboard setString:@"Account" forType:ACCOUNT_DRAG_TYPE];
623     
624     return YES;
628  * @brief Drag validate
629  */
630 - (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op
632     if (op == NSTableViewDropAbove && row != -1) {
633         return NSDragOperationPrivate;
634     } else {
635         return NSDragOperationNone;
636     }
640  * @brief Drag complete
641  */
642 - (BOOL)tableView:(NSTableView*)tv acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)op
644     NSString    *avaliableType = [[info draggingPasteboard] availableTypeFromArray:[NSArray arrayWithObject:ACCOUNT_DRAG_TYPE]];
645         
646     if ([avaliableType isEqualToString:@"AIAccount"]) {
647         int newIndex = [[adium accountController] moveAccount:tempDragAccount toIndex:row];
648         [tableView_accountList selectRow:newIndex byExtendingSelection:NO];
649                 
650         return YES;
651     } else {
652         return NO;
653     }
657  * @brief Selection change
658  */
659 - (void)tableViewSelectionDidChange:(NSNotification *)notification
661         [self updateControlAvailability];
665  * @brief Set up KFTypeSelectTableView
667  * Only search the "name" column.
668  */
669 - (void)configureTypeSelectTableView:(KFTypeSelectTableView *)tableView
671     [tableView setSearchColumnIdentifiers:[NSSet setWithObject:@"name"]];
674 @end