/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using System.Drawing; using System.IO; using System.Reflection; using System.Windows.Forms; using JetBrains.Omea.Base; using JetBrains.Omea.Containers; using JetBrains.Omea.OpenAPI; using JetBrains.Omea.Contacts; using JetBrains.Omea.ResourceTools; using JetBrains.Omea.GUIControls; namespace JetBrains.Omea.ContactsPlugin { [PluginDescriptionAttribute("Contacts", "JetBrains Inc.", "Contact viewer and editor.", PluginDescriptionFormat.PlainText, "Icons/ContactsPluginIcon.png")] public class ContactsPlugin: IPlugin, IResourceDisplayer, IResourceTextProvider { private const string _tabName = "Contacts"; private IResourceTreePane _addressBookPane; private ColorScheme _colorScheme; private static ContactsPlugin _instance; private static bool _isReader; #region IPlugin Members public void Register() { _instance = this; _isReader = Core.ProductFullName.EndsWith( "Reader" ); _colorScheme = new ColorScheme( Assembly.GetExecutingAssembly(), "ContactsPlugin.Icons.", Core.ResourceIconManager.IconColorDepth ); Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream( "ContactsPlugin.Icons.ContactColorScheme.xml" ); _colorScheme.Load( stream ); AddressBook.Initialize(); Core.ResourceTreeManager.SetViewsExclusive( "Contact" ); IUIManager uiMgr = Core.UIManager; Core.TabManager.RegisterResourceTypeTab( _tabName, _tabName, new[] { "Contact", "AddressBook" }, 10 ); uiMgr.RegisterResourceSelectPane( "Contact", typeof(CorrespondentCtrl) ); uiMgr.RegisterResourceSelectPane( "EmailAccount", typeof(EmailAccountSelector) ); IWorkspaceManager mgr = Core.WorkspaceManager; mgr.RegisterWorkspaceType( "Contact", new[] { -Core.ContactManager.Props.LinkFrom, -Core.ContactManager.Props.LinkTo, -Core.ContactManager.Props.LinkCC }, WorkspaceResourceType.Filter ); #if !READER mgr.RegisterWorkspaceType( "EmailAccount", new[] { -Core.ContactManager.Props.LinkEmailAcctFrom, -Core.ContactManager.Props.LinkEmailAcctTo, -Core.ContactManager.Props.LinkEmailAcctCC }, WorkspaceResourceType.Filter ); mgr.RegisterWorkspaceSelectorFilter( "EmailAccount", new EmailAccountFilter() ); mgr.SetWorkspaceTabName( "EmailAccount", "Email Accounts" ); #endif Core.PluginLoader.RegisterViewsConstructor( new ContactsUpgrade1ViewsConstructor() ); Core.PluginLoader.RegisterViewsConstructor( new ContactsViewsConstructor() ); Core.PluginLoader.RegisterViewsConstructor( new ContactsUpgrade2ViewsConstructor() ); Core.PluginLoader.RegisterViewsConstructor( new ContactsUpgrade3ViewsConstructor() ); //----------------------------------------------------------------- // Register Search Extensions to narrow the list of results using // simple phrases in search queries: for restricting the resource // type to Contact (three synonyms). //----------------------------------------------------------------- Core.SearchQueryExtensions.RegisterResourceTypeRestriction( "in", "contacts", "Contact" ); Core.SearchQueryExtensions.RegisterResourceTypeRestriction( "in", "contact", "Contact" ); Core.SearchQueryExtensions.RegisterResourceTypeRestriction( "in", "c", "Contact" ); IDisplayColumnManager colManager = Core.DisplayColumnManager; colManager.RegisterPropertyToTextCallback( Core.ContactManager.Props.LinkFrom, SubstituteName ); Core.UIManager.RegisterDisplayInContextHandler( "Contact", new DisplayContactInContextHandler() ); Core.UIManager.RegisterResourceLocationLink( "AddressBook", 0, "AddressBook" ); Core.PluginLoader.RegisterResourceTextProvider( "Contact", this ); Core.PluginLoader.RegisterResourceDisplayer( "Contact", this ); Core.PluginLoader.RegisterResourceSerializer( "Contact", new ContactSerializer() ); Core.PluginLoader.RegisterResourceSerializer( "Phone", new PhoneSerializer() ); Core.PluginLoader.RegisterResourceSerializer( "EmailAccount", new EmailAccountSerializer() ); Core.ActionManager.RegisterLinkClickAction( new DisplayMailsForEmailAccount(), "EmailAccount", null ); if ( !_isReader ) { IResource abRoot = AddressBook.AddressBookRoot; if ( abRoot != null ) { Assembly theAsm = Assembly.GetExecutingAssembly(); Image img = Utils.TryGetEmbeddedResourceImageFromAssembly( theAsm, "ContactsPlugin.Icons.AddressBook24.png" ); _addressBookPane = Core.LeftSidebar.RegisterResourceStructureTreePane( "AddressBooks", _tabName, "Address Books", img, "AddressBook" ); _addressBookPane.RegisterToolbarAction( new CreateABAction(), LoadIconFromAssembly( "addressbook.ico" ), null, "Create Address Book", null ); Core.LeftSidebar.RegisterViewPaneShortcut( "AddressBooks", Keys.Control | Keys.Alt | Keys.D ); } } else { Core.ResourceBrowser.RegisterLinksPaneFilter( "Contact", new ReaderABLinkFilter() ); } Core.ResourceBrowser.RegisterLinksPaneFilter( "Contact", new SkipEmailAddressesFilter() ); Core.ResourceIconManager.RegisterOverlayIconProvider( "Contact", new ContactOverlayIconProvider() ); Core.PluginLoader.RegisterResourceDeleter( "Contact", new ContactDeleter() ); Core.PluginLoader.RegisterResourceDeleter( "ContactName", new ContactDeleter() ); RegisterContactBlocks(); Core.ResourceIconManager.RegisterResourceLargeIcon( "Contact", LoadIconFromAssembly( "ContactLarge.ico") ); Core.ResourceBrowser.RegisterLinksGroup( "Accounts", new[] { Core.ContactManager.Props.LinkEmailAcct }, ListAnchor.First ); } public void Startup() {} public void Shutdown() {} private static Icon LoadIconFromAssembly( string name ) { Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream( "ContactsPlugin.Icons." + name ); return new Icon( stream ); } #endregion #region IResourceTextProvider Members bool IResourceTextProvider.ProcessResourceText( IResource res, IResourceTextConsumer consumer ) { string body = new ContactBO( res ).ContactBody; if ( body != null ) { lock( consumer ) { consumer.AddDocumentFragment( res.Id, body ); } } return true; } #endregion IResourceTextProvider Members private static void RegisterContactBlocks() { ContactService contactService = ContactService.GetInstance(); Core.PluginLoader.RegisterPluginService( contactService ); contactService.RegisterContactEditBlock( 0, ListAnchor.Last, "Name", NameBlock.CreateBlock ); contactService.RegisterContactEditBlock( 0, ListAnchor.Last, "Email Addresses", EmailBlock.CreateBlock ); contactService.RegisterContactEditBlock( 1, ListAnchor.Last, "Description", DescriptionBlock.CreateBlock ); contactService.RegisterContactEditBlock( 1, ListAnchor.Last, "Categories", CategoriesBlock.CreateBlock ); contactService.RegisterContactEditBlock(ContactTabNames.GeneralTab, ListAnchor.Last, "Name", NameBlock.CreateBlock); contactService.RegisterContactEditBlock(ContactTabNames.GeneralTab, ListAnchor.Last, "Email Addresses", EmailBlock.CreateBlock); contactService.RegisterContactEditBlock(ContactTabNames.PersonalTab, ListAnchor.Last, "Description", DescriptionBlock.CreateBlock); if ( !_isReader ) { contactService.RegisterContactEditBlock(0, ListAnchor.Last, "Phones", PhoneBlock.CreateBlock); contactService.RegisterContactEditBlock(1, ListAnchor.Last, "Job", JobBlock.CreateBlock); contactService.RegisterContactEditBlock(1, ListAnchor.Last, "Address", AddressBlock.CreateBlock); contactService.RegisterContactEditBlock(1, ListAnchor.Last, "Details", DetailsBlock.CreateBlock); contactService.RegisterContactEditBlock(ContactTabNames.GeneralTab, ListAnchor.Last, "Phones", PhoneBlock.CreateBlock); contactService.RegisterContactEditBlock(ContactTabNames.PersonalTab, ListAnchor.Last, "Job", JobBlock.CreateBlock); contactService.RegisterContactEditBlock(ContactTabNames.MailingTab, ListAnchor.Last, "Address", AddressBlock.CreateBlock); contactService.RegisterContactEditBlock(ContactTabNames.PersonalTab, ListAnchor.Last, "Details", DetailsBlock.CreateBlock); } } public static IResourceTreePane AddressBookPane { get { return _instance._addressBookPane; } } internal static bool IsReader { get { return _isReader; } } internal static ColorScheme ColorScheme { get { return _instance._colorScheme; } } #region IResourceDisplayer members IDisplayPane IResourceDisplayer.CreateDisplayPane( string resourceType ) { if ( String.Compare( resourceType, "Contact", true ) == 0 ) { return new ContactDisplayPane(); } return null; } #endregion #region Actions and Filters class EmailAccountFilter: IResourceNodeFilter { private bool _haveMyself = false; private IResource _myselfContact; public bool AcceptNode( IResource res, int level ) { if ( !_haveMyself ) { _myselfContact = Core.ContactManager.MySelf.Resource; _haveMyself = true; } if ( _myselfContact == null ) { return true; } return _myselfContact.HasLink( "EmailAcct", res ); } } class ReaderABLinkFilter: ILinksPaneFilter { public bool AcceptLinkType( IResource displayedResource, int propId, ref string displayName ) { return propId != AddressBook.PropInAddressBook; } public bool AcceptLink( IResource displayedResource, int propId, IResource targetResource, ref string linkTooltip ) { return true; } public bool AcceptAction( IResource displayedResource, IAction action ) { return true; } } internal static string SubstituteName( IResource res, int propId ) { #region Preconditions if( res == null ) throw new ArgumentNullException( "ContactsPlugin -- Input resource is NULL on name substitution." ); #endregion Preconditions ContactManager mgr = Core.ContactManager as ContactManager; if ( mgr.IsMajorLink( propId ) ) { IResourceList contacts = res.GetLinksOfType( null, propId ); IntArrayList contactsIDs = new IntArrayList( contacts.ResourceIds ); int linkNameId = mgr.GetNameLinkId( propId ); IResourceList contactNames = res.GetLinksOfType( "ContactName", linkNameId ); string[] results = new string [contacts.Count]; // In case of any problems or mismatches in the link structure, // fall back to default processing if ( contactNames.Count > contactsIDs.Count ) { return res.GetPropText( propId ); } for( int i = 0; i < contactNames.Count; i++ ) { IResource contactName = Core.ResourceStore.TryLoadResource( contactNames.ResourceIds [ i ] ); if ( contactName == null ) { results [i] = ""; continue; } IResource contact = contactName.GetLinkProp( "BaseContact" ); if( contact == null ) return res.GetPropText( propId ); int index = contactsIDs.IndexOf( contact.Id ); if ( index < 0 ) { return res.GetPropText( propId ); } contactsIDs.RemoveAt( index ); if ( contact.HasProp( Core.ContactManager.Props.ShowOriginalNames ) ) { results [i] = contactName.GetStringProp( "Name" ); } else { results [i] = contact.DisplayName; } } for( int i = 0; i < contactsIDs.Count; i++ ) { IResource majorLinkResource = Core.ResourceStore.TryLoadResource( contactsIDs [ i ] ); if ( majorLinkResource != null ) { results [ i + contactNames.Count] = majorLinkResource.DisplayName; } else { results [ i + contactNames.Count] = ""; } } return String.Join( ", ", results ); } return res.GetPropText( propId ); } class SkipEmailAddressesFilter : ILinksPaneFilter { public bool AcceptLinkType(IResource res, int propId, ref string displayName) { return (res.Type != "Contact") || (( propId != Core.ContactManager.Props.LinkEmailAcct ) && !((ContactManager) Core.ContactManager).IsMajorLink( Math.Abs( propId ) )); } public bool AcceptLink( IResource sourceRes, int propId, IResource targetRes, ref string linkTooltip) { return true; } public bool AcceptAction(IResource displayedResource, IAction action) { return true; } } internal class AddContactToABAction : IRuleAction { public void Exec(IResource res, IActionParameterStore actionStore) { IResourceList authors = res.GetLinksOfType( "Contact", Core.ContactManager.Props.LinkFrom ); foreach( IResource contact in authors ) { IResourceList addrBooks = actionStore.ParametersAsResList(); foreach( IResource addrBook in addrBooks ) { new AddressBook( addrBook ).AddContact( contact ); } } } } #endregion Actions and Filters #region ContactDeleter internal class ContactDeleter: DefaultResourceDeleter { private bool SavedIgnoranceValue = true; public override bool CanDeleteResource( IResource res, bool permanent ) { return !permanent && ( res == null || !res.HasProp( "MySelf" ) ); } public override DialogResult ConfirmDeleteResources( IResourceList list, bool permanent, bool showCancel ) { int fromCount, toCount, ccCount; CountCorrespondenceCounts( list, out fromCount, out toCount, out ccCount ); string message = string.Empty; if( fromCount + toCount + ccCount > 0 ) { if( fromCount > 0 ) message += fromCount + " outcoming items"; if( toCount > 0 ) { if( message.Length > 0 ) { if( ccCount > 0 ) message += ", "; else message += " and "; } message += toCount + " incoming items"; } if( ccCount > 0 ) { if( message.Length > 0 ) message += " and "; message += ccCount + " Carbon Copy items"; } string prefix; if( list.Count == 1 ) prefix = "A contact \'" + list[ 0 ].DisplayName + "\' has "; else prefix = "Selected contacts have "; message = prefix + message + ". These items will be moved to Deleted Resources. "; } message += "Are you sure you wish to delete "; if( list.Count == 1 ) message += "'" + list[ 0 ].DisplayName + "'?"; else message += list.Count + " contacts?"; MessageBoxWithCheckBox.Result result; result = MessageBoxWithCheckBox.ShowYesNo( Core.MainWindow, message, "Delete Contact", "&Ignore incoming correspondence from this contact", true ); SavedIgnoranceValue = result.Checked; return (result.IdPressedButton == (int)DialogResult.Yes) ? DialogResult.Yes : DialogResult.No; } public override void UndeleteResource( IResource res ) { base.UndeleteResource( res ); new ResourceProxy( res ).DeleteProp( Core.ContactManager.Props.Ignored ); } //----------------------------------------------------------------- // Method performs only "soft" contact removal - it never allows // to delete a resource permanently. //----------------------------------------------------------------- public override void DeleteResource( IResource res ) { #region Preconditions if ( res == null ) throw new ArgumentNullException( "ContactManager -- Contact for deletion can not be NULL" ); if( res.Type != "Contact" && res.Type != "ContactName" ) throw new ArgumentNullException( "ContactManager -- Contact for deletion has illegal type [" + res.Type + "]" ); #endregion Preconditions if( res.Type == "ContactName" ) res = res.GetLinkProp( Core.ContactManager.Props.LinkBaseContact ); string errMsg; Core.ContactManager.DeleteContact( res, SavedIgnoranceValue, out errMsg ); if( errMsg != null ) { Core.UIManager.ShowSimpleMessageBox( "Contact Deletion Failed", errMsg ); } else { // And do not forget to perform default actions with the // resource. base.DeleteResource( res ); } } //----------------------------------------------------------------- // This method is overriden in order to forbid the permanent // deletion of contacts. //----------------------------------------------------------------- public override void DeleteResourcePermanent( IResource res ) { // Nothing to do. } private static void CountCorrespondenceCounts( IResourceList list, out int fromCount, out int toCount, out int ccCount ) { fromCount = toCount = ccCount = 0; for( int i = 0; i < list.Count; i++ ) { IResource res = list[ i ]; if( res.Type == "ContactName" ) res = res.GetLinkProp( Core.ContactManager.Props.LinkBaseContact ); fromCount += res.GetLinksOfType( null, Core.ContactManager.Props.LinkFrom ).Count; toCount += res.GetLinksOfType( null, Core.ContactManager.Props.LinkTo ).Count; ccCount += res.GetLinksOfType( null, Core.ContactManager.Props.LinkCC ).Count; } } } #endregion ContactDeleter /// /// Decorate a contact with "Address Book" sign if it is defined /// in some Address Book. /// private class ContactOverlayIconProvider: IOverlayIconProvider { private readonly Icon[] _overlaySign = new Icon[ 1 ]; public ContactOverlayIconProvider() { _overlaySign[ 0 ] = LoadIconFromAssembly( "InABoverlay.ico" ); } public Icon[] GetOverlayIcons( IResource res ) { return (res.HasProp( "InAddressBook" ) ? _overlaySign : null); } } } internal class DisplayContactInContextHandler : IDisplayInContextHandler { public void DisplayResourceInContext( IResource res ) { Core.UIManager.BeginUpdateSidebar(); if ( !Core.TabManager.ActivateTab( "Contacts" ) ) { return; } IResource addressBook = res.GetLinkProp( AddressBook.PropInAddressBook ); if ( addressBook != null ) { Core.LeftSidebar.ActivateViewPane( "AddressBooks" ); Core.UIManager.EndUpdateSidebar(); AbstractViewPane pane = Core.LeftSidebar.GetPane( "AddressBooks" ); if ( pane != null ) { pane.SelectResource( addressBook, false ); } } else { IResource allView = Core.ResourceStore.FindUniqueResource( "SearchView", Core.Props.Name, "All" ); if ( allView != null ) { Core.LeftSidebar.ActivateViewPane( StandardViewPanes.ViewsCategories ); Core.UIManager.EndUpdateSidebar(); Core.LeftSidebar.DefaultViewPane.SelectResource( allView ); } } Core.ResourceBrowser.SelectResource( res ); } } }