adium/adium
Clone
Summary
Browse
Changes
Graph
We're releasing, silly.
adium-1.5.7
1.5.7
2013-07-02, Thijs Alkemade
c72b164f75a7
We're releasing, silly.
#import "AIDockNameOverlay.h"
#import "AIDockController.h"
#import <AIUtilities/AIParagraphStyleAdditions.h>
#import <AIUtilities/AIImageAdditions.h>
#import <Adium/AIChat.h>
#import <Adium/AIAccount.h>
#import <AIUtilities/AIArrayAdditions.h>
#import <Adium/AIAbstractListController.h>
#import <AIUtilities/AIColorAdditions.h>
#import <AIUtilities/AIBezierPathAdditions.h>
#define DOCK_OVERLAY_ALERT_SHORT AILocalizedString(@"Display name in the dock icon",nil)
#define DOCK_OVERLAY_ALERT_LONG DOCK_OVERLAY_ALERT_SHORT
@interface
AIDockNameOverlay
()
-
(
void
)
flushPreferenceColorCache
;
-
(
void
)
drawOverlay
;
-
(
void
)
removeDockOverlay:
(
NSTimer
*
)
removeTimer
;
@end
@implementation
AIDockNameOverlay
-
(
void
)
installPlugin
{
//Install our contact alert
[
adium
.
contactAlertsController
registerActionID
:
DOCK_OVERLAY_ALERT_IDENTIFIER
withHandler
:
self
];
overlayObjectsArray
=
[[
NSMutableArray
alloc
]
init
];
//Register as a contact observer (For signed on / signed off)
[[
AIContactObserverManager
sharedManager
]
registerListObjectObserver
:
self
];
[
adium
.
chatController
registerChatObserver
:
self
];
//Observe pref changes
[
adium
.
preferenceController
registerPreferenceObserver
:
self
forGroup
:
PREF_GROUP_APPEARANCE
];
[
adium
.
preferenceController
registerPreferenceObserver
:
self
forGroup
:
PREF_GROUP_LIST_THEME
];
}
-
(
void
)
preferencesChangedForGroup:
(
NSString
*
)
group
key:
(
NSString
*
)
key
object
:(
AIListObject
*
)
object
preferenceDict:
(
NSDictionary
*
)
prefDict
firstTime:
(
BOOL
)
firstTime
{
if
([
group
isEqualToString
:
PREF_GROUP_LIST_THEME
])
{
//Grab colors from status coloring plugin's prefs
[
self
flushPreferenceColorCache
];
signedOffColor
=
[[[
prefDict
objectForKey
:
KEY_SIGNED_OFF_COLOR
]
representedColor
]
retain
];
signedOnColor
=
[[[
prefDict
objectForKey
:
KEY_SIGNED_ON_COLOR
]
representedColor
]
retain
];
unviewedContentColor
=
[[[
prefDict
objectForKey
:
KEY_UNVIEWED_COLOR
]
representedColor
]
retain
];
backSignedOffColor
=
[[[
prefDict
objectForKey
:
KEY_LABEL_SIGNED_OFF_COLOR
]
representedColor
]
retain
];
backSignedOnColor
=
[[[
prefDict
objectForKey
:
KEY_LABEL_SIGNED_ON_COLOR
]
representedColor
]
retain
];
backUnviewedContentColor
=
[[[
prefDict
objectForKey
:
KEY_LABEL_UNVIEWED_COLOR
]
representedColor
]
retain
];
}
}
-
(
void
)
flushPreferenceColorCache
{
[
signedOffColor
release
];
signedOffColor
=
nil
;
[
signedOnColor
release
];
signedOnColor
=
nil
;
[
unviewedContentColor
release
];
unviewedContentColor
=
nil
;
[
backSignedOffColor
release
];
backSignedOffColor
=
nil
;
[
backSignedOnColor
release
];
backSignedOnColor
=
nil
;
[
backUnviewedContentColor
release
];
backUnviewedContentColor
=
nil
;
}
-
(
void
)
uninstallPlugin
{
[
adium
.
preferenceController
unregisterPreferenceObserver
:
self
];
[
adium
.
chatController
unregisterChatObserver
:
self
];
}
/*!
* @brief Short description
* @result A short localized description of the action
*/
-
(
NSString
*
)
shortDescriptionForActionID:
(
NSString
*
)
actionID
{
return
DOCK_OVERLAY_ALERT_SHORT
;
}
/*!
* @brief Long description
* @result A longer localized description of the action which should take into account the details dictionary as appropraite.
*/
-
(
NSString
*
)
longDescriptionForActionID:
(
NSString
*
)
actionID
withDetails:
(
NSDictionary
*
)
details
{
return
DOCK_OVERLAY_ALERT_LONG
;
}
/*!
* @brief Image
*/
-
(
NSImage
*
)
imageForActionID:
(
NSString
*
)
actionID
{
return
[
NSImage
imageNamed
:
@"events-dock-alert"
forClass
:
[
self
class
]];
}
/*!
* @brief Details pane
* @result An <tt>AIActionDetailsPane</tt> to use for configuring this action, or nil if no configuration is possible.
*/
-
(
AIActionDetailsPane
*
)
detailsPaneForActionID:
(
NSString
*
)
actionID
{
return
nil
;
}
/*!
* @brief Perform an action
*
* @param actionID The ID of the action to perform
* @param listObject The listObject associated with the event triggering the action. It may be nil
* @param details If set by the details pane when the action was created, the details dictionary for this particular action
* @param eventID The eventID which triggered this action
* @param userInfo Additional information associated with the event; userInfo's type will vary with the actionID.
*/
-
(
BOOL
)
performActionID:
(
NSString
*
)
actionID
forListObject:
(
AIListObject
*
)
listObject
withDetails:
(
NSDictionary
*
)
details
triggeringEventID:
(
NSString
*
)
eventID
userInfo:
(
id
)
userInfo
{
BOOL
isMessageEvent
=
[
adium
.
contactAlertsController
isMessageEvent
:
eventID
];
if
(
isMessageEvent
)
{
AIChat
*
chat
;
if
((
chat
=
[
userInfo
objectForKey
:
@"AIChat"
])
&&
(
chat
!=
adium
.
interfaceController
.
activeChat
))
{
if
(
!
[
overlayObjectsArray
containsObjectIdenticalTo
:
chat
])
[
overlayObjectsArray
addObject
:
chat
];
//Wait until the next run loop so that this event is done processing and our unviewed content count is correct
[
self
performSelector
:
@selector
(
drawOverlay
)
withObject
:
nil
afterDelay
:
0
];
}
}
else
if
(
listObject
)
{
NSTimer
*
removeTimer
;
//Clear any current timer for this object to have its overlay removed
if
((
removeTimer
=
[
listObject
valueForProperty
:
@"DockOverlayRemoveTimer"
]))
[
removeTimer
invalidate
];
//Add a timer to remove this overlay
removeTimer
=
[
NSTimer
scheduledTimerWithTimeInterval
:
5
target
:
self
selector
:
@selector
(
removeDockOverlay
:
)
userInfo
:
listObject
repeats
:
NO
];
[
listObject
setValue
:
removeTimer
forProperty
:
@"DockOverlayRemoveTimer"
notify
:
NotifyNever
];
if
(
!
[
overlayObjectsArray
containsObjectIdenticalTo
:
listObject
])
[
overlayObjectsArray
addObject
:
listObject
];
[
self
drawOverlay
];
}
return
YES
;
}
/*!
* @brief Allow multiple actions?
*
* If this method returns YES, every one of this action associated with the triggering event will be executed.
* If this method returns NO, only the first will be.
*/
-
(
BOOL
)
allowMultipleActionsWithID:
(
NSString
*
)
actionID
{
return
NO
;
}
/*!
* @brief When a chat no longer has unviewed content remove it from display
*/
-
(
NSSet
*
)
updateChat:
(
AIChat
*
)
inChat
keys:
(
NSSet
*
)
inModifiedKeys
silent:
(
BOOL
)
silent
{
if
(
inModifiedKeys
==
nil
||
[
inModifiedKeys
containsObject
:
KEY_UNVIEWED_CONTENT
])
{
if
(
!
[
inChat
unviewedContentCount
])
{
[
overlayObjectsArray
removeObjectIdenticalTo
:
inChat
];
[
self
drawOverlay
];
}
}
return
nil
;
}
/*!
* @brief When an account signs on or off force an overlay update as its contacts statuses may have silently changed
*/
-
(
NSSet
*
)
updateListObject:
(
AIListObject
*
)
inObject
keys:
(
NSSet
*
)
inModifiedKeys
silent:
(
BOOL
)
silent
{
if
([
inObject
isKindOfClass
:
[
AIAccount
class
]])
{
if
([
inModifiedKeys
containsObject
:
@"isOnline"
])
{
BOOL
madeChanges
=
NO
;
for
(
AIListObject
*
listObject
in
[[
overlayObjectsArray
copy
]
autorelease
])
{
if
(([
listObject
respondsToSelector
:
@selector
(
account
)])
&&
([(
id
)
listObject
account
]
==
inObject
)
&&
([
overlayObjectsArray
containsObjectIdenticalTo
:
listObject
]))
{
[
overlayObjectsArray
removeObjectIdenticalTo
:
listObject
];
madeChanges
=
YES
;
}
}
if
(
madeChanges
)
[
self
drawOverlay
];
}
}
return
nil
;
}
-
(
void
)
removeDockOverlay:
(
NSTimer
*
)
removeTimer
{
AIListObject
*
inObject
=
[
removeTimer
userInfo
];
[
overlayObjectsArray
removeObjectIdenticalTo
:
inObject
];
[
inObject
setValue
:
nil
forProperty
:
@"DockOverlayRemoveTimer"
notify
:
NotifyNever
];
[
self
drawOverlay
];
}
-
(
void
)
drawOverlay
{
NSFont
*
font
;
NSParagraphStyle
*
paragraphStyle
;
CGFloat
iconHeight
;
CGFloat
top
,
bottom
;
NSImage
*
image
=
[[
NSImage
alloc
]
initWithSize
:
NSMakeSize
(
128
,
128
)];
iconHeight
=
30.0f
;
bottom
=
2
;
top
=
bottom
+
iconHeight
;
//Set up the string details
font
=
[
NSFont
boldSystemFontOfSize
:
24.0f
];
paragraphStyle
=
[
NSParagraphStyle
styleWithAlignment
:
NSCenterTextAlignment
lineBreakMode
:
NSLineBreakByClipping
];
[
image
lockFocus
];
//Clear our image
[[
NSColor
clearColor
]
set
];
NSRectFillUsingOperation
(
NSMakeRect
(
0
,
0
,
128
,
128
),
NSCompositeCopy
);
//Draw overlays for each contact
for
(
ESObjectWithProperties
*
object
in
[
overlayObjectsArray
reverseObjectEnumerator
])
{
if
(
top
>=
128
)
break
;
CGFloat
arcRadius
,
stringInset
;
NSBezierPath
*
path
;
NSRect
pillRect
;
NSColor
*
backColor
=
nil
,
*
textColor
=
nil
,
*
borderColor
=
nil
;
//Create the pill frame
arcRadius
=
(
iconHeight
/
2.0f
);
stringInset
=
(
iconHeight
/
4.0f
);
pillRect
=
NSMakeRect
(
0
,
bottom
,
127
,
iconHeight
);
path
=
[
NSBezierPath
bezierPathWithRoundedRect
:
pillRect
radius
:
arcRadius
];
[
path
setLineWidth
:
((
iconHeight
/
2.0f
)
*
0.13333f
)];
if
([
object
integerValueForProperty
:
KEY_UNVIEWED_CONTENT
])
{
//Unviewed
backColor
=
backUnviewedContentColor
;
textColor
=
unviewedContentColor
;
}
else
if
([
object
boolValueForProperty
:
@"signedOn"
])
{
//Signed on
backColor
=
backSignedOnColor
;
textColor
=
signedOnColor
;
}
else
if
([
object
boolValueForProperty
:
@"signedOff"
])
{
//Signed off
backColor
=
backSignedOffColor
;
textColor
=
signedOffColor
;
}
if
(
!
backColor
)
backColor
=
[
NSColor
whiteColor
];
if
(
!
textColor
)
textColor
=
[
NSColor
blackColor
];
//Lighten/Darken the back color slightly
if
([
backColor
colorIsDark
])
{
backColor
=
[
backColor
darkenBy
:
-0.15f
];
borderColor
=
[
backColor
darkenBy
:
-0.3f
];
}
else
{
backColor
=
[
backColor
darkenBy
:
0.15f
];
borderColor
=
[
backColor
darkenBy
:
0.3f
];
}
//Draw
[
backColor
set
];
[
path
fill
];
[
borderColor
set
];
[
path
stroke
];
//Get the object's display name
[
object
.
displayName
drawInRect
:
NSMakeRect
(
stringInset
+
1
,
bottom
-
1
,
127
-
(
stringInset
*
2
),
top
-
bottom
)
withAttributes
:[
NSDictionary
dictionaryWithObjectsAndKeys
:
font
,
NSFontAttributeName
,
paragraphStyle
,
NSParagraphStyleAttributeName
,
textColor
,
NSForegroundColorAttributeName
,
nil
]];
//Move up to the next pill
bottom
=
top
+
3.0f
;
top
=
bottom
+
iconHeight
;
}
[
image
unlockFocus
];
[
adium
.
dockController
setOverlay
:
image
];
[
image
release
];
}
@end