adium/adium
Clone
Summary
Browse
Changes
Graph
Add a short delay to the contentAdded event, to ensure it's run after the content has been appended.
JSXtras
2013-04-16, Thijs Alkemade
30446d4b7b9f
Add a short delay to the contentAdded event, to ensure it's run after the content has been appended.
/*
* Adium is the legal property of its developers, whose names are listed in the copyright file included
* with this source distribution.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import "AINewMessagePromptController.h"
#import <Adium/AIChatControllerProtocol.h>
#import <Adium/AIInterfaceControllerProtocol.h>
#import <Adium/AIContactControllerProtocol.h>
#import <Adium/AIChatControllerProtocol.h>
#import <Adium/AIAccountControllerProtocol.h>
#import <Adium/AIInterfaceControllerProtocol.h>
#import <Adium/AIListContact.h>
#import "AIUserIcons.h"
#import "AIServiceIcons.h"
#import "AIStatusIcons.h"
#import "AIAttributedStringAdditions.h"
#import "AIImageDrawingAdditions.h"
#define NEW_MESSAGE_PROMPT_NIB @"NewMessagePrompt"
static
AINewMessagePromptController
*
sharedNewMessageInstance
=
nil
;
/*!
* @class AINewMessagePromptController
* @brief Controller for the New Message prompt, which allows messaging an arbitrary contact
*/
@implementation
AINewMessagePromptController
/*!
* @brief Return our shared instance
* @result The shared instance
*/
+
(
id
)
sharedInstance
{
if
(
!
sharedNewMessageInstance
)
[
self
createSharedInstance
];
return
sharedNewMessageInstance
;
}
/*!
* @brief Create the shared instance
* @result The shared instance
*/
+
(
id
)
createSharedInstance
{
sharedNewMessageInstance
=
[[
self
alloc
]
initWithWindowNibName
:
NEW_MESSAGE_PROMPT_NIB
];
return
sharedNewMessageInstance
;
}
/*!
* @brief Destroy the shared instance
*/
+
(
void
)
destroySharedInstance
{
[
sharedNewMessageInstance
autorelease
];
sharedNewMessageInstance
=
nil
;
}
-
(
void
)
dealloc
{
[
accountMenu
release
];
[
results
release
];
[
account
release
];
[
super
dealloc
];
}
/*!
* @brief Window did load
*/
-
(
void
)
windowDidLoad
{
[
super
windowDidLoad
];
[
button_okay
setLocalizedString
:
AILocalizedStringFromTable
(
@"Message"
,
@"Buttons"
,
"Button title to open a message window the specific contact from the 'New Chat' window"
)];
[
button_cancel
setLocalizedString
:
AILocalizedStringFromTable
(
@"Cancel"
,
@"Buttons"
,
nil
)];
[[
self
window
]
setTitle
:
AILocalizedString
(
@"New Message"
,
nil
)];
[
table_results
setDataSource
:
self
];
[
table_results
setDelegate
:
self
];
[
table_results
setDoubleAction
:
@selector
(
okay
:
)];
[
table_results
setTarget
:
self
];
[
label_account
setLocalizedString
:
AILocalizedString
(
@"Account:"
,
nil
)];
accountMenu
=
[[
AIAccountMenu
accountMenuWithDelegate
:
self
submenuType
:
AIAccountNoSubmenu
showTitleVerbs
:
NO
]
retain
];
}
/*!
* @brief Open a chat with the desired contact
*/
-
(
IBAction
)
okay:
(
id
)
sender
{
AIListContact
*
contact
;
if
(
account
&&
table_results
.
selectedRow
==
results
.
count
)
{
contact
=
[
adium
.
contactController
contactWithService
:
account
.
service
account
:
account
UID
:[
field_search
stringValue
]];
}
else
{
contact
=
[[
results
objectAtIndex
:
[
table_results
selectedRow
]]
objectForKey
:
@"Contact"
];
}
AIChat
*
chat
=
[
adium
.
chatController
chatWithContact
:
contact
];
[
adium
.
interfaceController
openChat
:
chat
];
[
adium
.
interfaceController
setActiveChat
:
chat
];
[
self
closeWindow
:
nil
];
}
-
(
void
)
windowWillClose:
(
id
)
sender
{
[
super
windowWillClose
:
sender
];
[
field_search
setStringValue
:
@""
];
[
results
release
];
results
=
nil
;
[
table_results
reloadData
];
[[
self
class
]
destroySharedInstance
];
}
-
(
NSString
*
)
lastAccountIDKey
{
return
@"NewMessagePrompt"
;
}
-
(
NSInteger
)
_string:
(
NSMutableAttributedString
*
)
astring
matchesQuery:
(
NSString
*
)
query
{
NSRange
matchRange
=
NSMakeRange
(
0
,
astring
.
length
);
NSInteger
i
;
NSInteger
score
=
0
;
for
(
i
=
0
;
i
<
query
.
length
;
i
++
)
{
NSString
*
chr
=
[
query
substringWithRange
:
NSMakeRange
(
i
,
1
)];
NSRange
newRange
=
[
astring
.
string
rangeOfString
:
chr
options
:
NSCaseInsensitiveSearch
|
NSDiacriticInsensitiveSearch
|
NSWidthInsensitiveSearch
range
:
matchRange
];
if
(
newRange
.
location
==
NSNotFound
)
return
NSNotFound
;
// Try to approximate Xcode's colors.
[
astring
addAttributes
:
[
NSDictionary
dictionaryWithObjectsAndKeys
:
[
NSNumber
numberWithInteger
:
NSUnderlineStyleSingle
],
NSUnderlineStyleAttributeName
,
[
NSColor
colorWithCalibratedRed
:
244.0f
/
255.0f
green
:
241.0f
/
255.0f
blue
:
197.0f
/
255.0f
alpha
:
1.0f
],
NSBackgroundColorAttributeName
,
[
NSColor
colorWithCalibratedRed
:
237.0
/
255.0f
green
:
204.0
/
255.0f
blue
:
0.0f
alpha
:
1.0f
],
NSUnderlineColorAttributeName
,
nil
]
range
:
newRange
];
score
+=
newRange
.
location
-
matchRange
.
location
;
matchRange
.
location
=
newRange
.
location
+
1
;
matchRange
.
length
=
astring
.
length
-
matchRange
.
location
;
}
return
score
;
}
-
(
IBAction
)
textUpdated:
(
id
)
sender
{
NSString
*
query
=
[
field_search
stringValue
];
if
(
query
.
length
<
2
)
{
[
results
release
];
results
=
[[
NSArray
array
]
retain
];
[
table_results
reloadData
];
return
;
}
NSArray
*
contacts
=
[
adium
.
contactController
allContacts
];
NSMutableArray
*
matches
=
[
NSMutableArray
array
];
for
(
AIListContact
*
contact
in
contacts
)
{
if
(
account
&&
contact
.
account
!=
account
)
continue
;
if
(
!
contact
.
account
.
enabled
)
continue
;
if
(
contact
.
isStranger
)
continue
;
NSMutableAttributedString
*
UID
=
[[[
NSMutableAttributedString
alloc
]
initWithString
:
contact
.
UID
attributes
:[
NSDictionary
dictionaryWithObject
:
[
NSFont
systemFontOfSize
:
11.0f
]
forKey
:
NSFontAttributeName
]]
autorelease
];
NSMutableAttributedString
*
displayName
=
[[[
NSMutableAttributedString
alloc
]
initWithString
:
contact
.
displayName
]
autorelease
];
NSInteger
UIDScore
=
[
self
_string
:
UID
matchesQuery
:
query
];
NSInteger
nameScore
=
[
self
_string
:
displayName
matchesQuery
:
query
];
NSInteger
score
=
MIN
(
UIDScore
,
nameScore
);
if
(
score
!=
NSNotFound
)
{
[
matches
addObject
:
[
NSDictionary
dictionaryWithObjectsAndKeys
:
contact
,
@"Contact"
,
[
NSNumber
numberWithInteger
:
score
],
@"Value"
,
UID
,
@"UID"
,
displayName
,
@"DisplayName"
,
contact
.
account
.
UID
,
@"From"
,
nil
]];
}
}
[
results
release
];
results
=
[[
matches
sortedArrayUsingComparator
:^
NSComparisonResult
(
id
obj1
,
id
obj2
)
{
return
[[
obj1
objectForKey
:
@"Value"
]
compare
:
[
obj2
objectForKey
:
@"Value"
]];
}]
retain
];
[
table_results
reloadData
];
}
#pragma mark Table view
-
(
NSInteger
)
numberOfRowsInTableView:
(
NSTableView
*
)
tableView
{
if
(
account
&&
[
field_search
stringValue
].
length
)
return
results
.
count
+
1
;
else
return
results
.
count
;
}
-
(
id
)
tableView:
(
NSTableView
*
)
tableView
objectValueForTableColumn:
(
NSTableColumn
*
)
tableColumn
row:
(
NSInteger
)
row
{
// As a last item, we include the literal query if only one account was selected.
if
(
row
==
results
.
count
)
{
if
([[
tableColumn
identifier
]
isEqualToString
:
@"icon"
])
{
return
[
AIServiceIcons
serviceIconForObject
:
account
type
:
AIServiceIconLarge
direction
:
AIIconNormal
];
}
else
{
NSMutableAttributedString
*
astring
=
[[
NSMutableAttributedString
alloc
]
initWithString
:
@"
\n
"
];
[
astring
appendString
:
[
field_search
stringValue
]
withAttributes
:
[
NSDictionary
dictionaryWithObjectsAndKeys
:
[
NSFont
systemFontOfSize
:
11.0f
],
NSFontAttributeName
,
[
NSNumber
numberWithInteger
:
NSUnderlineStyleSingle
],
NSUnderlineStyleAttributeName
,
[
NSColor
colorWithCalibratedRed
:
244.0f
/
255.0f
green
:
241.0f
/
255.0f
blue
:
197.0f
/
255.0f
alpha
:
1.0f
],
NSBackgroundColorAttributeName
,
[
NSColor
colorWithCalibratedRed
:
237.0
/
255.0f
green
:
204.0
/
255.0f
blue
:
0.0f
alpha
:
1.0f
],
NSUnderlineColorAttributeName
,
nil
]];
NSTextAttachment
*
attachment
;
NSTextAttachmentCell
*
cell
;
NSImage
*
serviceIcon
=
[[
AIServiceIcons
serviceIconForObject
:
account
type
:
AIStatusIconTab
direction
:
AIIconNormal
]
imageByScalingToSize
:
NSMakeSize
(
11
,
11
)];
cell
=
[[
NSTextAttachmentCell
alloc
]
init
];
[
cell
setImage
:
serviceIcon
];
attachment
=
[[
NSTextAttachment
alloc
]
init
];
[
attachment
setAttachmentCell
:
cell
];
[
cell
release
];
[
astring
appendString
:
@" "
withAttributes
:
nil
];
[
astring
appendAttributedString
:
[
NSAttributedString
attributedStringWithAttachment
:
attachment
]];
[
attachment
release
];
return
[
astring
autorelease
];
}
}
AIListContact
*
listContact
=
[[
results
objectAtIndex
:
row
]
objectForKey
:
@"Contact"
];
if
([[
tableColumn
identifier
]
isEqualToString
:
@"icon"
])
{
NSImage
*
userIcon
=
[
AIUserIcons
userIconForObject
:
listContact
];
if
(
!
userIcon
)
{
userIcon
=
[
AIServiceIcons
serviceIconForObject
:
listContact
type
:
AIServiceIconLarge
direction
:
AIIconNormal
];
}
return
userIcon
;
}
else
{
NSMutableAttributedString
*
result
=
[[
NSMutableAttributedString
alloc
]
init
];
[
result
appendAttributedString
:
[[
results
objectAtIndex
:
row
]
objectForKey
:
@"DisplayName"
]];
[
result
appendString
:
@"
\n
"
withAttributes
:
nil
];
NSImage
*
statusIcon
=
[[
AIStatusIcons
statusIconForListObject
:
listContact
type
:
AIStatusIconTab
direction
:
AIIconNormal
]
imageByScalingToSize
:
NSMakeSize
(
11
,
11
)];
if
(
statusIcon
)
{
NSTextAttachment
*
attachment
;
NSTextAttachmentCell
*
cell
;
cell
=
[[
NSTextAttachmentCell
alloc
]
init
];
[
cell
setImage
:
statusIcon
];
attachment
=
[[
NSTextAttachment
alloc
]
init
];
[
attachment
setAttachmentCell
:
cell
];
[
cell
release
];
[
result
appendAttributedString
:
[
NSAttributedString
attributedStringWithAttachment
:
attachment
]];
[
attachment
release
];
[
result
appendString
:
@" "
withAttributes
:
nil
];
}
[
result
appendAttributedString
:
[[
results
objectAtIndex
:
row
]
objectForKey
:
@"UID"
]];
NSImage
*
serviceIcon
=
[[
AIServiceIcons
serviceIconForObject
:
listContact
type
:
AIServiceIconSmall
direction
:
AIIconNormal
]
imageByScalingToSize
:
NSMakeSize
(
11
,
11
)];
if
(
serviceIcon
)
{
NSTextAttachment
*
attachment
;
NSTextAttachmentCell
*
cell
;
cell
=
[[
NSTextAttachmentCell
alloc
]
init
];
[
cell
setImage
:
serviceIcon
];
attachment
=
[[
NSTextAttachment
alloc
]
init
];
[
attachment
setAttachmentCell
:
cell
];
[
cell
release
];
[
result
appendString
:
@" "
withAttributes
:
nil
];
[
result
appendAttributedString
:
[
NSAttributedString
attributedStringWithAttachment
:
attachment
]];
[
attachment
release
];
}
[
result
appendString
:
@" – "
withAttributes
:
nil
];
[
result
appendString
:
[[
results
objectAtIndex
:
row
]
objectForKey
:
@"From"
]
withAttributes
:
[
NSDictionary
dictionaryWithObjectsAndKeys
:
[
NSFont
systemFontOfSize
:
11.0f
],
NSFontAttributeName
,
nil
]];
// The account's icon
serviceIcon
=
[[
AIServiceIcons
serviceIconForObject
:
listContact
.
account
type
:
AIServiceIconSmall
direction
:
AIIconNormal
]
imageByScalingToSize
:
NSMakeSize
(
11
,
11
)];
if
(
serviceIcon
)
{
NSTextAttachment
*
attachment
;
NSTextAttachmentCell
*
cell
;
cell
=
[[
NSTextAttachmentCell
alloc
]
init
];
[
cell
setImage
:
serviceIcon
];
attachment
=
[[
NSTextAttachment
alloc
]
init
];
[
attachment
setAttachmentCell
:
cell
];
[
cell
release
];
[
result
appendString
:
@" "
withAttributes
:
nil
];
[
result
appendAttributedString
:
[
NSAttributedString
attributedStringWithAttachment
:
attachment
]];
[
attachment
release
];
}
return
[
result
autorelease
];
}
}
// Move the selection in the table
-
(
void
)
move:
(
NSInteger
)
diff
{
NSInteger
selectedRow
=
[
table_results
selectedRow
];
[
table_results
selectRowIndexes
:
[
NSIndexSet
indexSetWithIndex
:
selectedRow
+
diff
]
byExtendingSelection
:
NO
];
[
table_results
scrollRowToVisible
:
selectedRow
+
diff
];
}
#pragma mark Text field
-
(
BOOL
)
control:
(
NSControl
*
)
control
textView:
(
NSTextView
*
)
textView
doCommandBySelector:
(
SEL
)
command
{
if
(
control
==
field_search
&&
command
==
@selector
(
moveUp
:
))
{
[
self
move
:
-1
];
return
YES
;
}
else
if
(
control
==
field_search
&&
command
==
@selector
(
moveDown
:
))
{
[
self
move
:
1
];
return
YES
;
}
else
if
(
control
==
field_search
&&
command
==
@selector
(
cancelOperation
:
))
{
[
self
closeWindow
:
nil
];
// The search field should clear too, so it doesn't still have contents the next time it's opened
return
NO
;
}
else
if
(
control
==
field_search
&&
command
==
@selector
(
insertNewline
:
))
{
[
self
okay
:
nil
];
return
YES
;
}
return
NO
;
}
-
(
void
)
controlTextDidEndEditing:
(
NSNotification
*
)
obj
{
[
table_results
setNeedsDisplay
];
}
#pragma mark Account menu
// Account menu delegate
-
(
void
)
accountMenu:
(
AIAccountMenu
*
)
inAccountMenu
didRebuildMenuItems:
(
NSArray
*
)
menuItems
{
[
popup_account
setMenu
:
[
inAccountMenu
menu
]];
}
-
(
BOOL
)
accountMenu:
(
AIAccountMenu
*
)
inAccountMenu
shouldIncludeAccount:
(
AIAccount
*
)
inAccount
{
return
inAccount
.
online
;
}
-
(
void
)
accountMenu:
(
AIAccountMenu
*
)
inAccountMenu
didSelectAccount:
(
AIAccount
*
)
inAccount
{
[
account
release
];
account
=
[
inAccount
retain
];
[
self
textUpdated
:
nil
];
}
-
(
NSMenuItem
*
)
accountMenuSpecialMenuItem:
(
AIAccountMenu
*
)
inAccountMenu
{
NSMenuItem
*
anyItem
=
nil
;
int
numberOfOnlineAccounts
=
0
;
for
(
AIAccount
*
anAccount
in
adium
.
accountController
.
accounts
)
{
if
([
self
accountMenu
:
inAccountMenu
shouldIncludeAccount
:
anAccount
])
{
account
=
[
anAccount
retain
];
numberOfOnlineAccounts
+=
1
;
if
(
numberOfOnlineAccounts
>
1
)
{
[
account
release
];
account
=
nil
;
anyItem
=
[[[
NSMenuItem
alloc
]
initWithTitle
:
AILocalizedString
(
@"Any"
,
@"New message window label to show contacts for 'Any' account."
)
action
:
nil
keyEquivalent
:
@""
]
autorelease
];
break
;
}
}
}
return
anyItem
;
}
@end