account: Add selected account in Toolbar

This commit add dropdown list to toolbar to change currently selected account.
After selection it update ring id used to share account info.

Tuleap: #1532
Change-Id: I9fe3e65513ec45dce8bd53d8611f4daca6081663
Reviewed-by: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
diff --git a/src/ChooseAccountVC.h b/src/ChooseAccountVC.h
new file mode 100644
index 0000000..9c2e268
--- /dev/null
+++ b/src/ChooseAccountVC.h
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ *  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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface ChooseAccountVC : NSViewController
+
+@end
diff --git a/src/ChooseAccountVC.mm b/src/ChooseAccountVC.mm
new file mode 100644
index 0000000..b6316fa
--- /dev/null
+++ b/src/ChooseAccountVC.mm
@@ -0,0 +1,228 @@
+/*
+ *  Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ *  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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#import "ChooseAccountVC.h"
+
+//Qt
+#import <QSize>
+#import <QtMacExtras/qmacfunctions.h>
+#import <QPixmap>
+
+//LRC
+#import <profilemodel.h>
+#import <profile.h>
+#import <person.h>
+#import <globalinstances.h>
+#import <accountmodel.h>
+#import <account.h>
+#import <QItemSelectionModel.h>
+#import <interfaces/pixmapmanipulatori.h>
+//RING
+#import "views/AccountMenuItemView.h"
+
+@interface ChooseAccountVC () <NSMenuDelegate>
+
+@end
+
+@implementation ChooseAccountVC {
+    __unsafe_unretained IBOutlet NSImageView*   profileImage;
+    __unsafe_unretained IBOutlet NSPopUpButton* accountSelectionButton;
+}
+Boolean menuIsOpen;
+Boolean menuNeedsUpdate;
+NSMenu* accountsMenu;
+NSMenuItem* selectedMenuItem;
+QMetaObject::Connection accountUpdate;
+
+- (void)awakeFromNib
+{
+    [profileImage setWantsLayer: YES];
+    profileImage.layer.cornerRadius = profileImage.frame.size.width / 2;
+    profileImage.layer.masksToBounds = YES;
+
+    if (auto pro = ProfileModel::instance().selectedProfile()) {
+        auto photo = GlobalInstances::pixmapManipulator().contactPhoto(pro->person(), {140,140});
+        [profileImage setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
+    }
+
+    accountsMenu = [[NSMenu alloc] initWithTitle:@""];
+    [accountsMenu setDelegate:self];
+    accountSelectionButton.menu = accountsMenu;
+    [self update];
+
+    QObject::disconnect(accountUpdate);
+    accountUpdate = QObject::connect(&AccountModel::instance(),
+                                     &AccountModel::dataChanged,
+                                     [=] {
+                                          [self update];
+                                     });
+}
+
+-(void) updateMenu {
+    [accountsMenu removeAllItems];
+    QList<Account*> allAccounts = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+    NSLog(@"numberOfaccounts: %d", allAccounts.count());
+
+    for (auto account : allAccounts) {
+        NSMenuItem* menuBarItem = [[NSMenuItem alloc]
+                                   initWithTitle:[self itemTitleForAccount:account] action:NULL keyEquivalent:@""];
+        menuBarItem.attributedTitle = [self attributedItemTitleForAccount:account];
+        AccountMenuItemView *itemView = [[AccountMenuItemView alloc] initWithFrame:CGRectZero];
+        [itemView.accountLabel setStringValue:account->alias().toNSString()];
+        NSString* userNameString = [self nameForAccount: account];
+        [itemView.userNameLabel setStringValue:userNameString];
+        [itemView.accountTypeLabel setStringValue:@"Ring"];
+        auto humanState = account->toHumanStateName();
+        [itemView.accountStatus setStringValue:humanState.toNSString()];
+        [menuBarItem setView:itemView];
+        [accountsMenu addItem:menuBarItem];
+        [accountsMenu addItem:[NSMenuItem separatorItem]];
+
+    }
+}
+
+-(NSString*) nameForAccount:(Account*) account {
+    auto name = account->registeredName();
+    NSString* userNameString = nullptr;
+    if (!name.isNull() && !name.isEmpty()) {
+        userNameString = name.toNSString();
+    } else {
+        userNameString = account->username().toNSString();
+    }
+    return userNameString;
+}
+
+-(NSString*) itemTitleForAccount:(Account*) account {
+    NSString* alias = account->alias().toNSString();
+    alias = [NSString stringWithFormat: @"%@\n", alias];
+    NSString* userNameString = [self nameForAccount: account];
+    return [alias stringByAppendingString:userNameString];
+}
+
+- (NSAttributedString*) attributedItemTitleForAccount:(Account*) account {
+    NSString* alias = account->alias().toNSString();
+    alias = [NSString stringWithFormat: @"%@\n", alias];
+    NSString* userNameString = [self nameForAccount: account];
+    NSFont *fontAlias = [NSFont userFontOfSize:14.0];
+    NSFont *fontUserName = [NSFont userFontOfSize:11.0];
+    NSColor *colorAlias = [NSColor labelColor];
+    NSColor *colorAUserName = [NSColor secondaryLabelColor];
+    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+    paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
+    NSDictionary *aliasAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontAlias,NSFontAttributeName,
+                                colorAlias,NSForegroundColorAttributeName,
+                                paragraphStyle,NSParagraphStyleAttributeName, nil];
+    NSDictionary *userNameAttrs = [NSDictionary dictionaryWithObjectsAndKeys:fontUserName,NSFontAttributeName,
+                                   colorAUserName,NSForegroundColorAttributeName,
+                                   paragraphStyle,NSParagraphStyleAttributeName, nil];
+    NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:alias attributes:aliasAttrs];
+    NSAttributedString* attributedStringSecond= [[NSAttributedString alloc] initWithString:userNameString attributes:userNameAttrs];
+    NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
+    [result appendAttributedString:attributedString];
+    [result appendAttributedString:attributedStringSecond];
+    return result;
+}
+
+-(Account *)selectedAccount {
+    Account* finalChoice = nullptr;
+    finalChoice = AccountModel::instance().userChosenAccount();
+
+    if(finalChoice == nil) {
+        Account* registered = nullptr;
+        Account* enabled = nullptr;
+        auto ringList = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+        for (int i = 0 ; i < ringList.size() && !registered ; ++i) {
+            auto account = ringList.value(i);
+            if (account->isEnabled()) {
+                if(!enabled) {
+                    enabled = finalChoice = account;
+                }
+                if (account->registrationState() == Account::RegistrationState::READY) {
+                    registered = enabled = finalChoice = account;
+                }
+            } else {
+                if (!finalChoice) {
+                    finalChoice = account;
+                }
+            }
+        }
+    }
+    return finalChoice;
+}
+
+
+-(void) update {
+    if(menuIsOpen) {
+        return;
+    }
+    [self updateMenu];
+    [self chooseAccount];
+}
+
+-(void) chooseAccount {
+    if(accountsMenu.itemArray.count == 0) {
+        [self.view setHidden:YES];
+        return;
+    }
+    Account* selectedAccount = [self selectedAccount];
+    NSString *itemTitle = [self itemTitleForAccount:selectedAccount];
+    if([accountSelectionButton itemWithTitle:itemTitle]){
+        [accountSelectionButton selectItemWithTitle:itemTitle];
+        // check if chosen account is the same as selected in popup button. If yes we don.t need setUserChosenAccount
+        Account* choosenaccount = AccountModel::instance().userChosenAccount();
+        if (choosenaccount && [itemTitle isEqualToString:[self itemTitleForAccount:choosenaccount]]){
+            return;
+        }
+        AccountModel::instance().setUserChosenAccount(selectedAccount);
+    }
+}
+
+#pragma mark - NSPopUpButton item selection
+
+- (IBAction)itemChanged:(id)sender {
+    NSInteger index = [(NSPopUpButton *)sender indexOfSelectedItem];
+     QList<Account*> allAccounts = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+    // menu contains accounts and separation lines, so divide it by 2 to get account index
+    Account *selectedAccount = allAccounts.at(index/2);
+    AccountModel::instance().setUserChosenAccount(selectedAccount);
+}
+
+#pragma mark - NSMenuDelegate
+- (void)menuWillOpen:(NSMenu *)menu {
+    menuIsOpen = true;
+    // remember selected item to remove highlighting when menu is open
+    selectedMenuItem = [accountSelectionButton selectedItem];
+}
+- (void)menuDidClose:(NSMenu *)menu {
+
+    menuIsOpen = false;
+}
+
+- (void)menu:(NSMenu *)menu willHighlightItem:(nullable NSMenuItem *)item {
+    if (!selectedMenuItem || selectedMenuItem == item) {
+        return;
+    }
+    int index = [menu indexOfItem:selectedMenuItem];
+    [menu removeItemAtIndex:index];
+    [menu insertItem:selectedMenuItem atIndex:index];
+    [accountSelectionButton selectItemAtIndex:index];
+    selectedMenuItem = nil;
+}
+
+@end
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
index 62e43d5..c545f09 100644
--- a/src/RingWindowController.mm
+++ b/src/RingWindowController.mm
@@ -42,8 +42,9 @@
 #import "views/IconButton.h"
 #import "views/NSColor+RingTheme.h"
 #import "views/BackgroundView.h"
+#import "ChooseAccountVC.h"
 
-@interface RingWindowController () <MigrateRingAccountsDelegate>
+@interface RingWindowController () <MigrateRingAccountsDelegate, NSToolbarDelegate>
 
 @property (retain) MigrateRingAccountsWC* migrateWC;
 
@@ -64,20 +65,23 @@
 
     CurrentCallVC* currentCallVC;
     ConversationVC* offlineVC;
+
+    ChooseAccountVC* chooseAccountVC;
 }
 
-QMetaObject::Connection accountUpdate;
 static NSString* const kPreferencesIdentifier = @"PreferencesIdentifier";
+NSString* const kChangeAccountToolBarItemIdentifier = @"ChangeAccountToolBarItemIdentifier";
 
 - (void)windowDidLoad {
     [super windowDidLoad];
     [self.window setMovableByWindowBackground:YES];
 
     [self.window setBackgroundColor:[NSColor colorWithRed:242.0/255 green:242.0/255 blue:242.0/255 alpha:1.0]];
+    self.window.titleVisibility = NSWindowTitleHidden;
 
     currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
     offlineVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil];
-
+    chooseAccountVC = [[ChooseAccountVC alloc] initWithNibName:@"ChooseAccount" bundle:nil];
     [callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     [[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     [[offlineVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
@@ -94,13 +98,6 @@
 - (void) connect
 {
     // Update Ring ID label based on account model changes
-    QObject::disconnect(accountUpdate);
-    accountUpdate = QObject::connect(&AccountModel::instance(),
-                                     &AccountModel::dataChanged,
-                                     [=] {
-                                         [self updateRingID];
-                                     });
-
     QObject::connect(RecentModel::instance().selectionModel(),
                      &QItemSelectionModel::currentChanged,
                      [=](const QModelIndex &current, const QModelIndex &previous) {
@@ -137,6 +134,14 @@
                              [offlineVC animateOut];
                          }
                      });
+    QObject::connect(AccountModel::instance().userSelectionModel(),
+                     &QItemSelectionModel::currentChanged,
+                     [=](const QModelIndex &current, const QModelIndex &previous) {
+                         if(!current.isValid())
+                             return;
+                         [self updateRingID];
+                     });
+
 }
 
 /**
@@ -150,23 +155,26 @@
     Account* finalChoice = nullptr;
 
     [ringIDLabel setStringValue:@""];
-    auto ringList = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
-    for (int i = 0 ; i < ringList.size() && !registered ; ++i) {
-        auto account = ringList.value(i);
-        if (account->isEnabled()) {
-            if(!enabled) {
-                enabled = finalChoice = account;
-            }
-            if (account->registrationState() == Account::RegistrationState::READY) {
-                registered = enabled = finalChoice = account;
-            }
-        } else {
-            if (!finalChoice) {
-                finalChoice = account;
+    finalChoice = AccountModel::instance().userChosenAccount();
+
+    if(finalChoice == nil) {
+        auto ringList = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING);
+        for (int i = 0 ; i < ringList.size() && !registered ; ++i) {
+            auto account = ringList.value(i);
+            if (account->isEnabled()) {
+                if(!enabled) {
+                    enabled = finalChoice = account;
+                }
+                if (account->registrationState() == Account::RegistrationState::READY) {
+                    registered = enabled = finalChoice = account;
+                }
+            } else {
+                if (!finalChoice) {
+                    finalChoice = account;
+                }
             }
         }
     }
-
     auto name = finalChoice->registeredName();
     NSString* uriToDisplay = nullptr;
     if (!name.isNull() && !name.isEmpty()) {
@@ -319,10 +327,13 @@
         [self migrateRingAccount:acc];
     } else {
         // Fresh run, we need to make sure RingID appears
-        [self updateRingID];
         [shareButton sendActionOn:NSLeftMouseDownMask];
 
         [self connect];
+        // display accounts to select
+        NSToolbar *toolbar = self.window.toolbar;
+        toolbar.delegate = self;
+        [toolbar insertItemWithItemIdentifier:kChangeAccountToolBarItemIdentifier atIndex:1];
     }
 }
 
@@ -336,4 +347,15 @@
     [self checkAccountsToMigrate];
 }
 
+#pragma mark - NSToolbarDelegate
+- (nullable NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag{
+    if(!(itemIdentifier == kChangeAccountToolBarItemIdentifier)) {
+        return nil;
+    }
+    NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:kChangeAccountToolBarItemIdentifier];
+    CGRect frame = chooseAccountVC.view.frame;
+    toolbarItem.view = chooseAccountVC.view;
+    return toolbarItem;
+}
+
 @end
diff --git a/src/views/AccountMenuItemView.h b/src/views/AccountMenuItemView.h
new file mode 100644
index 0000000..038a122
--- /dev/null
+++ b/src/views/AccountMenuItemView.h
@@ -0,0 +1,30 @@
+/*
+ *  Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ *  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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface AccountMenuItemView : NSView
+
+@property (nonatomic, strong) IBOutlet NSView*      containerView;
+@property (nonatomic, strong) IBOutlet NSTextField* accountLabel;
+@property (nonatomic, strong) IBOutlet NSTextField* userNameLabel;
+@property (nonatomic, strong) IBOutlet NSTextField* accountTypeLabel;
+@property (nonatomic, strong) IBOutlet NSTextField* accountStatus;
+
+@end
diff --git a/src/views/AccountMenuItemView.mm b/src/views/AccountMenuItemView.mm
new file mode 100644
index 0000000..8b8a3aa
--- /dev/null
+++ b/src/views/AccountMenuItemView.mm
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ *  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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#import "AccountMenuItemView.h"
+#import "NSColor+RingTheme.h"
+
+@implementation AccountMenuItemView
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self loadFromNib];
+    }
+    return self;
+}
+
+- (void)loadFromNib
+{
+    NSView *viewFromXib = nil;
+    NSArray *objectsFromXib = nil;
+    [[NSBundle mainBundle] loadNibNamed:@"AccountMenuItemView" owner:self topLevelObjects:&objectsFromXib];
+    for (id item in objectsFromXib) {
+        if ([item isKindOfClass:[NSView class]]) {
+            viewFromXib = item;
+            break;
+        }
+    }
+    if (viewFromXib != nil) {
+        self.frame = viewFromXib.frame;
+        self.containerView = viewFromXib;
+        [self addSubview:self.containerView];
+    }
+}
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)event {
+    return YES;
+}
+
+-(void) mouseUp:(NSEvent *)theEvent {
+    NSMenu *menu = self.enclosingMenuItem.menu;
+    [menu cancelTracking];
+    [menu performActionForItemAtIndex:[menu indexOfItem:self.enclosingMenuItem]];
+    [super mouseUp:theEvent];
+}
+
+- (void) drawRect: (NSRect) rect {
+    NSMenuItem *menuItem = ([self enclosingMenuItem]);
+    BOOL isHighlighted = [menuItem isHighlighted];
+    if (isHighlighted) {
+        [[NSColor ringGreyHighlight] set];
+        [NSBezierPath fillRect:rect];
+    } else {
+        [super drawRect: rect];
+    }
+}
+
+@end