adium/adium
Clone
Summary
Browse
Changes
Graph
Updated Sparkle to 1.17.0, to fix a problem when copying broken symlinks.
adium-1.5.10.4
2017-04-23, Thijs Alkemade
5883c460b8cb
Updated Sparkle to 1.17.0, to fix a problem when copying broken symlinks.
/*
* 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 "AIEmoticonController.h"
#import <Adium/AIMenuControllerProtocol.h>
#import <Adium/AIToolbarControllerProtocol.h>
#import "BGEmoticonMenuPlugin.h"
#import <AIUtilities/AIMenuAdditions.h>
#import <AIUtilities/AIToolbarUtilities.h>
#import <AIUtilities/AIImageAdditions.h>
#import <AIUtilities/AIImageDrawingAdditions.h>
#import <AIUtilities/MVMenuButton.h>
#import <Adium/AIEmoticon.h>
@interface
BGEmoticonMenuPlugin
()
-
(
void
)
registerToolbarItem
;
-
(
IBAction
)
dummyTarget:
(
id
)
sender
;
-
(
void
)
insertEmoticon:
(
id
)
sender
;
@end
/*!
* @class BGEmoticonMenuPlugin
* @brief Component to manage the Emoticons menu in its various forms
*/
@implementation
BGEmoticonMenuPlugin
#define PREF_GROUP_EMOTICONS @"Emoticons"
#define TITLE_INSERT_EMOTICON AILocalizedString(@"Insert Emoticon",nil)
#define TOOLTIP_INSERT_EMOTICON AILocalizedString(@"Insert an emoticon into the text",nil)
#define TITLE_EMOTICON AILocalizedString(@"Emoticon",nil)
#define TOOLBAR_EMOTICON_IDENTIFIER @"InsertEmoticon"
/*!
* @brief Install
*/
-
(
void
)
installPlugin
{
//init the menus and menuItems
quickMenuItem
=
[[
NSMenuItem
alloc
]
initWithTitle
:
TITLE_INSERT_EMOTICON
target
:
self
action
:
@selector
(
dummyTarget
:
)
keyEquivalent
:
@""
];
quickContextualMenuItem
=
[[
NSMenuItem
alloc
]
initWithTitle
:
TITLE_INSERT_EMOTICON
target
:
self
action
:
@selector
(
dummyTarget
:
)
keyEquivalent
:
@""
];
/* Create a submenu for these so menu:updateItem:atIndex:shouldCancel: will be called
* to populate them later. Don't need to check respondsToSelector:@selector(setDelegate:).
*/
NSMenu
*
tempMenu
;
tempMenu
=
[[
NSMenu
alloc
]
init
];
[
tempMenu
setDelegate
:
self
];
[
quickMenuItem
setSubmenu
:
tempMenu
];
[
tempMenu
release
];
tempMenu
=
[[
NSMenu
alloc
]
init
];
[
tempMenu
setDelegate
:
self
];
[
quickContextualMenuItem
setSubmenu
:
tempMenu
];
[
tempMenu
release
];
//add the items to their menus.
[
adium
.
menuController
addContextualMenuItem
:
quickContextualMenuItem
toLocation
:
Context_TextView_Edit
];
[
adium
.
menuController
addMenuItem
:
quickMenuItem
toLocation
:
LOC_Edit_Additions
];
toolbarItems
=
[[
NSMutableSet
alloc
]
init
];
[
self
registerToolbarItem
];
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(
toolbarWillAddItem
:
)
name
:
NSToolbarWillAddItemNotification
object
:
nil
];
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(
toolbarDidRemoveItem
:
)
name
:
NSToolbarDidRemoveItemNotification
object
:
nil
];
}
/*!
* @brief Uninstall
*/
-
(
void
)
uninstallPlugin
{
[[
NSNotificationCenter
defaultCenter
]
removeObserver
:
self
];
[
adium
.
preferenceController
unregisterPreferenceObserver
:
self
];
}
/*!
* @brief Deallocate
*/
-
(
void
)
dealloc
{
[
toolbarItems
release
];
[
super
dealloc
];
}
/*!
* @brief Add the emoticon menu as an item goes into a toolbar
*/
-
(
void
)
toolbarWillAddItem:
(
NSNotification
*
)
notification
{
NSToolbarItem
*
item
=
[[
notification
userInfo
]
objectForKey
:
@"item"
];
if
([[
item
itemIdentifier
]
isEqualToString
:
TOOLBAR_EMOTICON_IDENTIFIER
])
{
NSMenu
*
theEmoticonMenu
=
[[[
NSMenu
alloc
]
init
]
autorelease
];
[
theEmoticonMenu
setDelegate
:
self
];
//Add menu to view
[[
item
view
]
setMenu
:
theEmoticonMenu
];
//Add menu to toolbar item (for text mode)
NSMenuItem
*
mItem
=
[[[
NSMenuItem
allocWithZone
:
[
NSMenu
menuZone
]]
init
]
autorelease
];
[
mItem
setSubmenu
:
theEmoticonMenu
];
[
mItem
setTitle
:
TITLE_EMOTICON
];
[
item
setMenuFormRepresentation
:
mItem
];
[
toolbarItems
addObject
:
item
];
}
}
/*!
* @brief Stop tracking when an item is removed from a toolbar
*/
-
(
void
)
toolbarDidRemoveItem:
(
NSNotification
*
)
notification
{
NSToolbarItem
*
item
=
[[
notification
userInfo
]
objectForKey
:
@"item"
];
if
([[
item
itemIdentifier
]
isEqualToString
:
TOOLBAR_EMOTICON_IDENTIFIER
])
{
[
item
setView
:
nil
];
[
toolbarItems
removeObject
:
item
];
}
}
/*!
* @brief Register our toolbar item
*/
-
(
void
)
registerToolbarItem
{
NSToolbarItem
*
toolbarItem
;
MVMenuButton
*
button
;
//Register our toolbar item
button
=
[[[
MVMenuButton
alloc
]
initWithFrame
:
NSMakeRect
(
0
,
0
,
32
,
32
)]
autorelease
];
[
button
setImage
:
[
NSImage
imageNamed
:
@"emoticon32"
forClass
:
[
self
class
]
loadLazily
:
YES
]];
toolbarItem
=
[
AIToolbarUtilities
toolbarItemWithIdentifier
:
TOOLBAR_EMOTICON_IDENTIFIER
label
:
TITLE_EMOTICON
paletteLabel
:
TITLE_INSERT_EMOTICON
toolTip
:
TOOLTIP_INSERT_EMOTICON
target
:
self
settingSelector
:
@selector
(
setView
:
)
itemContent
:
button
action
:
@selector
(
insertEmoticon
:
)
menu
:
nil
];
[
toolbarItem
setMinSize
:
NSMakeSize
(
32
,
32
)];
[
toolbarItem
setMaxSize
:
NSMakeSize
(
32
,
32
)];
[
button
setToolbarItem
:
toolbarItem
];
[
adium
.
toolbarController
registerToolbarItem
:
toolbarItem
forToolbarType
:
@"TextEntry"
];
}
//Menu Generation ------------------------------------------------------------------------------------------------------
#pragma mark Menu Generation
/*!
* @brief Build a flat emoticon menu for a single pack
*
* @result A menu for the pack
*/
-
(
NSMenu
*
)
flatEmoticonMenuForPack:
(
AIEmoticonPack
*
)
incomingPack
{
NSMenu
*
packMenu
=
[[
NSMenu
alloc
]
initWithTitle
:
TITLE_EMOTICON
];
[
packMenu
setMenuChangedMessagesEnabled
:
NO
];
//loop through each emoticon and add a menu item for each
for
(
AIEmoticon
*
anEmoticon
in
incomingPack
.
emoticons
)
{
if
(
anEmoticon
.
isEnabled
)
{
NSArray
*
textEquivalents
=
[
anEmoticon
textEquivalents
];
NSString
*
textEquivalent
;
if
([
textEquivalents
count
])
{
textEquivalent
=
[
textEquivalents
objectAtIndex
:
0
];
}
else
{
textEquivalent
=
@""
;
}
NSString
*
menuTitle
=
[
NSString
stringWithFormat
:
@"%@ %@"
,[
anEmoticon
name
],
textEquivalent
];
NSMenuItem
*
newItem
=
[[
NSMenuItem
alloc
]
initWithTitle
:
menuTitle
target
:
self
action
:
@selector
(
insertEmoticon
:
)
keyEquivalent
:
@""
];
[
newItem
setImage
:
[[
anEmoticon
image
]
imageByScalingForMenuItem
]];
[
newItem
setRepresentedObject
:
anEmoticon
];
[
packMenu
addItem
:
newItem
];
[
newItem
release
];
}
}
[
packMenu
setMenuChangedMessagesEnabled
:
YES
];
return
[
packMenu
autorelease
];
}
//Menu Control ---------------------------------------------------------------------------------------------------------
#pragma mark Menu Control
/*!
* @brief Insert an emoticon into the first responder if possible
*
* First responder must be an editable NSTextView.
*
* @param sender An NSMenuItem whose representedObject is an AIEmoticon
*/
-
(
void
)
insertEmoticon:
(
id
)
sender
{
if
([
sender
isKindOfClass
:
[
NSMenuItem
class
]])
{
NSString
*
emoString
=
[[[
sender
representedObject
]
textEquivalents
]
objectAtIndex
:
0
];
NSResponder
*
responder
=
[[[
NSApplication
sharedApplication
]
keyWindow
]
firstResponder
];
if
(
emoString
&&
[
responder
isKindOfClass
:
[
NSTextView
class
]]
&&
[(
NSTextView
*
)
responder
isEditable
])
{
NSRange
tmpRange
=
[(
NSTextView
*
)
responder
selectedRange
];
if
(
0
!=
tmpRange
.
length
)
{
[(
NSTextView
*
)
responder
setSelectedRange
:
NSMakeRange
((
tmpRange
.
location
+
tmpRange
.
length
),
0
)];
}
[
responder
insertText
:
emoString
];
}
}
}
/*!
* @brief Just a target so we get the validateMenuItem: call for the emoticon menu
*/
-
(
IBAction
)
dummyTarget:
(
id
)
sender
{
//Empty
}
/*!
* @brief Validate menu item
*
* Disable the emoticon menu if a text field is not active
*/
-
(
BOOL
)
validateMenuItem:
(
NSMenuItem
*
)
menuItem
{
if
(
menuItem
==
quickMenuItem
||
menuItem
==
quickContextualMenuItem
)
{
BOOL
haveEmoticons
=
([[
adium
.
emoticonController
activeEmoticonPacks
]
count
]
!=
0
);
//Disable the main emoticon menu items if no emoticons are available
return
haveEmoticons
;
}
else
{
//Disable the emoticon menu items if we're not in a text field
NSResponder
*
responder
=
[[[
NSApplication
sharedApplication
]
keyWindow
]
firstResponder
];
if
(
responder
&&
[
responder
isKindOfClass
:
[
NSText
class
]])
{
return
[(
NSText
*
)
responder
isEditable
];
}
else
{
return
NO
;
}
}
}
/*!
* @brief We don't want to get -menuNeedsUpdate: called on every keystroke. This method suppresses that.
*/
-
(
BOOL
)
menuHasKeyEquivalent:
(
NSMenu
*
)
menu
forEvent:
(
NSEvent
*
)
event
target:
(
id
*
)
target
action:
(
SEL
*
)
action
{
*
target
=
nil
;
//use menu's target
*
action
=
NULL
;
//use menu's action
return
NO
;
}
/*!
* @brief Update our menus if necessary
*
* Called each time before any of our menus are displayed.
* This rebuilds menus incrementally, in place, and only updating items that need it.
*
*/
-
(
BOOL
)
menu:
(
NSMenu
*
)
menu
updateItem:
(
NSMenuItem
*
)
item
atIndex:
(
NSInteger
)
idx
shouldCancel:
(
BOOL
)
shouldCancel
{
NSArray
*
activePacks
=
[
adium
.
emoticonController
activeEmoticonPacks
];
AIEmoticonPack
*
pack
;
/* We need special voodoo here to identify if the menu belongs to a toolbar,
* add the necessary pad item, and then adjust the index accordingly.
* this shouldn't be necessary, but NSToolbar is evil.
*/
if
([[[
menu
itemAtIndex
:
0
]
title
]
isEqualToString
:
TITLE_EMOTICON
])
{
if
(
idx
==
0
)
{
return
YES
;
}
else
{
--
idx
;
}
}
// Add in flat emoticon menu
if
([
activePacks
count
]
==
1
)
{
pack
=
[
activePacks
objectAtIndex
:
0
];
AIEmoticon
*
emoticon
=
[[
pack
enabledEmoticons
]
objectAtIndex
:
idx
];
if
([
emoticon
isEnabled
]
&&
!
[[
item
representedObject
]
isEqualTo
:
emoticon
])
{
[
item
setTitle
:
[
emoticon
name
]];
[
item
setTarget
:
self
];
[
item
setAction
:
@selector
(
insertEmoticon
:
)];
[
item
setKeyEquivalent
:
@""
];
[
item
setImage
:
[[
emoticon
image
]
imageByScalingForMenuItem
]];
[
item
setRepresentedObject
:
emoticon
];
[
item
setSubmenu
:
nil
];
}
// Add in multi-pack menu
}
else
if
([
activePacks
count
]
>
1
)
{
pack
=
[
activePacks
objectAtIndex
:
idx
];
if
(
!
[[
item
title
]
isEqualToString
:
[
pack
name
]]){
[
item
setTitle
:
[
pack
name
]];
[
item
setTarget
:
nil
];
[
item
setAction
:
nil
];
[
item
setKeyEquivalent
:
@""
];
[
item
setImage
:
[[
pack
menuPreviewImage
]
imageByScalingForMenuItem
]];
[
item
setRepresentedObject
:
nil
];
[
item
setSubmenu
:
[
self
flatEmoticonMenuForPack
:
pack
]];
}
}
return
YES
;
}
/*!
* @brief Set the number of items that should be in the menu.
*
* Toolbars need one empty item to display properly. We increase the number by 1, if the menu
* is in a toolbar
*
*/
-
(
NSInteger
)
numberOfItemsInMenu:
(
NSMenu
*
)
menu
{
NSArray
*
activePacks
=
[
adium
.
emoticonController
activeEmoticonPacks
];
NSInteger
itemCounts
=
-1
;
itemCounts
=
[
activePacks
count
];
if
(
itemCounts
==
1
)
itemCounts
=
[[[
activePacks
objectAtIndex
:
0
]
enabledEmoticons
]
count
];
if
([
menu
numberOfItems
]
>
0
)
{
if
([[[
menu
itemAtIndex
:
0
]
title
]
isEqualToString
:
TITLE_EMOTICON
])
{
++
itemCounts
;
}
}
return
itemCounts
;
}
@end