ui: add account screen management
- ability to create SIP/IAX/RING accounts
- add configuration panels: security panel needs to be discussed
- some settings may change
Refs #67077
Change-Id: I17afbcbbd067bf75f381492997ad40a72703cf0f
diff --git a/AccountsVC.mm b/AccountsVC.mm
new file mode 100644
index 0000000..bfb5d52
--- /dev/null
+++ b/AccountsVC.mm
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
+ * Author: Alexandre Lision <alexandre.lision@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.
+ *
+ * Additional permission under GNU GPL version 3 section 7:
+ *
+ * If you modify this program, or any covered work, by linking or
+ * combining it with the OpenSSL project's OpenSSL library (or a
+ * modified version of that library), containing parts covered by the
+ * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ * grants you additional permission to convey the resulting work.
+ * Corresponding Source for a non-source form of such a combination
+ * shall include the source code for the parts of OpenSSL used as well
+ * as that of the covered work.
+ */
+
+#define COLUMNID_ENABLE @"EnableColumn"
+#define COLUMNID_NAME @"NameColumn"
+#define COLUMNID_STATE @"StateColumn"
+
+#import "AccountsVC.h"
+
+// LibRingClient
+#include <accountmodel.h>
+#include <protocolmodel.h>
+#include <QItemSelectionModel>
+#include <account.h>
+
+#import "QNSTreeController.h"
+#import "AccGeneralVC.h"
+#import "AccAudioVC.h"
+#import "AccVideoVC.h"
+#import "AccAdvancedVC.h"
+#import "AccSecurityVC.h"
+#import "AccRingVC.h"
+
+@interface AccountsVC ()
+@property (assign) IBOutlet NSPopUpButton *protocolList;
+
+@property (assign) IBOutlet NSTabView *configPanels;
+@property (retain) IBOutlet NSTabViewItem *generalTabItem;
+@property (retain) IBOutlet NSTabViewItem *audioTabItem;
+@property (retain) IBOutlet NSTabViewItem *videoTabItem;
+@property (retain) IBOutlet NSTabViewItem *advancedTabItem;
+@property (retain) IBOutlet NSTabViewItem *securityTabItem;
+@property (retain) IBOutlet NSTabViewItem *ringTabItem;
+
+@property QNSTreeController *treeController;
+@property (assign) IBOutlet NSOutlineView *accountsListView;
+@property (assign) IBOutlet NSTabView *accountDetailsView;
+
+@property AccRingVC* ringVC;
+@property AccGeneralVC* generalVC;
+@property AccAudioVC* audioVC;
+@property AccVideoVC* videoVC;
+@property AccAdvancedVC* advancedVC;
+@property AccSecurityVC* securityVC;
+
+@end
+
+@implementation AccountsVC
+@synthesize protocolList;
+@synthesize configPanels;
+@synthesize generalTabItem;
+@synthesize audioTabItem;
+@synthesize videoTabItem;
+@synthesize advancedTabItem;
+@synthesize securityTabItem;
+@synthesize ringTabItem;
+@synthesize accountsListView;
+@synthesize accountDetailsView;
+@synthesize treeController;
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+ if (self = [super initWithCoder:aDecoder]) {
+ NSLog(@"INIT Accounts VC");
+ }
+ return self;
+}
+
+- (void)awakeFromNib
+{
+ treeController = [[QNSTreeController alloc] initWithQModel:AccountModel::instance()];
+ [treeController setAvoidsEmptySelection:NO];
+ [treeController setAlwaysUsesMultipleValuesMarker:YES];
+ [treeController setChildrenKeyPath:@"children"];
+
+ [accountsListView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
+ [accountsListView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
+ [accountsListView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
+
+
+ QObject::connect(AccountModel::instance(),
+ &QAbstractItemModel::dataChanged,
+ [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
+ NSLog(@"data changed %d, %d", topLeft.row(), bottomRight.row());
+
+ [accountsListView reloadDataForRowIndexes:
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(topLeft.row(), bottomRight.row() + 1)]
+ columnIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, accountsListView.tableColumns.count)]];
+
+ });
+
+ QModelIndex qProtocolIdx = AccountModel::instance()->protocolModel()->selectionModel()->currentIndex();
+ [self.protocolList addItemWithTitle:
+ AccountModel::instance()->protocolModel()->data(qProtocolIdx, Qt::DisplayRole).toString().toNSString()];
+
+ self.generalVC = [[AccGeneralVC alloc] initWithNibName:@"AccGeneral" bundle:nil];
+ [[self.generalVC view] setFrame:[self.generalTabItem.view frame]];
+ [[self.generalVC view] setBounds:[self.generalTabItem.view bounds]];
+ [self.generalTabItem setView:self.generalVC.view];
+
+ self.audioVC = [[AccAudioVC alloc] initWithNibName:@"AccAudio" bundle:nil];
+ [[self.audioVC view] setFrame:[self.audioTabItem.view frame]];
+ [[self.audioVC view] setBounds:[self.audioTabItem.view bounds]];
+ [self.audioTabItem setView:self.audioVC.view];
+
+ self.videoVC = [[AccVideoVC alloc] initWithNibName:@"AccVideo" bundle:nil];
+ [[self.videoVC view] setFrame:[self.videoTabItem.view frame]];
+ [[self.videoVC view] setBounds:[self.videoTabItem.view bounds]];
+ [self.videoTabItem setView:self.videoVC.view];
+
+ self.advancedVC = [[AccAdvancedVC alloc] initWithNibName:@"AccAdvanced" bundle:nil];
+ [[self.advancedVC view] setFrame:[self.advancedTabItem.view frame]];
+ [[self.advancedVC view] setBounds:[self.advancedTabItem.view bounds]];
+ [self.advancedTabItem setView:self.advancedVC.view];
+
+ self.securityVC = [[AccSecurityVC alloc] initWithNibName:@"AccSecurity" bundle:nil];
+ [[self.securityVC view] setFrame:[self.securityTabItem.view frame]];
+ [[self.securityVC view] setBounds:[self.securityTabItem.view bounds]];
+ [self.securityTabItem setView:self.securityVC.view];
+
+ self.ringVC = [[AccRingVC alloc] initWithNibName:@"AccRing" bundle:nil];
+ [[self.ringVC view] setFrame:[self.ringTabItem.view frame]];
+ [[self.ringVC view] setBounds:[self.ringTabItem.view bounds]];
+ [self.ringTabItem setView:self.ringVC.view];
+}
+
+- (IBAction)removeAccount:(id)sender {
+
+ if(treeController.selectedNodes.count > 0) {
+ QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
+ AccountModel::instance()->remove(qIdx);
+ AccountModel::instance()->save();
+ }
+}
+- (IBAction)addAccount:(id)sender {
+ QModelIndex qIdx = AccountModel::instance()->protocolModel()->selectionModel()->currentIndex();
+
+ NSString* newAccName = [[NSString alloc] initWithFormat:@"New %@ account",
+ AccountModel::instance()->protocolModel()->data(qIdx, Qt::DisplayRole).toString().toNSString(), nil];
+
+ Account* newAcc =AccountModel::instance()->add([newAccName UTF8String], qIdx);
+}
+
+- (IBAction)protocolSelectedChanged:(id)sender {
+
+ int index = [sender indexOfSelectedItem];
+ AccountModel::instance()->protocolModel()->selectionModel()->setCurrentIndex(
+ AccountModel::instance()->protocolModel()->index(index), QItemSelectionModel::ClearAndSelect);
+
+}
+
+- (void) setupSIPPanelsForAccount:(Account*) acc
+{
+ NSTabViewItem* selected = [configPanels selectedTabViewItem];
+
+ // Start by removing all tabs
+ for(NSTabViewItem* item in configPanels.tabViewItems) {
+ [configPanels removeTabViewItem:item];
+ }
+
+ [configPanels insertTabViewItem:generalTabItem atIndex:0];
+ [configPanels insertTabViewItem:audioTabItem atIndex:1];
+ [configPanels insertTabViewItem:videoTabItem atIndex:2];
+ [configPanels insertTabViewItem:advancedTabItem atIndex:3];
+ [configPanels insertTabViewItem:securityTabItem atIndex:4];
+
+ [self.generalVC loadAccount:acc];
+ [self.audioVC loadAccount:acc];
+ [self.videoVC loadAccount:acc];
+ [self.advancedVC loadAccount:acc];
+ [self.securityVC loadAccount:acc];
+}
+
+- (void) setupIAXPanelsForAccount:(Account*) acc
+{
+ NSTabViewItem* selected = [configPanels selectedTabViewItem];
+
+ // Start by removing all tabs
+ for(NSTabViewItem* item in configPanels.tabViewItems) {
+ [configPanels removeTabViewItem:item];
+ }
+
+ [configPanels insertTabViewItem:generalTabItem atIndex:0];
+ [configPanels insertTabViewItem:audioTabItem atIndex:1];
+ [configPanels insertTabViewItem:videoTabItem atIndex:2];
+
+ [self.generalVC loadAccount:acc];
+ [self.audioVC loadAccount:acc];
+ [self.videoVC loadAccount:acc];
+}
+
+- (void) setupRINGPanelsForAccount:(Account*) acc
+{
+ NSTabViewItem* selected = [configPanels selectedTabViewItem];
+
+ // Start by removing all tabs
+ for(NSTabViewItem* item in configPanels.tabViewItems) {
+ [configPanels removeTabViewItem:item];
+ }
+
+ [configPanels insertTabViewItem:ringTabItem atIndex:0];
+ [configPanels insertTabViewItem:audioTabItem atIndex:1];
+ [configPanels insertTabViewItem:videoTabItem atIndex:2];
+ [configPanels insertTabViewItem:advancedTabItem atIndex:3];
+ [configPanels insertTabViewItem:securityTabItem atIndex:4];
+
+ [self.ringVC loadAccount:acc];
+ [self.audioVC loadAccount:acc];
+ [self.videoVC loadAccount:acc];
+ [self.advancedVC loadAccount:acc];
+ [self.securityVC loadAccount:acc];
+}
+
+- (IBAction)toggleAccount:(NSOutlineView*)sender {
+
+ if([sender clickedColumn] < 0)
+ return;
+
+ NSTableColumn* col = [sender.tableColumns objectAtIndex:[sender clickedColumn]];
+ if([col.identifier isEqualToString:COLUMNID_ENABLE]) {
+ NSInteger row = [sender clickedRow];
+ QModelIndex accIdx = AccountModel::instance()->index(row);
+ Account* toToggle = AccountModel::instance()->getAccountByModelIndex(accIdx);
+ NSButtonCell *cell = [col dataCellForRow:row];
+ toToggle->setEnabled(cell.state == NSOnState ? NO : YES);
+ }
+}
+
+#pragma mark - NSOutlineViewDelegate methods
+
+// -------------------------------------------------------------------------------
+// shouldSelectItem:item
+// -------------------------------------------------------------------------------
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
+{
+ return YES;
+}
+
+// -------------------------------------------------------------------------------
+// dataCellForTableColumn:tableColumn:item
+// -------------------------------------------------------------------------------
+- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ NSCell *returnCell = [tableColumn dataCell];
+ return returnCell;
+}
+
+// -------------------------------------------------------------------------------
+// textShouldEndEditing:fieldEditor
+// -------------------------------------------------------------------------------
+- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
+{
+ if ([[fieldEditor string] length] == 0)
+ {
+ // don't allow empty node names
+ return NO;
+ }
+ else
+ {
+ return YES;
+ }
+}
+
+// -------------------------------------------------------------------------------
+// shouldEditTableColumn:tableColumn:item
+//
+// Decide to allow the edit of the given outline view "item".
+// -------------------------------------------------------------------------------
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ return NO;
+}
+
+// -------------------------------------------------------------------------------
+// outlineView:willDisplayCell:forTableColumn:item
+// -------------------------------------------------------------------------------
+- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
+ if(!qIdx.isValid())
+ return;
+
+ if ([[tableColumn identifier] isEqualToString:COLUMNID_NAME])
+ {
+ cell.title = AccountModel::instance()->data(qIdx, Qt::DisplayRole).toString().toNSString();
+ } else if([[tableColumn identifier] isEqualToString:COLUMNID_STATE]) {
+ //cell.title = AccountModel::instance()->data(qIdx, AccountStatusModel::).toString().toNSString();
+ } else if([[tableColumn identifier] isEqualToString:COLUMNID_ENABLE]) {
+ [cell setState:AccountModel::instance()->data(qIdx, Qt::CheckStateRole).value<BOOL>()];
+ }
+}
+
+// -------------------------------------------------------------------------------
+// outlineViewSelectionDidChange:notification
+// -------------------------------------------------------------------------------
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+ // ask the tree controller for the current selection
+ if([[treeController selectedNodes] count] > 0) {
+ QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
+ //Update details view
+ Account* acc = AccountModel::instance()->getAccountByModelIndex(qIdx);
+
+ switch (acc->protocol()) {
+ case Account::Protocol::SIP:
+ NSLog(@"SIP");
+ [self setupSIPPanelsForAccount:acc];
+ break;
+ case Account::Protocol::IAX:
+ NSLog(@"IAX");
+ [self setupIAXPanelsForAccount:acc];
+ break;
+ case Account::Protocol::RING:
+ [self setupRINGPanelsForAccount:acc];
+ NSLog(@"DRING");
+ break;
+ default:
+ break;
+ }
+
+
+ [self.accountDetailsView setHidden:NO];
+ } else {
+ [self.accountDetailsView setHidden:YES];
+ }
+}
+
+#pragma mark - NSMenuDelegate methods
+
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+ QModelIndex qIdx = AccountModel::instance()->protocolModel()->index(index);
+ [item setTitle:AccountModel::instance()->protocolModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
+
+ return YES;
+}
+
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+ return AccountModel::instance()->protocolModel()->rowCount();
+}
+
+
+
+@end