project: use better structure

Create src/ and ui/ sub-folders instead of flat structure
Remove cantarell folder and licence duplicate

Refs #69161

Change-Id: Ifa136b0e26533f4e9d178479fc958a2563917894
diff --git a/src/AccAdvancedVC.h b/src/AccAdvancedVC.h
new file mode 100644
index 0000000..52216be
--- /dev/null
+++ b/src/AccAdvancedVC.h
@@ -0,0 +1,40 @@
+/*
+ *  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.
+ */
+#import <Cocoa/Cocoa.h>
+
+#import <account.h>
+
+@interface AccAdvancedVC : NSViewController <NSTextFieldDelegate> {
+
+}
+
+- (void)loadAccount:(Account *)account;
+
+@end
diff --git a/src/AccAdvancedVC.mm b/src/AccAdvancedVC.mm
new file mode 100644
index 0000000..d4bfeca
--- /dev/null
+++ b/src/AccAdvancedVC.mm
@@ -0,0 +1,254 @@
+/*
+ *  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 REGISTRATION_TAG 0
+#define LOCALPORT_TAG 1
+#define STUNURL_TAG 2
+#define PUBLICADDR_TAG 3
+#define PUBLICPORT_TAG 4
+#define MINAUDIO_TAG 5
+#define MAXAUDIO_TAG 6
+#define MINVIDEO_TAG 7
+#define MAXVIDEO_TAG 8
+
+#import "AccAdvancedVC.h"
+
+@interface AccAdvancedVC ()
+
+@property Account* privateAccount;
+@property (assign) IBOutlet NSTextField *registrationField;
+@property (assign) IBOutlet NSTextField *localPortField;
+@property (assign) IBOutlet NSButton *isUsingSTUN;
+
+@property (assign) IBOutlet NSTextField *STUNserverURLField;
+@property (assign) IBOutlet NSTextField *minAudioRTPRange;
+@property (assign) IBOutlet NSTextField *maxAudioRTPRange;
+@property (assign) IBOutlet NSTextField *minVideoRTPRange;
+@property (assign) IBOutlet NSTextField *maxVideoRTPRange;
+
+
+@property (assign) IBOutlet NSStepper *registrationStepper;
+@property (assign) IBOutlet NSStepper *localPortStepper;
+@property (assign) IBOutlet NSStepper *minAudioPortStepper;
+@property (assign) IBOutlet NSStepper *maxAudioPortStepper;
+@property (assign) IBOutlet NSStepper *minVideoPortStepper;
+@property (assign) IBOutlet NSStepper *maxVideoPortStepper;
+
+@property (assign) IBOutlet NSMatrix *publishAddrAndPortRadioGroup;
+@property (assign) IBOutlet NSTextField *publishedAddrField;
+@property (assign) IBOutlet NSTextField *publishedPortField;
+
+@end
+
+@implementation AccAdvancedVC
+@synthesize privateAccount;
+@synthesize registrationField;
+@synthesize localPortField;
+@synthesize isUsingSTUN;
+@synthesize STUNserverURLField;
+@synthesize minAudioRTPRange;
+@synthesize maxAudioRTPRange;
+@synthesize minVideoRTPRange;
+@synthesize maxVideoRTPRange;
+@synthesize registrationStepper;
+@synthesize localPortStepper;
+@synthesize minAudioPortStepper;
+@synthesize maxAudioPortStepper;
+@synthesize minVideoPortStepper;
+@synthesize maxVideoPortStepper;
+@synthesize publishAddrAndPortRadioGroup;
+@synthesize publishedAddrField;
+@synthesize publishedPortField;
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT Advanced VC");
+    [registrationStepper setTag:REGISTRATION_TAG];
+    [localPortStepper setTag:LOCALPORT_TAG];
+    [minAudioPortStepper setTag:MINAUDIO_TAG];
+    [maxAudioPortStepper setTag:MAXAUDIO_TAG];
+    [minVideoPortStepper setTag:MINVIDEO_TAG];
+    [maxVideoPortStepper setTag:MAXVIDEO_TAG];
+
+    [registrationField setTag:REGISTRATION_TAG];
+    [localPortField setTag:LOCALPORT_TAG];
+    [minAudioRTPRange setTag:MINAUDIO_TAG];
+    [maxAudioRTPRange setTag:MAXAUDIO_TAG];
+    [minVideoRTPRange setTag:MINVIDEO_TAG];
+    [maxVideoRTPRange setTag:MAXVIDEO_TAG];
+
+    [STUNserverURLField setTag:STUNURL_TAG];
+    [publishedPortField setTag:PUBLICPORT_TAG];
+    [publishedAddrField setTag:PUBLICADDR_TAG];
+    
+}
+
+- (void)loadAccount:(Account *)account
+{
+    privateAccount = account;
+    [self updateControlsWithTag:REGISTRATION_TAG];
+    [self updateControlsWithTag:LOCALPORT_TAG];
+    [self updateControlsWithTag:MINAUDIO_TAG];
+    [self updateControlsWithTag:MAXAUDIO_TAG];
+    [self updateControlsWithTag:MINVIDEO_TAG];
+    [self updateControlsWithTag:MAXVIDEO_TAG];
+
+    [STUNserverURLField setStringValue:privateAccount->sipStunServer().toNSString()];
+    [isUsingSTUN setState:privateAccount->isSipStunEnabled()?NSOnState:NSOffState];
+    [STUNserverURLField setEnabled:privateAccount->isSipStunEnabled()];
+
+    if(privateAccount->isPublishedSameAsLocal())
+        [publishAddrAndPortRadioGroup selectCellAtRow:0 column:0];
+    else {
+        [publishAddrAndPortRadioGroup selectCellAtRow:1 column:0];
+    }
+
+    [publishedAddrField setStringValue:privateAccount->publishedAddress().toNSString()];
+    [publishedPortField setIntValue:privateAccount->publishedPort()];
+    [publishedAddrField setEnabled:!privateAccount->isPublishedSameAsLocal()];
+    [publishedPortField setEnabled:!privateAccount->isPublishedSameAsLocal()];
+}
+
+#pragma mark - NSTextFieldDelegate methods
+
+- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
+{
+    NSLog(@"textShouldBeginEditing");
+    return YES;
+}
+
+- (void)control:(NSControl *)control didFailToValidatePartialString:(NSString *)string errorDescription:(NSString *)error
+{
+    NSLog(@"didFailToValidatePartialString");
+}
+
+-(void)controlTextDidBeginEditing:(NSNotification *)obj
+{
+
+}
+
+-(void)controlTextDidChange:(NSNotification *)notif
+{
+    NSTextField *textField = [notif object];
+    NSRange test = [[textField currentEditor] selectedRange];
+
+    [self valueDidChange:textField];
+    //FIXME: saving account lose focus because in NSTreeController we remove and reinsert row so View selction change
+    [textField.window makeFirstResponder:textField];
+    [[textField currentEditor] setSelectedRange:test];
+}
+
+- (IBAction) valueDidChange: (id) sender
+{
+    switch ([sender tag]) {
+        case REGISTRATION_TAG:
+            privateAccount->setRegistrationExpire([sender integerValue]);
+            break;
+        case LOCALPORT_TAG:
+            privateAccount->setLocalPort([sender integerValue]);
+            break;
+        case STUNURL_TAG:
+            privateAccount->setSipStunServer([[sender stringValue] UTF8String]);
+            break;
+        case PUBLICADDR_TAG:
+            privateAccount->setPublishedAddress([[sender stringValue] UTF8String]);
+            break;
+        case PUBLICPORT_TAG:
+            privateAccount->setPublishedPort([sender integerValue]);
+            break;
+        case MINAUDIO_TAG:
+            privateAccount->setAudioPortMin([sender integerValue]);
+            break;
+        case MAXAUDIO_TAG:
+            privateAccount->setAudioPortMax([sender integerValue]);
+            break;
+        case MINVIDEO_TAG:
+            privateAccount->setVideoPortMin([sender integerValue]);
+            break;
+        case MAXVIDEO_TAG:
+            privateAccount->setVideoPortMax([sender integerValue]);
+            break;
+        default:
+            break;
+    }
+    [self updateControlsWithTag:[sender tag]];
+}
+
+- (IBAction)toggleSTUN:(NSButton *)sender
+{
+    privateAccount->setSipStunEnabled([sender state]==NSOnState);
+    [STUNserverURLField setEnabled:privateAccount->isSipStunEnabled()];
+}
+
+- (IBAction)didSwitchPublishedAddress:(NSMatrix *)matrix
+{
+    NSInteger row = [matrix selectedRow];
+    if(row == 0) {
+        privateAccount->setPublishedSameAsLocal(YES);
+    } else {
+        privateAccount->setPublishedSameAsLocal(NO);
+    }
+    [publishedAddrField setEnabled:!privateAccount->isPublishedSameAsLocal()];
+    [publishedPortField setEnabled:!privateAccount->isPublishedSameAsLocal()];
+
+}
+
+- (void) updateControlsWithTag:(NSInteger) tag
+{
+    switch (tag) {
+        case REGISTRATION_TAG:
+            [registrationStepper setIntegerValue:privateAccount->registrationExpire()];
+            [registrationField setIntegerValue:privateAccount->registrationExpire()];
+            break;
+        case LOCALPORT_TAG:
+            [localPortStepper setIntegerValue:privateAccount->localPort()];
+            [localPortField setIntegerValue:privateAccount->localPort()];
+            break;
+        case MINAUDIO_TAG:
+            [minAudioPortStepper setIntegerValue:privateAccount->audioPortMin()];
+            [minAudioRTPRange setIntegerValue:privateAccount->audioPortMin()];
+            break;
+        case MAXAUDIO_TAG:
+            [maxAudioPortStepper setIntegerValue:privateAccount->audioPortMax()];
+            [maxAudioRTPRange setIntegerValue:privateAccount->audioPortMax()];
+            break;
+        case MINVIDEO_TAG:
+            [minVideoPortStepper setIntegerValue:privateAccount->videoPortMin()];
+            [minVideoRTPRange setIntegerValue:privateAccount->videoPortMin()];
+            break;
+        case MAXVIDEO_TAG:
+            [maxVideoPortStepper setIntegerValue:privateAccount->videoPortMax()];
+            [maxVideoRTPRange setIntegerValue:privateAccount->videoPortMax()];
+            break;
+        default:
+            break;
+    }
+}
+
+@end
diff --git a/src/AccAudioVC.h b/src/AccAudioVC.h
new file mode 100644
index 0000000..38f8283
--- /dev/null
+++ b/src/AccAudioVC.h
@@ -0,0 +1,47 @@
+/*
+ *  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.
+ */
+#ifndef ACCAUDIOVC_H
+#define ACCAUDIOVC_H
+
+#import <Cocoa/Cocoa.h>
+
+#import <account.h>
+
+#import "QNSTreeController.h"
+
+@interface AccAudioVC : NSViewController <NSOutlineViewDelegate> {
+
+}
+
+- (void)loadAccount:(Account *)account;
+
+@end
+
+#endif // ACCAUDIOVC_H
\ No newline at end of file
diff --git a/src/AccAudioVC.mm b/src/AccAudioVC.mm
new file mode 100644
index 0000000..704c8cc
--- /dev/null
+++ b/src/AccAudioVC.mm
@@ -0,0 +1,181 @@
+/*
+ *  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_STATE   @"AudioStateColumn"
+#define COLUMNID_CODECS   @"AudioCodecsColumn"
+#define COLUMNID_FREQ     @"AudioFrequencyColumn"
+#define COLUMNID_BITRATE  @"AudioBitrateColumn"
+
+#import "AccAudioVC.h"
+
+#import <QSortFilterProxyModel>
+#import <audio/codecmodel.h>
+#import <accountmodel.h>
+
+@interface AccAudioVC ()
+
+@property Account* privateAccount;
+@property QNSTreeController *treeController;
+@property (assign) IBOutlet NSOutlineView *codecsView;
+
+@end
+
+@implementation AccAudioVC
+@synthesize treeController;
+@synthesize codecsView;
+@synthesize privateAccount;
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT Audio VC");
+}
+
+- (void)loadAccount:(Account *)account
+{
+    privateAccount = account;
+    treeController = [[QNSTreeController alloc] initWithQModel:privateAccount->codecModel()->audioCodecs()];
+
+    [treeController setAvoidsEmptySelection:NO];
+    [treeController setChildrenKeyPath:@"children"];
+
+    [codecsView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
+    [codecsView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
+    [codecsView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
+}
+
+- (IBAction)moveUp:(id)sender {
+    if([[treeController selectedNodes] count] > 0) {
+        QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
+        if(!qIdx.isValid())
+            return;
+
+        QMimeData* mime = privateAccount->codecModel()->audioCodecs()->mimeData(QModelIndexList() << qIdx);
+        privateAccount->codecModel()->audioCodecs()->dropMimeData(mime, Qt::MoveAction, qIdx.row() - 1, 0, QModelIndex());
+    }
+}
+
+- (IBAction)moveDown:(id)sender {
+    if([[treeController selectedNodes] count] > 0) {
+        QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
+        if(!qIdx.isValid())
+            return;
+
+        QMimeData* mime = privateAccount->codecModel()->audioCodecs()->mimeData(QModelIndexList() << qIdx);
+        privateAccount->codecModel()->audioCodecs()->dropMimeData(mime, Qt::MoveAction, qIdx.row() + 1, 0, QModelIndex());
+    }
+}
+
+- (IBAction)toggleCodec:(NSOutlineView*)sender {
+    NSInteger row = [sender clickedRow];
+    NSTableColumn *col = [sender tableColumnWithIdentifier:COLUMNID_STATE];
+    NSButtonCell *cell = [col dataCellForRow:row];
+    QModelIndex qIdx = privateAccount->codecModel()->audioCodecs()->index(row, 0, QModelIndex());
+    privateAccount->codecModel()->audioCodecs()->setData(qIdx, cell.state == NSOnState ? Qt::Unchecked : Qt::Checked, Qt::CheckStateRole);
+}
+
+#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];
+
+    if(item == nil)
+        return returnCell;
+
+    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_STATE]) {
+        [cell setState:privateAccount->codecModel()->audioCodecs()->data(qIdx, Qt::CheckStateRole).value<BOOL>()?NSOnState:NSOffState];
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_CODECS])
+    {
+        cell.title = privateAccount->codecModel()->audioCodecs()->data(qIdx, CodecModel::Role::NAME).toString().toNSString();
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_FREQ])
+    {
+        cell.title = privateAccount->codecModel()->audioCodecs()->data(qIdx, CodecModel::Role::SAMPLERATE).toString().toNSString();
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_BITRATE])
+    {
+        cell.title = privateAccount->codecModel()->audioCodecs()->data(qIdx, CodecModel::Role::BITRATE).toString().toNSString();
+    }
+}
+
+// -------------------------------------------------------------------------------
+//	outlineViewSelectionDidChange:notification
+// -------------------------------------------------------------------------------
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+
+}
+
+@end
diff --git a/src/AccGeneralVC.h b/src/AccGeneralVC.h
new file mode 100644
index 0000000..139fd1b
--- /dev/null
+++ b/src/AccGeneralVC.h
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+#ifndef ACCGENERALVC_H
+#define ACCGENERALVC_H
+
+#import <Cocoa/Cocoa.h>
+
+#import <account.h>
+
+@interface AccGeneralVC : NSViewController <NSTextFieldDelegate> {
+
+}
+
+- (IBAction)toggleUpnp:(NSButton *)sender;
+- (IBAction)toggleAutoAnswer:(NSButton *)sender;
+- (IBAction)toggleCustomAgent:(NSButton *)sender;
+
+- (void)loadAccount:(Account *)account;
+
+@end
+
+#endif // ACCGENERALVC_H
\ No newline at end of file
diff --git a/src/AccGeneralVC.mm b/src/AccGeneralVC.mm
new file mode 100644
index 0000000..cfb92ea
--- /dev/null
+++ b/src/AccGeneralVC.mm
@@ -0,0 +1,182 @@
+/*
+ *  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 ALIAS_TAG 0
+#define HOSTNAME_TAG 1
+#define USERNAME_TAG 2
+#define PASSWORD_TAG 3
+#define USERAGENT_TAG 4
+
+
+#import "AccGeneralVC.h"
+
+#import <accountmodel.h>
+#import <protocolmodel.h>
+#import <qitemselectionmodel.h>
+
+@interface AccGeneralVC ()
+
+@property Account* privateAccount;
+
+@property (assign) IBOutlet NSView *boxingAccount;
+@property (assign) IBOutlet NSView *boxingParameters;
+@property (assign) IBOutlet NSView *boxingCommon;
+
+@property (assign) IBOutlet NSTextField *aliasTextField;
+@property (assign) IBOutlet NSTextField *typeLabel;
+
+@property (assign) IBOutlet NSTextField *serverHostTextField;
+@property (assign) IBOutlet NSTextField *usernameTextField;
+@property (assign) IBOutlet NSSecureTextField *passwordTextField;
+
+@property (assign) IBOutlet NSButton *upnpButton;
+@property (assign) IBOutlet NSButton *autoAnswerButton;
+@property (assign) IBOutlet NSButton *userAgentButton;
+
+@property (assign) IBOutlet NSTextField *userAgentTextField;
+
+@end
+
+@implementation AccGeneralVC
+@synthesize typeLabel;
+@synthesize boxingAccount;
+@synthesize boxingParameters;
+@synthesize boxingCommon;
+@synthesize aliasTextField;
+@synthesize serverHostTextField;
+@synthesize usernameTextField;
+@synthesize passwordTextField;
+@synthesize upnpButton;
+@synthesize autoAnswerButton;
+@synthesize userAgentButton;
+@synthesize userAgentTextField;
+@synthesize privateAccount;
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT General VC");
+    [aliasTextField setTag:ALIAS_TAG];
+    [serverHostTextField setTag:HOSTNAME_TAG];
+    [usernameTextField setTag:USERNAME_TAG];
+    [passwordTextField setTag:PASSWORD_TAG];
+    [userAgentTextField setTag:USERAGENT_TAG];
+}
+
+- (IBAction)toggleUpnp:(NSButton *)sender {
+    privateAccount->setUpnpEnabled([sender state] == NSOnState);
+}
+
+- (IBAction)toggleAutoAnswer:(NSButton *)sender {
+    privateAccount->setAutoAnswer([sender state] == NSOnState);
+}
+
+- (IBAction)toggleCustomAgent:(NSButton *)sender {
+    [self.userAgentTextField setEnabled:[sender state] == NSOnState];
+    privateAccount->setHasCustomUserAgent([sender state] == NSOnState);
+}
+
+- (void)loadAccount:(Account *)account
+{
+
+    privateAccount = account;
+
+    if([account->alias().toNSString() isEqualToString:@"IP2IP"]) {
+        [boxingAccount.subviews setValue:@YES forKeyPath:@"hidden"];
+        [boxingParameters.subviews setValue:@YES forKeyPath:@"hidden"];
+
+        NSLog(@"IP@IP");
+        // Put visible items at top of the frame
+        [boxingCommon setFrameOrigin:NSMakePoint(boxingAccount.frame.origin.x,
+                                                boxingAccount.frame.origin.y - 40)];
+        [boxingCommon setNeedsDisplay:YES];
+
+    } else {
+        [boxingAccount.subviews setValue:@NO forKeyPath:@"hidden"];
+        [boxingParameters.subviews setValue:@NO forKeyPath:@"hidden"];
+
+        [self.aliasTextField setStringValue:account->alias().toNSString()];
+        [self.serverHostTextField setStringValue:account->hostname().toNSString()];
+        [self.usernameTextField setStringValue:account->username().toNSString()];
+        [self.passwordTextField setStringValue:account->password().toNSString()];
+    }
+
+    switch (account->protocol()) {
+        case Account::Protocol::SIP:
+            [self.typeLabel setStringValue:@"SIP"];
+            break;
+        case Account::Protocol::IAX:
+            [self.typeLabel setStringValue:@"IAX"];
+            break;
+        case Account::Protocol::RING:
+            [self.typeLabel setStringValue:@"RING"];
+            break;
+
+        default:
+            break;
+    }
+
+    [upnpButton setState:privateAccount->isUpnpEnabled()];
+    [userAgentButton setState:privateAccount->hasCustomUserAgent()];
+    [userAgentTextField setEnabled:privateAccount->hasCustomUserAgent()];
+    [self.autoAnswerButton setState:privateAccount->isAutoAnswer()];
+    [self.userAgentTextField setStringValue:account->userAgent().toNSString()];
+}
+
+#pragma mark - NSTextFieldDelegate methods
+
+- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
+{
+    return YES;
+}
+
+-(void)controlTextDidChange:(NSNotification *)notif
+{
+    NSTextField *textField = [notif object];
+
+    switch ([textField tag]) {
+        case ALIAS_TAG:
+            privateAccount->setAlias([[textField stringValue] UTF8String]);
+            break;
+        case HOSTNAME_TAG:
+            privateAccount->setHostname([[textField stringValue] UTF8String]);
+            break;
+        case USERNAME_TAG:
+            privateAccount->setUsername([[textField stringValue] UTF8String]);
+            break;
+        case PASSWORD_TAG:
+            privateAccount->setPassword([[textField stringValue] UTF8String]);
+            break;
+        case USERAGENT_TAG:
+            privateAccount->setUserAgent([[textField stringValue] UTF8String]);
+            break;
+        default:
+            break;
+    }
+}
+@end
diff --git a/src/AccRingVC.h b/src/AccRingVC.h
new file mode 100644
index 0000000..df21709
--- /dev/null
+++ b/src/AccRingVC.h
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+#ifndef ACCRINGVC_H
+#define ACCRINGVC_H
+
+#import <Cocoa/Cocoa.h>
+
+#import <account.h>
+
+@interface AccRingVC : NSViewController <NSTextFieldDelegate> {
+    
+    NSTextField *hashField;
+}
+
+- (void)loadAccount:(Account *)account;
+
+@end
+
+#endif // ACCRINGVC_H
diff --git a/src/AccRingVC.mm b/src/AccRingVC.mm
new file mode 100644
index 0000000..88a5f6a
--- /dev/null
+++ b/src/AccRingVC.mm
@@ -0,0 +1,155 @@
+/*
+ *  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 ALIAS_TAG 0
+#define HOSTNAME_TAG 1
+#define USERNAME_TAG 2
+#define PASSWORD_TAG 3
+#define USERAGENT_TAG 4
+
+#import "AccRingVC.h"
+
+@interface AccRingVC ()
+
+@property Account* privateAccount;
+
+@property (assign) IBOutlet NSTextField *aliasTextField;
+@property (assign) IBOutlet NSTextField *typeLabel;
+@property (assign) IBOutlet NSTextField *bootstrapField;
+@property (assign) IBOutlet NSTextField *hashField;
+
+@property (assign) IBOutlet NSButton *upnpButton;
+@property (assign) IBOutlet NSButton *autoAnswerButton;
+@property (assign) IBOutlet NSButton *userAgentButton;
+@property (assign) IBOutlet NSTextField *userAgentTextField;
+
+@end
+
+@implementation AccRingVC
+@synthesize privateAccount;
+@synthesize typeLabel;
+@synthesize bootstrapField;
+@synthesize hashField;
+@synthesize aliasTextField;
+@synthesize upnpButton;
+@synthesize autoAnswerButton;
+@synthesize userAgentButton;
+@synthesize userAgentTextField;
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT Ring VC");
+    [aliasTextField setTag:ALIAS_TAG];
+    [userAgentTextField setTag:USERAGENT_TAG];
+    [bootstrapField setTag:HOSTNAME_TAG];
+}
+
+- (void)loadAccount:(Account *)account
+{
+    if(privateAccount == account)
+        return;
+
+    privateAccount = account;
+
+    [self.aliasTextField setStringValue:account->alias().toNSString()];
+
+    switch (account->protocol()) {
+        case Account::Protocol::SIP:
+            [typeLabel setStringValue:@"SIP"];
+            break;
+        case Account::Protocol::IAX:
+            [typeLabel setStringValue:@"IAX"];
+            break;
+        case Account::Protocol::RING:
+            [typeLabel setStringValue:@"RING"];
+            break;
+
+        default:
+            break;
+    }
+
+    [upnpButton setState:privateAccount->isUpnpEnabled()];
+    [userAgentButton setState:privateAccount->hasCustomUserAgent()];
+    [userAgentTextField setEnabled:privateAccount->hasCustomUserAgent()];
+
+    [autoAnswerButton setState:privateAccount->isAutoAnswer()];
+    [userAgentTextField setStringValue:account->userAgent().toNSString()];
+
+    [bootstrapField setStringValue:account->hostname().toNSString()];
+
+    if([privateAccount->username().toNSString() isEqualToString:@""])
+        [hashField setStringValue:@"Reopen account to see your hash"];
+    else
+        [hashField setStringValue:privateAccount->username().toNSString()];
+
+}
+
+- (IBAction)toggleUpnp:(NSButton *)sender {
+    privateAccount->setUpnpEnabled([sender state] == NSOnState);
+}
+
+- (IBAction)toggleAutoAnswer:(NSButton *)sender {
+    privateAccount->setAutoAnswer([sender state] == NSOnState);
+}
+
+- (IBAction)toggleCustomAgent:(NSButton *)sender {
+    [self.userAgentTextField setEnabled:[sender state] == NSOnState];
+    privateAccount->setHasCustomUserAgent([sender state] == NSOnState);
+}
+
+#pragma mark - NSTextFieldDelegate methods
+
+- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
+{
+    return YES;
+}
+
+-(void)controlTextDidChange:(NSNotification *)notif
+{
+    NSTextField *textField = [notif object];
+
+    switch ([textField tag]) {
+        case ALIAS_TAG:
+            privateAccount->setAlias([[textField stringValue] UTF8String]);
+            break;
+        case HOSTNAME_TAG:
+            privateAccount->setHostname([[textField stringValue] UTF8String]);
+            break;
+        case PASSWORD_TAG:
+            privateAccount->setPassword([[textField stringValue] UTF8String]);
+            break;
+        case USERAGENT_TAG:
+            privateAccount->setUserAgent([[textField stringValue] UTF8String]);
+            break;
+        default:
+            break;
+    }
+}
+
+@end
diff --git a/src/AccSecurityVC.h b/src/AccSecurityVC.h
new file mode 100644
index 0000000..952a8de
--- /dev/null
+++ b/src/AccSecurityVC.h
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+#ifndef ACCSECURITYVC_H
+#define ACCSECURITYVC_H
+
+#import <Cocoa/Cocoa.h>
+
+#import <account.h>
+
+@interface AccSecurityVC : NSViewController<NSPathControlDelegate, NSOpenSavePanelDelegate> {
+
+}
+
+- (void)loadAccount:(Account *)account;
+
+@end
+
+#endif // ACCSECURITYVC_H
\ No newline at end of file
diff --git a/src/AccSecurityVC.mm b/src/AccSecurityVC.mm
new file mode 100644
index 0000000..6302cbe
--- /dev/null
+++ b/src/AccSecurityVC.mm
@@ -0,0 +1,102 @@
+/*
+ *  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.
+ */
+#import "AccSecurityVC.h"
+
+@interface AccSecurityVC ()
+
+@property Account* privateAccount;
+
+@end
+
+@implementation AccSecurityVC
+@synthesize privateAccount;
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT Security VC");
+}
+
+- (void)loadAccount:(Account *)account
+{
+    privateAccount = account;
+}
+
+#pragma mark - NSPathControl delegate methods
+
+/*
+ Delegate method of NSPathControl to determine how the NSOpenPanel will look/behave.
+ */
+- (void)pathControl:(NSPathControl *)pathControl willDisplayOpenPanel:(NSOpenPanel *)openPanel
+{
+    NSLog(@"willDisplayOpenPanel");
+    [openPanel setAllowsMultipleSelection:NO];
+    [openPanel setCanChooseDirectories:NO];
+    [openPanel setCanChooseFiles:YES];
+    [openPanel setResolvesAliases:YES];
+    [openPanel setTitle:NSLocalizedString(@"Choose a file", @"Open panel title")];
+    [openPanel setPrompt:NSLocalizedString(@"Choose", @"Open panel prompt for 'Choose a file'")];
+    [openPanel setDelegate:self];
+}
+
+- (void)pathControl:(NSPathControl *)pathControl willPopUpMenu:(NSMenu *)menu
+{
+
+}
+
+#pragma mark - NSOpenSavePanelDelegate delegate methods
+
+- (void)panel:(id)sender willExpand:(BOOL)expanding
+{
+    //NSLog(@"willExpand");
+}
+
+- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
+{
+    //NSLog(@"userEnteredFilename");
+}
+
+- (void)panelSelectionDidChange:(id)sender
+{
+    //NSLog(@"panelSelectionDidChange");
+}
+
+- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError
+{
+    NSLog(@"validateURL");
+    return YES;
+
+}
+
+- (void)panel:(id)sender didChangeToDirectoryURL:(NSURL *)url
+{
+    //NSLog(@"didChangeToDirectoryURL");
+}
+
+@end
diff --git a/src/AccVideoVC.h b/src/AccVideoVC.h
new file mode 100644
index 0000000..b7fa537
--- /dev/null
+++ b/src/AccVideoVC.h
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+#ifndef ACCVIDEOVC_H
+#define ACCVIDEOVC_H
+
+#import <Cocoa/Cocoa.h>
+
+#import <account.h>
+
+@interface AccVideoVC : NSViewController <NSOutlineViewDelegate> {
+
+}
+
+- (void)loadAccount:(Account *)account;
+
+@end
+
+#endif // ACCVIDEOVC_H
\ No newline at end of file
diff --git a/src/AccVideoVC.mm b/src/AccVideoVC.mm
new file mode 100644
index 0000000..7d3ebe5
--- /dev/null
+++ b/src/AccVideoVC.mm
@@ -0,0 +1,196 @@
+/*
+ *  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_STATE   @"VideoStateColumn"
+#define COLUMNID_CODECS   @"VideoCodecsColumn"
+#define COLUMNID_FREQ     @"VideoFrequencyColumn"
+#define COLUMNID_BITRATE  @"VideoBitrateColumn"
+
+#import "AccVideoVC.h"
+
+#include <QtCore/QSortFilterProxyModel>
+#import <audio/codecmodel.h>
+#import <accountmodel.h>
+
+#import "QNSTreeController.h"
+
+@interface AccVideoVC ()
+
+@property Account* privateAccount;
+@property QNSTreeController *treeController;
+@property (assign) IBOutlet NSOutlineView *codecsView;
+@property (assign) IBOutlet NSView *videoPanelContainer;
+@property (assign) IBOutlet NSButton *toggleVideoButton;
+
+@end
+
+@implementation AccVideoVC
+@synthesize treeController;
+@synthesize codecsView;
+@synthesize privateAccount;
+@synthesize videoPanelContainer;
+@synthesize toggleVideoButton;
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT Video VC");
+}
+
+- (void)loadAccount:(Account *)account
+{
+    privateAccount = account;
+
+    treeController = [[QNSTreeController alloc] initWithQModel:privateAccount->codecModel()->videoCodecs()];
+    [treeController setAvoidsEmptySelection:NO];
+    [treeController setChildrenKeyPath:@"children"];
+
+    [codecsView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
+    [codecsView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
+    [codecsView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
+    [videoPanelContainer setHidden:!privateAccount->isVideoEnabled()];
+    [toggleVideoButton setState:privateAccount->isVideoEnabled()?NSOnState:NSOffState];
+}
+
+- (IBAction)toggleVideoEnabled:(id)sender {
+    privateAccount->setVideoEnabled([sender state] == NSOnState);
+    [videoPanelContainer setHidden:!privateAccount->isVideoEnabled()];
+}
+
+- (IBAction)toggleCodec:(NSOutlineView*)sender {
+    NSInteger row = [sender clickedRow];
+    NSTableColumn *col = [sender tableColumnWithIdentifier:COLUMNID_STATE];
+    NSButtonCell *cell = [col dataCellForRow:row];
+    privateAccount->codecModel()->videoCodecs()->setData(privateAccount->codecModel()->videoCodecs()->index(row, 0, QModelIndex()),
+        cell.state == NSOnState ? Qt::Unchecked : Qt::Checked, Qt::CheckStateRole);
+}
+
+- (IBAction)moveUp:(id)sender {
+
+    if([[treeController selectedNodes] count] > 0) {
+        QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
+        if(!qIdx.isValid())
+            return;
+
+        QMimeData* mime = privateAccount->codecModel()->mimeData(QModelIndexList() << qIdx);
+        privateAccount->codecModel()->dropMimeData(mime, Qt::MoveAction, qIdx.row() - 1, 0, QModelIndex());
+    }
+}
+
+- (IBAction)moveDown:(id)sender {
+    if([[treeController selectedNodes] count] > 0) {
+        QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
+        if(!qIdx.isValid())
+            return;
+
+        QMimeData* mime = privateAccount->codecModel()->mimeData(QModelIndexList() << qIdx);
+        privateAccount->codecModel()->dropMimeData(mime, Qt::MoveAction, qIdx.row() + 1, 0, QModelIndex());
+    }
+}
+
+#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];
+
+    if(item == nil)
+        return returnCell;
+    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_STATE]) {
+        [cell setState:privateAccount->codecModel()->videoCodecs()->data(qIdx, Qt::CheckStateRole).value<BOOL>()?NSOnState:NSOffState];
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_CODECS])
+    {
+        cell.title = privateAccount->codecModel()->videoCodecs()->data(qIdx, CodecModel::Role::NAME).toString().toNSString();
+        [cell setState:privateAccount->codecModel()->videoCodecs()->data(qIdx, Qt::CheckStateRole).value<BOOL>()?NSOnState:NSOffState];
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_FREQ])
+    {
+        cell.title = privateAccount->codecModel()->videoCodecs()->data(qIdx, CodecModel::Role::SAMPLERATE).toString().toNSString();
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_BITRATE])
+    {
+        cell.title = privateAccount->codecModel()->videoCodecs()->data(qIdx, CodecModel::Role::BITRATE).toString().toNSString();
+    }
+}
+
+// -------------------------------------------------------------------------------
+//	outlineViewSelectionDidChange:notification
+// -------------------------------------------------------------------------------
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+    // ask the tree controller for the current selection
+}
+
+@end
diff --git a/src/AccountsVC.h b/src/AccountsVC.h
new file mode 100644
index 0000000..f79fc3e
--- /dev/null
+++ b/src/AccountsVC.h
@@ -0,0 +1,41 @@
+/*
+ *  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.
+ */
+#ifndef ACCOUNTSVC_H
+#define ACCOUNTSVC_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface AccountsVC : NSViewController <NSOutlineViewDelegate, NSMenuDelegate> {
+
+}
+
+@end
+
+#endif // ACCOUNTSVC_H
diff --git a/src/AccountsVC.mm b/src/AccountsVC.mm
new file mode 100644
index 0000000..3bbd086
--- /dev/null
+++ b/src/AccountsVC.mm
@@ -0,0 +1,411 @@
+/*
+ *  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
+#import <QSortFilterProxyModel>
+#import <accountmodel.h>
+#import <protocolmodel.h>
+#import <QItemSelectionModel>
+#import <account.h>
+
+#import "QNSTreeController.h"
+#import "AccGeneralVC.h"
+#import "AccAudioVC.h"
+#import "AccVideoVC.h"
+#import "AccAdvancedVC.h"
+#import "AccSecurityVC.h"
+#import "AccRingVC.h"
+
+// We disabled IAX protocol for now, so don't show it to the user
+class ActiveProtocolModel : public QSortFilterProxyModel
+{
+public:
+    ActiveProtocolModel(QAbstractItemModel* parent) : QSortFilterProxyModel(parent)
+    {
+        setSourceModel(parent);
+    }
+    virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
+    {
+        return sourceModel()->index(source_row,0,source_parent).flags() & Qt::ItemIsEnabled;
+    }
+};
+
+@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 ActiveProtocolModel* proxyProtocolModel;
+@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;
+@synthesize proxyProtocolModel;
+
+- (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)]];
+
+                     });
+
+    self.proxyProtocolModel = new ActiveProtocolModel(AccountModel::instance()->protocolModel());
+    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)moveUp:(id)sender {
+    AccountModel::instance()->moveUp();
+}
+
+- (IBAction)moveDown:(id)sender {
+    AccountModel::instance()->moveDown();
+}
+
+- (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:@"%@ account",
+                AccountModel::instance()->protocolModel()->data(qIdx, Qt::DisplayRole).toString().toNSString(), nil];
+
+    Account* newAcc =AccountModel::instance()->add([newAccName UTF8String], qIdx);
+    AccountModel::instance()->save();
+}
+
+- (IBAction)protocolSelectedChanged:(id)sender {
+
+    int index = [sender indexOfSelectedItem];
+    QModelIndex proxyIdx = proxyProtocolModel->index(index, 0);
+    AccountModel::instance()->protocolModel()->selectionModel()->setCurrentIndex(
+                proxyProtocolModel->mapToSource(proxyIdx), 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]) {
+        Account::RegistrationState state = qvariant_cast<Account::RegistrationState>(AccountModel::instance()->data(qIdx, (int)Account::Role::RegistrationState));
+        switch (state) {
+            case Account::RegistrationState::READY:
+                [cell setTitle:@"Ready"];
+                break;
+            case Account::RegistrationState::TRYING:
+                [cell setTitle:@"Trying..."];
+                break;
+            case Account::RegistrationState::UNREGISTERED:
+                [cell setTitle:@"Unregistered"];
+                break;
+            case Account::RegistrationState::ERROR:
+                [cell setTitle:@"Error"];
+                break;
+            default:
+                break;
+        }
+    } 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
+        AccountModel::instance()->selectionModel()->setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
+        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];
+        AccountModel::instance()->selectionModel()->clearCurrentIndex();
+    }
+}
+
+#pragma mark - NSMenuDelegate methods
+
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+    QModelIndex proxyIdx = proxyProtocolModel->index(index, 0);
+    QModelIndex qIdx = AccountModel::instance()->protocolModel()->index(proxyProtocolModel->mapToSource(proxyIdx).row());
+    [item setTitle:AccountModel::instance()->protocolModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
+
+    return YES;
+}
+
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+    return proxyProtocolModel->rowCount();
+}
+
+
+
+@end
diff --git a/src/AppDelegate.h b/src/AppDelegate.h
new file mode 100644
index 0000000..a0b6053
--- /dev/null
+++ b/src/AppDelegate.h
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+#ifndef APPDELEGATE_H
+#define APPDELEGATE_H
+
+#import <AppKit/NSApplication.h> // NSApplicationDelegate
+
+#import "RingWindowController.h"
+#import "PreferencesWindowController.h"
+
+@interface AppDelegate : NSObject <NSApplicationDelegate, NSUserNotificationCenterDelegate>
+
+- (void) showWizard;
+- (void) showMainWindow;
+
+@end
+
+#endif // APPDELEGATE_H
diff --git a/src/AppDelegate.mm b/src/AppDelegate.mm
new file mode 100644
index 0000000..b73e0e5
--- /dev/null
+++ b/src/AppDelegate.mm
@@ -0,0 +1,135 @@
+/*
+ *  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.
+ */
+#import "AppDelegate.h"
+
+#import <callmodel.h>
+
+#import <accountmodel.h>
+#import <protocolmodel.h>
+#import <QItemSelectionModel>
+#import <account.h>
+
+#import "RingWizardWC.h"
+
+@interface AppDelegate()
+
+@property RingWindowController* ringWindowController;
+@property RingWizardWC* wizard;
+
+@end
+
+@implementation AppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"];
+
+
+    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
+
+    if([self checkForRingAccount]) {
+        [self showMainWindow];
+    } else {
+        [self showWizard];
+    }
+    [self connect];
+}
+
+- (void) connect
+{
+    QObject::connect(CallModel::instance(),
+                     &CallModel::incomingCall,
+                     [=](Call* call) {
+                         BOOL shouldComeToForeground = [[NSUserDefaults standardUserDefaults] boolForKey:@"window_behaviour"];
+                         BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:@"enable_notifications"];
+                         if(shouldComeToForeground)
+                             [NSApp activateIgnoringOtherApps:YES];
+
+                         if(shouldNotify) {
+                             [self showIncomingNotification:call];
+                         }
+                     });
+}
+
+- (void) showIncomingNotification:(Call*) call{
+    NSUserNotification *notification = [[NSUserNotification alloc] init];
+    notification.title = @"Incoming call", call->peerName();
+    //notification.informativeText = @"A notification";
+    notification.soundName = NSUserNotificationDefaultSoundName;
+
+    [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+}
+
+/**
+ * click in MainMenu "Setup Ring"
+ */
+- (IBAction)showWizard:(id)sender {
+    [self showWizard];
+}
+
+- (void) showWizard
+{
+    NSLog(@"Showing wizard");
+    if(self.wizard == nil) {
+        self.wizard = [[RingWizardWC alloc] initWithWindowNibName:@"RingWizard"];
+    }
+    [self.wizard.window orderFront:self];
+}
+
+- (void) showMainWindow
+{
+    if(self.ringWindowController == nil)
+        self.ringWindowController = [[RingWindowController alloc] initWithWindowNibName:@"RingWindow"];
+
+    [self.ringWindowController.window makeKeyAndOrderFront:self];
+}
+
+- (BOOL) checkForRingAccount
+{
+    for (int i = 0 ; i < AccountModel::instance()->rowCount() ; ++i) {
+        QModelIndex idx = AccountModel::instance()->index(i);
+        Account* acc = AccountModel::instance()->getAccountByModelIndex(idx);
+        if(acc->protocol() == Account::Protocol::RING) {
+            return YES;
+        }
+    }
+    return FALSE;
+}
+
+- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
+{
+    if([self checkForRingAccount]) {
+        [self showMainWindow];
+    } else {
+        [self showWizard];
+    }
+    return YES;
+}
+
+@end
diff --git a/src/AudioPrefsVC.h b/src/AudioPrefsVC.h
new file mode 100644
index 0000000..024d955
--- /dev/null
+++ b/src/AudioPrefsVC.h
@@ -0,0 +1,41 @@
+/*
+ *  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.
+ */
+#ifndef AUDIOPREFSVC_H
+#define AUDIOPREFSVC_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface AudioPrefsVC : NSViewController <NSMenuDelegate, NSPathControlDelegate, NSOpenSavePanelDelegate> {
+
+}
+
+@end
+
+#endif // AUDIOPREFSVC_H
diff --git a/src/AudioPrefsVC.mm b/src/AudioPrefsVC.mm
new file mode 100644
index 0000000..16700a6
--- /dev/null
+++ b/src/AudioPrefsVC.mm
@@ -0,0 +1,210 @@
+/*
+ *  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.
+ */
+#import "AudioPrefsVC.h"
+
+#import <audio/settings.h>
+#import <QUrl>
+#import <audio/inputdevicemodel.h>
+#import <audio/outputdevicemodel.h>
+#import <qitemselectionmodel.h>
+
+@interface AudioPrefsVC ()
+
+@property (assign) IBOutlet NSPathControl *recordingsPathControl;
+@property (assign) IBOutlet NSPopUpButton *outputDeviceList;
+@property (assign) IBOutlet NSPopUpButton *inputDeviceList;
+@property (assign) IBOutlet NSButton *alwaysRecordingButton;
+@property (assign) IBOutlet NSButton *muteDTMFButton;
+
+@end
+
+@implementation AudioPrefsVC
+@synthesize recordingsPathControl;
+@synthesize outputDeviceList;
+@synthesize inputDeviceList;
+@synthesize alwaysRecordingButton;
+@synthesize muteDTMFButton;
+
+- (void)loadView
+{
+    [super loadView];
+
+    QModelIndex qInputIdx = Audio::Settings::instance()->inputDeviceModel()->selectionModel()->currentIndex();
+    QModelIndex qOutputIdx = Audio::Settings::instance()->outputDeviceModel()->selectionModel()->currentIndex();
+    
+    [self.outputDeviceList addItemWithTitle:
+            Audio::Settings::instance()->outputDeviceModel()->data(qOutputIdx, Qt::DisplayRole).toString().toNSString()];
+
+    [self.inputDeviceList addItemWithTitle:
+            Audio::Settings::instance()->inputDeviceModel()->data(qInputIdx, Qt::DisplayRole).toString().toNSString()];
+    [self.alwaysRecordingButton setState:
+            Audio::Settings::instance()->isAlwaysRecording()?NSOnState:NSOffState];
+
+    [self.muteDTMFButton setState:
+            Audio::Settings::instance()->areDTMFMuted()?NSOnState:NSOffState];
+
+    if([[Audio::Settings::instance()->recordPath().toNSURL() absoluteString] isEqualToString:@""]) {
+        NSArray * pathComponentArray = [self pathComponentArray];
+        [recordingsPathControl setPathComponentCells:pathComponentArray];
+    }
+}
+
+- (IBAction)toggleMuteDTMF:(NSButton *)sender
+{
+    Audio::Settings::instance()->setDTMFMuted([sender state] == NSOnState);
+}
+
+- (IBAction)toggleAlwaysRecording:(NSButton *)sender
+{
+    Audio::Settings::instance()->setAlwaysRecording([sender state] == NSOnState);
+}
+
+- (IBAction)pathControlSingleClick:(id)sender {
+    // Select that chosen component of the path.
+    [self.recordingsPathControl setURL:[[self.recordingsPathControl clickedPathComponentCell] URL]];
+    Audio::Settings::instance()->setRecordPath(QUrl::fromNSURL(self.recordingsPathControl.URL));
+}
+
+- (IBAction)chooseOutput:(id)sender {
+    int index = [sender indexOfSelectedItem];
+    QModelIndex qIdx = Audio::Settings::instance()->outputDeviceModel()->index(index, 0);
+    Audio::Settings::instance()->outputDeviceModel()->selectionModel()->setCurrentIndex(
+                                                    qIdx, QItemSelectionModel::ClearAndSelect);
+}
+
+- (IBAction)chooseInput:(id)sender {
+    int index = [sender indexOfSelectedItem];
+    QModelIndex qIdx = Audio::Settings::instance()->inputDeviceModel()->index(index, 0);
+    Audio::Settings::instance()->inputDeviceModel()->selectionModel()->setCurrentIndex(
+                                                    qIdx, QItemSelectionModel::ClearAndSelect);
+}
+
+#pragma mark - NSPathControl delegate methods
+
+/*
+ Assemble a set of custom cells to display into an array to pass to the path control.
+ */
+- (NSArray *)pathComponentArray
+{
+    NSMutableArray *pathComponentArray = [[NSMutableArray alloc] init];
+
+    NSFileManager *fileManager = [[NSFileManager alloc] init];
+
+    NSURL* desktopURL = [fileManager URLForDirectory:NSDesktopDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
+    NSURL* documentsURL = [fileManager URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
+    NSURL* userURL = [fileManager URLForDirectory:NSUserDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
+
+    NSPathComponentCell *componentCell;
+
+    // Use utility method to obtain a NSPathComponentCell based on icon, title and URL.
+    componentCell = [self componentCellForType:kGenericFolderIcon withTitle:@"Desktop" URL:desktopURL];
+    [pathComponentArray addObject:componentCell];
+
+    componentCell = [self componentCellForType:kGenericFolderIcon withTitle:@"Documents" URL:documentsURL];
+    [pathComponentArray addObject:componentCell];
+
+    componentCell = [self componentCellForType:kUserFolderIcon withTitle:NSUserName() URL:userURL];
+    [pathComponentArray addObject:componentCell];
+
+    return pathComponentArray;
+}
+
+/*
+ This method is used by pathComponentArray to create a NSPathComponent cell based on icon, title and URL information. 
+ Each path component needs an icon, URL and title.
+ */
+- (NSPathComponentCell *)componentCellForType:(OSType)withIconType withTitle:(NSString *)title URL:(NSURL *)url
+{
+    NSPathComponentCell *componentCell = [[NSPathComponentCell alloc] init];
+
+    NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(withIconType)];
+    [componentCell setImage:iconImage];
+    [componentCell setURL:url];
+    [componentCell setTitle:title];
+
+    return componentCell;
+}
+
+/*
+ Delegate method of NSPathControl to determine how the NSOpenPanel will look/behave.
+ */
+- (void)pathControl:(NSPathControl *)pathControl willDisplayOpenPanel:(NSOpenPanel *)openPanel
+{
+    NSLog(@"willDisplayOpenPanel");
+    [openPanel setAllowsMultipleSelection:NO];
+    [openPanel setCanChooseDirectories:YES];
+    [openPanel setCanChooseFiles:NO];
+    [openPanel setResolvesAliases:YES];
+    [openPanel setTitle:NSLocalizedString(@"Choose a file", @"Open panel title")];
+    [openPanel setPrompt:NSLocalizedString(@"Choose", @"Open panel prompt for 'Choose a directory'")];
+    [openPanel setDelegate:self];
+}
+
+- (void)pathControl:(NSPathControl *)pathControl willPopUpMenu:(NSMenu *)menu
+{
+
+}
+
+#pragma mark - NSOpenSavePanelDelegate delegate methods
+
+- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError
+{
+    [recordingsPathControl setURL:url];
+    return YES;
+}
+
+#pragma mark - NSMenuDelegate methods
+
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+    QModelIndex qIdx;
+
+    if([menu.title isEqualToString:@"inputlist"])
+    {
+        qIdx = Audio::Settings::instance()->inputDeviceModel()->index(index);
+        [item setTitle:Audio::Settings::instance()->inputDeviceModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
+    } else
+    {
+        qIdx = Audio::Settings::instance()->outputDeviceModel()->index(index);
+        [item setTitle:Audio::Settings::instance()->outputDeviceModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
+    }
+
+    return YES;
+}
+
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+    if([menu.title isEqualToString:@"inputlist"])
+        return Audio::Settings::instance()->inputDeviceModel()->rowCount();
+    else
+        return Audio::Settings::instance()->outputDeviceModel()->rowCount();
+}
+
+@end
diff --git a/src/ConversationsViewController.h b/src/ConversationsViewController.h
new file mode 100644
index 0000000..09d4e3b
--- /dev/null
+++ b/src/ConversationsViewController.h
@@ -0,0 +1,42 @@
+/*
+ *  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.
+ */
+#ifndef CONVERSATIONSVC_H
+#define CONVERSATIONSVC_H
+
+#import <Cocoa/Cocoa.h>
+#import "QNSTreeController.h"
+
+@interface ConversationsViewController : NSViewController <NSOutlineViewDelegate> {
+
+}
+
+@end
+
+#endif // CONVERSATIONSVC_H
diff --git a/src/ConversationsViewController.mm b/src/ConversationsViewController.mm
new file mode 100644
index 0000000..4b7ce22
--- /dev/null
+++ b/src/ConversationsViewController.mm
@@ -0,0 +1,163 @@
+/*
+ *  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.
+ */
+#import "ConversationsViewController.h"
+
+#import <callmodel.h>
+#import <QtCore/qitemselectionmodel.h>
+
+#import "CurrentCallVC.h"
+
+#define COLUMNID_CONVERSATIONS @"ConversationsColumn"	// the single column name in our outline view
+
+@interface ConversationsViewController ()
+
+@property CurrentCallVC* currentVC;
+@property (assign) IBOutlet NSView *currentCallView;
+@property QNSTreeController *treeController;
+@property (assign) IBOutlet NSOutlineView *conversationsView;
+
+@end
+
+@implementation ConversationsViewController
+@synthesize conversationsView;
+@synthesize treeController;
+@synthesize currentVC;
+@synthesize currentCallView;
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT Conversations VC");
+
+    treeController = [[QNSTreeController alloc] initWithQModel:CallModel::instance()];
+
+    [treeController setAvoidsEmptySelection:NO];
+    [treeController setChildrenKeyPath:@"children"];
+
+    [self.conversationsView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
+    [self.conversationsView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
+    [self.conversationsView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
+
+    NSInteger idx = [conversationsView columnWithIdentifier:COLUMNID_CONVERSATIONS];
+    [[[[self.conversationsView tableColumns] objectAtIndex:idx] headerCell] setStringValue:@"Conversations"];
+
+    QObject::connect(CallModel::instance(),
+                     &QAbstractItemModel::dataChanged,
+                     [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
+                         [conversationsView reloadDataForRowIndexes:
+                          [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(topLeft.row(), bottomRight.row() + 1)]
+                        columnIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, conversationsView.tableColumns.count)]];
+                         
+                     });
+
+    currentVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
+    [currentCallView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+    [[currentVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+    [currentCallView addSubview:[self.currentVC view]];
+    [currentVC initFrame];
+}
+
+#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];
+    if(item == nil)
+        return returnCell;
+    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
+{
+    if ([[tableColumn identifier] isEqualToString:COLUMNID_CONVERSATIONS])
+    {
+        QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
+        if(qIdx.isValid())
+            cell.title = CallModel::instance()->data(qIdx, Qt::DisplayRole).toString().toNSString();
+    }
+}
+
+// -------------------------------------------------------------------------------
+//	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 by changing selection
+        CallModel::instance()->selectionModel()->setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
+    } else {
+        CallModel::instance()->selectionModel()->clearCurrentIndex();
+    }
+}
+
+
+@end
diff --git a/src/CurrentCallVC.h b/src/CurrentCallVC.h
new file mode 100644
index 0000000..e24cf01
--- /dev/null
+++ b/src/CurrentCallVC.h
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+#ifndef CURRENTCALLVC_H
+#define CURRENTCALLVC_H
+
+#import <Cocoa/Cocoa.h>
+
+class Call;
+
+@interface CurrentCallVC : NSViewController {
+
+}
+
+- (void) initFrame;
+
+@end
+
+#endif // CURRENTCALLVC_H
\ No newline at end of file
diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm
new file mode 100644
index 0000000..ba70063
--- /dev/null
+++ b/src/CurrentCallVC.mm
@@ -0,0 +1,451 @@
+/*
+ *  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.
+ */
+#import "CurrentCallVC.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#import <call.h>
+#import <callmodel.h>
+#import <useractionmodel.h>
+#import <contactmethod.h>
+#import <qabstractitemmodel.h>
+#import <QItemSelectionModel>
+#import <QItemSelection>
+
+#import <video/previewmanager.h>
+#import <video/renderer.h>
+
+/** FrameReceiver class - delegate for AVCaptureSession
+ */
+@interface RendererConnectionsHolder : NSObject
+
+@property QMetaObject::Connection frameUpdated;
+@property QMetaObject::Connection started;
+@property QMetaObject::Connection stopped;
+
+@end
+
+@implementation RendererConnectionsHolder
+
+@end
+
+@interface CurrentCallVC ()
+
+@property (assign) IBOutlet NSTextField *personLabel;
+@property (assign) IBOutlet NSTextField *stateLabel;
+@property (assign) IBOutlet NSButton *holdOnOffButton;
+@property (assign) IBOutlet NSButton *hangUpButton;
+@property (assign) IBOutlet NSButton *recordOnOffButton;
+@property (assign) IBOutlet NSButton *pickUpButton;
+@property (assign) IBOutlet NSTextField *timeSpentLabel;
+@property (assign) IBOutlet NSView *controlsPanel;
+
+@property QHash<int, NSButton*> actionHash;
+
+// Video
+@property (assign) IBOutlet NSView *videoView;
+@property CALayer* videoLayer;
+@property (assign) IBOutlet NSView *previewView;
+@property CALayer* previewLayer;
+
+@property RendererConnectionsHolder* previewHolder;
+@property RendererConnectionsHolder* videoHolder;
+@property QMetaObject::Connection videoStarted;
+
+@end
+
+@implementation CurrentCallVC
+@synthesize personLabel;
+@synthesize actionHash;
+@synthesize stateLabel;
+@synthesize holdOnOffButton;
+@synthesize hangUpButton;
+@synthesize recordOnOffButton;
+@synthesize pickUpButton;
+@synthesize timeSpentLabel;
+@synthesize controlsPanel;
+@synthesize videoView;
+@synthesize videoLayer;
+@synthesize previewLayer;
+@synthesize previewView;
+
+@synthesize previewHolder;
+@synthesize videoHolder;
+
+- (void) updateAllActions
+{
+    for(int i = 0 ; i <= CallModel::instance()->userActionModel()->rowCount() ; i++) {
+        [self updateActionAtIndex:i];
+    }
+}
+
+- (void) updateActionAtIndex:(int) row
+{
+    const QModelIndex& idx = CallModel::instance()->userActionModel()->index(row,0);
+    UserActionModel::Action action = qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION));
+    NSButton* a = actionHash[(int) action];
+    if (a != nil) {
+        [a setEnabled:(idx.flags() & Qt::ItemIsEnabled)];
+        [a setState:(idx.data(Qt::CheckStateRole) == Qt::Checked) ? NSOnState : NSOffState];
+
+        if(action == UserActionModel::Action::HOLD) {
+            [a setTitle:(a.state == NSOnState ? @"Hold off" : @"Hold")];
+        }
+        if(action == UserActionModel::Action::RECORD) {
+            [a setTitle:(a.state == NSOnState ? @"Record off" : @"Record")];
+        }
+    }
+}
+
+-(void) updateCall
+{
+    QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
+    [personLabel setStringValue:CallModel::instance()->data(callIdx, Qt::DisplayRole).toString().toNSString()];
+    [timeSpentLabel setStringValue:CallModel::instance()->data(callIdx, (int)Call::Role::Length).toString().toNSString()];
+
+    Call::State state = CallModel::instance()->data(callIdx, (int)Call::Role::State).value<Call::State>();
+
+    switch (state) {
+        case Call::State::INITIALIZATION:
+            [stateLabel setStringValue:@"Initializing"];
+            break;
+        case Call::State::RINGING:
+            [stateLabel setStringValue:@"Ringing"];
+            break;
+        case Call::State::CURRENT:
+            [stateLabel setStringValue:@"Current"];
+            break;
+        case Call::State::HOLD:
+            [stateLabel setStringValue:@"On Hold"];
+            break;
+        case Call::State::BUSY:
+            [stateLabel setStringValue:@"Busy"];
+            break;
+        case Call::State::OVER:
+            [stateLabel setStringValue:@"Finished"];
+            break;
+        case Call::State::FAILURE:
+            [stateLabel setStringValue:@"Failure"];
+            break;
+        default:
+            break;
+    }
+
+}
+
+- (void)awakeFromNib
+{
+    NSLog(@"INIT CurrentCall VC");
+    [self.view setWantsLayer:YES];
+    [self.view setLayer:[CALayer layer]];
+
+    [controlsPanel setWantsLayer:YES];
+    [controlsPanel setLayer:[CALayer layer]];
+    [controlsPanel.layer setZPosition:2.0];
+    [controlsPanel.layer setBackgroundColor:[NSColor whiteColor].CGColor];
+
+    actionHash[ (int)UserActionModel::Action::ACCEPT] = pickUpButton;
+    actionHash[ (int)UserActionModel::Action::HOLD  ] = holdOnOffButton;
+    actionHash[ (int)UserActionModel::Action::RECORD] = recordOnOffButton;
+    actionHash[ (int)UserActionModel::Action::HANGUP] = hangUpButton;
+
+    videoLayer = [CALayer layer];
+    [videoView setWantsLayer:YES];
+    [videoView setLayer:videoLayer];
+    [videoView.layer setBackgroundColor:[NSColor blackColor].CGColor];
+    [videoView.layer setFrame:videoView.frame];
+    [videoView.layer setContentsGravity:kCAGravityResizeAspect];
+
+    previewLayer = [CALayer layer];
+    [previewView setWantsLayer:YES];
+    [previewView setLayer:previewLayer];
+    [previewLayer setBackgroundColor:[NSColor blackColor].CGColor];
+    [previewLayer setContentsGravity:kCAGravityResizeAspectFill];
+    [previewLayer setFrame:previewView.frame];
+
+    [controlsPanel setWantsLayer:YES];
+    [controlsPanel setLayer:[CALayer layer]];
+    [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
+    [controlsPanel.layer setFrame:controlsPanel.frame];
+
+    previewHolder = [[RendererConnectionsHolder alloc] init];
+    videoHolder = [[RendererConnectionsHolder alloc] init];
+
+    [self connect];
+}
+
+- (void) connect
+{
+    QObject::connect(CallModel::instance()->selectionModel(),
+                     &QItemSelectionModel::currentChanged,
+                     [=](const QModelIndex &current, const QModelIndex &previous) {
+                         if(!current.isValid()) {
+                             [self animateOut];
+                             return;
+                         }
+                         [self updateCall];
+                         [self updateAllActions];
+                         [self animateOut];
+                     });
+
+    QObject::connect(CallModel::instance(),
+                     &QAbstractItemModel::dataChanged,
+                     [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
+                         [self updateCall];
+                     });
+
+    QObject::connect(CallModel::instance()->userActionModel(),
+                     &QAbstractItemModel::dataChanged,
+                     [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
+                         const int first(topLeft.row()),last(bottomRight.row());
+                         for(int i = first; i <= last;i++) {
+                             [self updateActionAtIndex:i];
+                         }
+                     });
+
+    QObject::connect(CallModel::instance(),
+                     &CallModel::callStateChanged,
+                     [self](Call* c, Call::State state) {
+                         [self updateCall];
+    });
+}
+
+-(void) connectVideoSignals
+{
+    QModelIndex idx = CallModel::instance()->selectionModel()->currentIndex();
+    Call* call = CallModel::instance()->getCall(idx);
+    QObject::connect(call,
+                     &Call::videoStarted,
+                     [=](Video::Renderer* renderer) {
+                         NSLog(@"Video started!");
+                         QObject::disconnect(self.videoStarted);
+                         [self connectVideoRenderer:renderer];
+                     });
+
+    if(call->videoRenderer())
+    {
+        [self connectVideoRenderer:call->videoRenderer()];
+    }
+
+    [self connectPreviewRenderer];
+
+}
+
+-(void) connectPreviewRenderer
+{
+    QObject::disconnect(previewHolder.frameUpdated);
+    QObject::disconnect(previewHolder.stopped);
+    QObject::disconnect(previewHolder.started);
+    previewHolder.started = QObject::connect(Video::PreviewManager::instance(),
+                     &Video::PreviewManager::previewStarted,
+                     [=](Video::Renderer* renderer) {
+                         QObject::disconnect(previewHolder.frameUpdated);
+                         previewHolder.frameUpdated = QObject::connect(renderer,
+                                                                       &Video::Renderer::frameUpdated,
+                                                                       [=]() {
+                                                                           [self renderer:Video::PreviewManager::instance()->previewRenderer()
+                                                                       renderFrameForView:previewView];
+                                                                       });
+                     });
+
+    previewHolder.stopped = QObject::connect(Video::PreviewManager::instance(),
+                     &Video::PreviewManager::previewStopped,
+                     [=](Video::Renderer* renderer) {
+                         QObject::disconnect(previewHolder.frameUpdated);
+                        [previewView.layer setContents:nil];
+                     });
+
+    previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance()->previewRenderer(),
+                                                 &Video::Renderer::frameUpdated,
+                                                 [=]() {
+                                                     [self renderer:Video::PreviewManager::instance()->previewRenderer()
+                                                            renderFrameForView:previewView];
+                                                 });
+}
+
+-(void) connectVideoRenderer: (Video::Renderer*)renderer
+{
+    QObject::disconnect(videoHolder.frameUpdated);
+    QObject::disconnect(videoHolder.started);
+    QObject::disconnect(videoHolder.stopped);
+    videoHolder.frameUpdated = QObject::connect(renderer,
+                     &Video::Renderer::frameUpdated,
+                     [=]() {
+                         [self renderer:renderer renderFrameForView:videoView];
+                     });
+
+    videoHolder.started = QObject::connect(renderer,
+                     &Video::Renderer::started,
+                     [=]() {
+                         QObject::disconnect(videoHolder.frameUpdated);
+                         videoHolder.frameUpdated = QObject::connect(renderer,
+                                                                     &Video::Renderer::frameUpdated,
+                                                                     [=]() {
+                                                                         [self renderer:renderer renderFrameForView:videoView];
+                                                                     });
+                     });
+
+    videoHolder.stopped = QObject::connect(renderer,
+                     &Video::Renderer::stopped,
+                     [=]() {
+                         QObject::disconnect(videoHolder.frameUpdated);
+                        [videoView.layer setContents:nil];
+                     });
+}
+
+-(void) renderer: (Video::Renderer*)renderer renderFrameForView:(NSView*) view
+{
+    const QByteArray& data = renderer->currentFrame();
+    QSize res = renderer->size();
+
+    auto buf = reinterpret_cast<const unsigned char*>(data.data());
+
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef newContext = CGBitmapContextCreate((void *)buf,
+                                                    res.width(),
+                                                    res.height(),
+                                                    8,
+                                                    4*res.width(),
+                                                    colorSpace,
+                                                    kCGImageAlphaPremultipliedLast);
+
+
+    CGImageRef newImage = CGBitmapContextCreateImage(newContext);
+
+    /*We release some components*/
+    CGContextRelease(newContext);
+    CGColorSpaceRelease(colorSpace);
+
+    [CATransaction begin];
+    view.layer.contents = (__bridge id)newImage;
+    [CATransaction commit];
+
+    CFRelease(newImage);
+}
+
+- (void) initFrame
+{
+    [self.view setFrame:self.view.superview.bounds];
+    [self.view setHidden:YES];
+    self.view.layer.position = self.view.frame.origin;
+}
+
+# pragma private IN/OUT animations
+
+-(void) animateIn
+{
+    NSLog(@"animateIn");
+    CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
+    [self.view setHidden:NO];
+
+    [CATransaction begin];
+    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
+    [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
+    [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
+    [animation setDuration:0.2f];
+    [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]];
+    [CATransaction setCompletionBlock:^{
+        [self connectVideoSignals];
+    }];
+    [self.view.layer addAnimation:animation forKey:animation.keyPath];
+
+    [CATransaction commit];
+}
+
+-(void) cleanUp
+{
+    QObject::disconnect(videoHolder.frameUpdated);
+    QObject::disconnect(videoHolder.started);
+    QObject::disconnect(videoHolder.stopped);
+    QObject::disconnect(previewHolder.frameUpdated);
+    QObject::disconnect(previewHolder.stopped);
+    QObject::disconnect(previewHolder.started);
+    [videoView.layer setContents:nil];
+    [previewView.layer setContents:nil];
+}
+
+-(void) animateOut
+{
+    NSLog(@"animateOut");
+    if(self.view.frame.origin.x < 0) {
+        NSLog(@"Already hidden");
+        if (CallModel::instance()->selectionModel()->currentIndex().isValid()) {
+            [self animateIn];
+        }
+        return;
+    }
+
+    CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
+    [CATransaction begin];
+    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
+    [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
+    [animation setToValue:[NSValue valueWithPoint:frame.origin]];
+    [animation setDuration:0.2f];
+    [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]];
+
+    [CATransaction setCompletionBlock:^{
+        [self.view setHidden:YES];
+        // first make sure everything is disconnected
+        [self cleanUp];
+        if (CallModel::instance()->selectionModel()->currentIndex().isValid()) {
+            [self animateIn];
+        }
+    }];
+    [self.view.layer addAnimation:animation forKey:animation.keyPath];
+    [CATransaction commit];
+}
+
+/**
+ *  Debug purpose
+ */
+-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
+{
+    NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+}
+
+
+#pragma button methods
+- (IBAction)hangUp:(id)sender {
+    CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::REFUSE;
+}
+
+- (IBAction)accept:(id)sender {
+    CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::ACCEPT;
+}
+
+- (IBAction)toggleRecording:(id)sender {
+    CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::RECORD;
+}
+
+- (IBAction)toggleHold:(id)sender {
+    CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::HOLD;
+}
+
+@end
diff --git a/src/GeneralPrefsVC.h b/src/GeneralPrefsVC.h
new file mode 100644
index 0000000..ef059ae
--- /dev/null
+++ b/src/GeneralPrefsVC.h
@@ -0,0 +1,42 @@
+/*
+ *  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.
+ */
+#ifndef GENERALPREFSVC_H
+#define GENERALPREFSVC_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface GeneralPrefsVC : NSViewController {
+
+    NSTextField *historyChangedLabel;
+}
+
+@end
+
+#endif // GENERALPREFSVC_H
\ No newline at end of file
diff --git a/src/GeneralPrefsVC.mm b/src/GeneralPrefsVC.mm
new file mode 100644
index 0000000..ea6d972
--- /dev/null
+++ b/src/GeneralPrefsVC.mm
@@ -0,0 +1,63 @@
+/*
+ *  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.
+ */
+#import "GeneralPrefsVC.h"
+
+#import <categorizedhistorymodel.h>
+
+@interface GeneralPrefsVC ()
+@property (assign) IBOutlet NSTextField *historyChangedLabel;
+
+@end
+
+@implementation GeneralPrefsVC {
+
+}
+@synthesize historyChangedLabel;
+
+- (void)loadView
+{
+    [super loadView];
+    [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"history_limit" options:NSKeyValueObservingOptionNew context:NULL];
+}
+
+- (IBAction)clearHistory:(id)sender {
+    CategorizedHistoryModel::instance()->clearAllCollections();
+    [historyChangedLabel setHidden:NO];
+}
+
+// KVO handler
+-(void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject
+                       change:(NSDictionary *)aChange context:(void *)aContext
+{
+    NSLog(@"VALUE CHANGED");
+    [historyChangedLabel setHidden:NO];
+}
+
+@end
diff --git a/src/HistoryViewController.h b/src/HistoryViewController.h
new file mode 100644
index 0000000..4c4dbea
--- /dev/null
+++ b/src/HistoryViewController.h
@@ -0,0 +1,41 @@
+/*
+ *  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.
+ */
+#ifndef HISTORYVIEWCONTROLLER_H
+#define HISTORYVIEWCONTROLLER_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface HistoryViewController : NSViewController <NSOutlineViewDelegate> {
+
+}
+
+@end
+
+#endif // HISTORYVIEWCONTROLLER_H
diff --git a/src/HistoryViewController.mm b/src/HistoryViewController.mm
new file mode 100644
index 0000000..5ca5dad
--- /dev/null
+++ b/src/HistoryViewController.mm
@@ -0,0 +1,178 @@
+/*
+ *  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.
+ */
+#import "HistoryViewController.h"
+
+#import <categorizedhistorymodel.h>
+#import <QSortFilterProxyModel>
+#import <callmodel.h>
+#import <call.h>
+#import <contactmethod.h>
+
+#import "backends/MinimalHistoryBackend.h"
+#import "QNSTreeController.h"
+
+#define COLUMNID_DAY			@"DayColumn"	// the single column name in our outline view
+#define COLUMNID_CONTACTMETHOD	@"ContactMethodColumn"	// the single column name in our outline view
+#define COLUMNID_DATE			@"DateColumn"	// the single column name in our outline view
+
+@interface HistoryViewController()
+
+@property NSTreeController *treeController;
+@property (assign) IBOutlet NSOutlineView *historyView;
+@property QSortFilterProxyModel *historyProxyModel;
+@end
+
+@implementation HistoryViewController
+@synthesize treeController;
+@synthesize historyView;
+@synthesize historyProxyModel;
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+    if (self = [super initWithCoder:aDecoder]) {
+        NSLog(@"INIT HVC");
+
+    }
+    return self;
+}
+
+- (void)awakeFromNib
+{
+    historyProxyModel = new QSortFilterProxyModel(CategorizedHistoryModel::instance());
+    historyProxyModel->setSourceModel(CategorizedHistoryModel::instance());
+    historyProxyModel->setSortRole(static_cast<int>(Call::Role::Date));
+    historyProxyModel->sort(0,Qt::DescendingOrder);
+    treeController = [[QNSTreeController alloc] initWithQModel:historyProxyModel];
+
+    [treeController setAvoidsEmptySelection:NO];
+    [treeController setChildrenKeyPath:@"children"];
+
+    [historyView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
+    [historyView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
+    [historyView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
+    [historyView setTarget:self];
+    [historyView setDoubleAction:@selector(placeCall:)];
+
+    CategorizedHistoryModel::instance()->addCollection<MinimalHistoryBackend>(LoadOptions::FORCE_ENABLED);
+}
+
+- (void)placeCall:(id)sender
+{
+    if([[treeController selectedNodes] count] > 0) {
+        Call* c = CallModel::instance()->dialingCall();
+        QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
+        QVariant var = historyProxyModel->data(qIdx, (int)Call::Role::ContactMethod);
+        ContactMethod* m = qvariant_cast<ContactMethod*>(var);
+        if(m){
+            Call* c = CallModel::instance()->dialingCall();
+            c->setDialNumber(m);
+            c << Call::Action::ACCEPT;
+        }
+    }
+}
+
+#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];
+    if(item == nil)
+        return returnCell;
+    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_DAY])
+    {
+        cell.title = historyProxyModel->data(qIdx, Qt::DisplayRole).toString().toNSString();
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_CONTACTMETHOD])
+    {
+        cell.title = historyProxyModel->data(qIdx, (int)Call::Role::Number).toString().toNSString();
+    } else if ([[tableColumn identifier] isEqualToString:COLUMNID_DATE])
+    {
+        cell.title = historyProxyModel->data(qIdx, (int)Call::Role::FormattedDate).toString().toNSString();
+    }
+}
+
+// -------------------------------------------------------------------------------
+//	outlineViewSelectionDidChange:notification
+// -------------------------------------------------------------------------------
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+    // ask the tree controller for the current selection
+    //NSLog(@"outlineViewSelectionDidChange!!");
+}
+
+@end
diff --git a/src/PreferencesViewController.h b/src/PreferencesViewController.h
new file mode 100644
index 0000000..ac0400c
--- /dev/null
+++ b/src/PreferencesViewController.h
@@ -0,0 +1,52 @@
+/*
+ *  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.
+ */
+#ifndef PREFERENCESVIEWCONTROLLER_H
+#define PREFERENCESVIEWCONTROLLER_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface PreferencesViewController : NSViewController <NSToolbarDelegate>
+
+- (void) close;
+@property (nonatomic, assign) NSViewController *currentVC;
+@property (nonatomic, assign) NSViewController *accountsPrefsVC;
+@property (nonatomic, assign) NSViewController *generalPrefsVC;
+@property (nonatomic, assign) NSViewController *audioPrefsVC;
+@property (nonatomic, assign) NSViewController *videoPrefsVC;
+
+- (void)displayGeneral:(NSToolbarItem *)sender;
+- (void)displayAudio:(NSToolbarItem *)sender;
+- (void)displayAncrage:(NSToolbarItem *)sender;
+- (void)displayVideo:(NSToolbarItem *)sender;
+- (void)displayAccounts:(NSToolbarItem *)sender;
+
+@end
+
+#endif // PREFERENCESVIEWCONTROLLER_H
\ No newline at end of file
diff --git a/src/PreferencesViewController.mm b/src/PreferencesViewController.mm
new file mode 100644
index 0000000..5ccde7a
--- /dev/null
+++ b/src/PreferencesViewController.mm
@@ -0,0 +1,262 @@
+/*
+ *  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.
+ */
+#import "PreferencesViewController.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#import <accountmodel.h>
+#import <audio/codecmodel.h>
+
+#import "AccountsVC.h"
+#import "GeneralPrefsVC.h"
+#import "AudioPrefsVC.h"
+#import "VideoPrefsVC.h"
+
+@interface PreferencesViewController ()
+
+@property NSButton* toggleAdvancedSettings;
+
+@end
+
+@implementation PreferencesViewController
+@synthesize toggleAdvancedSettings;
+
+static NSString* const kProfilePrefsIdentifier = @"ProfilesPrefsIdentifier";
+static NSString* const kGeneralPrefsIdentifier = @"GeneralPrefsIdentifier";
+static NSString* const kAudioPrefsIdentifer = @"AudioPrefsIdentifer";
+static NSString* const kAncragePrefsIdentifer = @"AncragePrefsIdentifer";
+static NSString* const kVideoPrefsIdentifer = @"VideoPrefsIdentifer";
+static NSString* const kDonePrefsIdentifer = @"DonePrefsIdentifer";
+static NSString* const kPowerSettingsIdentifer = @"PowerSettingsIdentifer";
+
+-(void)loadView
+{
+    [super loadView];
+
+    [self displayGeneral:nil];
+
+    [self.view setWantsLayer:YES];
+    self.view.layer.backgroundColor = [NSColor windowBackgroundColor].CGColor;
+
+    // Set the layer redraw policy. This would be better done in
+    // the initialization method of a NSView subclass instead of here.
+    self.view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
+
+    [self.view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+    CGRect frame = CGRectOffset(self.view.frame, 0, -self.view.frame.size.height);
+
+    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
+    animation.fromValue = [NSValue valueWithPoint:frame.origin];
+    animation.toValue = [NSValue valueWithPoint:self.view.frame.origin];
+    animation.duration = 0.3f;
+    [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]];
+    [self.view.layer addAnimation:animation forKey:animation.keyPath];
+}
+
+- (void) close
+{
+    // first save codecs for each account
+    for (int i = 0 ; i < AccountModel::instance()->rowCount(); ++i) {
+        QModelIndex qIdx = AccountModel::instance()->index(i);
+        AccountModel::instance()->getAccountByModelIndex(qIdx)->codecModel()->save();
+    }
+
+    // then save accounts
+    AccountModel::instance()->save();
+
+    CGRect frame = CGRectOffset(self.view.frame, 0, -self.view.frame.size.height);
+
+    [CATransaction begin];
+    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
+    animation.fromValue = [NSValue valueWithPoint:self.view.frame.origin];
+    animation.toValue = [NSValue valueWithPoint:frame.origin];
+    animation.duration = 0.3f;
+    [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.7 :0.9 :1 :1]];
+
+    [CATransaction setCompletionBlock:^{
+        [self.view removeFromSuperview];
+    }];
+
+
+    [self.view.layer addAnimation:animation forKey:animation.keyPath];
+    [CATransaction commit];
+}
+
+- (void)displayGeneral:(NSToolbarItem *)sender {
+    if (self.currentVC != nil) {
+        [self.currentVC.view removeFromSuperview];
+    }
+    self.generalPrefsVC = [[GeneralPrefsVC alloc] initWithNibName:@"GeneralPrefs" bundle:nil];
+    [self.view addSubview:self.generalPrefsVC.view];
+    [self.generalPrefsVC.view setFrame:[self.view bounds]];
+    self.currentVC = self.generalPrefsVC;
+}
+
+- (void)displayAudio:(NSToolbarItem *)sender {
+    if (self.currentVC != nil) {
+        [self.currentVC.view removeFromSuperview];
+    }
+    self.audioPrefsVC = [[AudioPrefsVC alloc] initWithNibName:@"AudioPrefs" bundle:nil];
+    [self.view addSubview:self.audioPrefsVC.view];
+    [self.audioPrefsVC.view setFrame:[self.view bounds]];
+    self.currentVC = self.audioPrefsVC;
+}
+
+- (void)displayAncrage:(NSToolbarItem *)sender {
+
+}
+
+- (void)displayVideo:(NSToolbarItem *)sender {
+    if (self.currentVC != nil) {
+        [self.currentVC.view removeFromSuperview];
+    }
+    self.videoPrefsVC = [[VideoPrefsVC alloc] initWithNibName:@"VideoPrefs" bundle:nil];
+    [self.view addSubview:self.videoPrefsVC.view];
+    [self.videoPrefsVC.view setFrame:[self.view bounds]];
+    self.currentVC = self.videoPrefsVC;
+}
+
+- (void) displayAccounts:(NSToolbarItem *) sender {
+    if (self.currentVC != nil) {
+        [self.currentVC.view removeFromSuperview];
+    }
+    self.accountsPrefsVC = [[AccountsVC alloc] initWithNibName:@"Accounts" bundle:nil];
+    [self.view addSubview:self.accountsPrefsVC.view];
+    [self.accountsPrefsVC.view setFrame:[self.view bounds]];
+    self.currentVC = self.accountsPrefsVC;
+}
+
+
+#pragma NSToolbar Delegate
+
+-(NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
+{
+    NSToolbarItem* item = nil;
+
+    if ([itemIdentifier isEqualToString: kProfilePrefsIdentifier]) {
+
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kProfilePrefsIdentifier];
+        [item setImage: [NSImage imageNamed: @"NSUserAccounts"]];
+        [item setLabel: @"Accounts"];
+        [item setAction:@selector(displayAccounts:)];
+    }
+
+    if ([itemIdentifier isEqualToString: kGeneralPrefsIdentifier]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kGeneralPrefsIdentifier];
+        [item setImage: [NSImage imageNamed: @"general"]];
+        [item setLabel: @"General"];
+        [item setAction:@selector(displayGeneral:)];
+    }
+
+    if ([itemIdentifier isEqualToString: kAudioPrefsIdentifer]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kAudioPrefsIdentifer];
+        [item setImage: [NSImage imageNamed: @"audio"]];
+        [item setLabel: @"Audio"];
+        [item setAction:@selector(displayAudio:)];
+    }
+
+    if ([itemIdentifier isEqualToString: kPowerSettingsIdentifer]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kPowerSettingsIdentifer];
+        toggleAdvancedSettings = [[NSButton alloc] initWithFrame:NSMakeRect(0,0,20,20)];
+        [toggleAdvancedSettings setButtonType:NSSwitchButton];
+        [toggleAdvancedSettings setTitle:@""];
+        [toggleAdvancedSettings setState:[[NSUserDefaults standardUserDefaults] boolForKey:@"show_advanced"]];
+        [item setLabel:@"Show Advanced"];
+        [item setView:toggleAdvancedSettings];
+        [item setAction:@selector(togglePowerSettings:)];
+    }
+
+    if ([itemIdentifier isEqualToString: kDonePrefsIdentifer]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kDonePrefsIdentifer];
+        [item setImage: [NSImage imageNamed: @"ic_action_cancel"]];
+        [item setLabel: @"Done"];
+        [item setAction:@selector(closePreferences:)];
+    }
+
+    if ([itemIdentifier isEqualToString: kVideoPrefsIdentifer]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kVideoPrefsIdentifer];
+        [item setImage: [NSImage imageNamed: @"video"]];
+        [item setLabel: @"Video"];
+        [item setAction:@selector(displayVideo:)];
+    }
+
+    return item;
+}
+
+-(NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
+{
+
+    NSMutableArray* items = [NSMutableArray arrayWithObjects:
+                      kPowerSettingsIdentifer,
+                      NSToolbarFlexibleSpaceItemIdentifier,
+                      kGeneralPrefsIdentifier,
+                      kAudioPrefsIdentifer,
+                      kVideoPrefsIdentifer,
+                      //           kAncragePrefsIdentifer,
+                      NSToolbarFlexibleSpaceItemIdentifier,
+                      kDonePrefsIdentifer,
+                      nil];
+
+    if([[NSUserDefaults standardUserDefaults] boolForKey:@"show_advanced"]) {
+        [items insertObject:NSToolbarSpaceItemIdentifier atIndex:5];
+        [items insertObject:kProfilePrefsIdentifier atIndex:2];
+    } else
+        [items insertObject:NSToolbarSpaceItemIdentifier atIndex:5];
+
+    return items;
+}
+
+-(NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
+{
+    NSMutableArray* items = [NSMutableArray arrayWithObjects:
+                             kPowerSettingsIdentifer,
+                             kGeneralPrefsIdentifier,
+                             kAudioPrefsIdentifer,
+                             kVideoPrefsIdentifer,
+                             nil];
+
+    if([[NSUserDefaults standardUserDefaults] boolForKey:@"show_advanced"])
+        [items insertObject:kProfilePrefsIdentifier atIndex:1];
+
+
+    return items;
+}
+
+-(NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
+{
+    return nil;
+}
+
+
+
+
+
+@end
diff --git a/src/PreferencesWindowController.h b/src/PreferencesWindowController.h
new file mode 100644
index 0000000..13eb9aa
--- /dev/null
+++ b/src/PreferencesWindowController.h
@@ -0,0 +1,13 @@
+//
+//  PreferenceWindowController.h
+//  Ring
+//
+//  Created by Alexandre Lision on 2015-02-03.
+//
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface PreferencesWindowController : NSWindowController
+
+@end
diff --git a/src/PreferencesWindowController.mm b/src/PreferencesWindowController.mm
new file mode 100644
index 0000000..97c73d9
--- /dev/null
+++ b/src/PreferencesWindowController.mm
@@ -0,0 +1,23 @@
+//
+//  PreferenceWindowController.m
+//  Ring
+//
+//  Created by Alexandre Lision on 2015-02-03.
+//
+//
+
+#import "PreferencesWindowController.h"
+
+@interface PreferencesWindowController ()
+
+@end
+
+@implementation PreferencesWindowController
+
+- (void)windowDidLoad {
+    [super windowDidLoad];
+    
+    // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
+}
+
+@end
diff --git a/src/QNSTreeController.h b/src/QNSTreeController.h
new file mode 100644
index 0000000..735fe56
--- /dev/null
+++ b/src/QNSTreeController.h
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+#ifndef QNSTREECONTROLLER_H
+#define QNSTREECONTROLLER_H
+
+#import <Cocoa/Cocoa.h>
+#import <qabstractitemmodel.h>
+
+@interface QNSTreeController : NSTreeController {
+
+QAbstractItemModel *privateQModel;
+NSMutableArray* topNodes;
+
+}
+
+- (void*)connect;
+- (id) initWithQModel:(QAbstractItemModel*) model;
+- (QModelIndex) toQIdx:(NSTreeNode*) node;
+
+@end
+
+#endif // QNSTREECONTROLLER_H
\ No newline at end of file
diff --git a/src/QNSTreeController.mm b/src/QNSTreeController.mm
new file mode 100644
index 0000000..75533c2
--- /dev/null
+++ b/src/QNSTreeController.mm
@@ -0,0 +1,185 @@
+/*
+ *  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.
+ */
+#import "QNSTreeController.h"
+
+@interface Node : NSObject {
+    NSMutableArray *children;
+}
+@end
+
+@implementation Node
+- (id) init
+{
+    if (self = [super init]) {
+        children = [[NSMutableArray alloc] init];
+    }
+    return self;
+}
+
+- (void) addChild:(Node*) child
+{
+    [children addObject:child];
+}
+
+@end
+
+
+@implementation QNSTreeController
+
+- (id) initWithQModel:(QAbstractItemModel*) model
+{
+    [super init];
+    self->privateQModel = model;
+
+    topNodes = [[NSMutableArray alloc] init];
+    [self connect];
+
+    [self populate];
+
+    return [self initWithContent:topNodes];
+}
+
+-(void) populate
+{
+    for (int i =0 ; i < self->privateQModel->rowCount() ; ++i){
+        [topNodes insertObject:[[Node alloc] init] atIndex:i];
+    }
+}
+
+- (BOOL)isEditable
+{
+    return self->privateQModel->flags(self->privateQModel->index(0, 0)) | Qt::ItemIsEditable;
+}
+
+- (QModelIndex) toQIdx:(NSTreeNode*) node
+{
+    NSIndexPath* idx = node.indexPath;
+    NSUInteger myArray[[idx length]];
+    [idx getIndexes:myArray];
+    QModelIndex toReturn;
+    if(idx.length == 2)
+        toReturn = self->privateQModel->index(myArray[1], 0, self->privateQModel->index(myArray[0], 0));
+    else
+        toReturn = self->privateQModel->index(myArray[0], 0);
+    return toReturn;
+}
+
+- (void)connect
+{
+    QObject::connect(self->privateQModel,
+                     &QAbstractItemModel::rowsInserted,
+                     [=](const QModelIndex & parent, int first, int last) {
+                         for( int row = first; row <= last; row++) {
+                             if(!parent.isValid()) {
+                                 //Inserting topnode
+                                 Node* n = [[Node alloc] init];
+                                 [self insertObject:n atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
+                             } else {
+                                 Node* child = [[Node alloc] init];
+                                 NSUInteger indexes[] = { (NSUInteger)parent.row(), (NSUInteger)row};
+                                 [self insertObject:child atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:2]];
+                             }
+                         }
+                     }
+                     );
+
+    QObject::connect(self->privateQModel,
+                     &QAbstractItemModel::rowsAboutToBeMoved,
+                     [=](const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) {
+                        NSLog(@"rows about to be moved, start: %d, end: %d, moved to: %d", sourceStart, sourceEnd, destinationRow);
+                        /* first remove the row from old location
+                          * then insert them at the new location on the "rowsMoved signal */
+                         for( int row = sourceStart; row <= sourceEnd; row++) {
+                             //TODO
+                         }
+                     }
+                     );
+
+    QObject::connect(self->privateQModel,
+                     &QAbstractItemModel::rowsMoved,
+                     [=](const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) {
+                         //NSLog(@"rows moved, start: %d, end: %d, moved to: %d", sourceStart, sourceEnd, destinationRow);
+                         /* these rows should have been removed in the "rowsAboutToBeMoved" handler
+                          * now insert them in the new location */
+                         for( int row = sourceStart; row <= sourceEnd; row++) {
+                             //TODO
+                         }
+                     }
+                     );
+
+    QObject::connect(self->privateQModel,
+                     &QAbstractItemModel::rowsAboutToBeRemoved,
+                     [=](const QModelIndex & parent, int first, int last) {
+                         NSLog(@"rows about to be removed");
+                     }
+                     );
+
+    QObject::connect(self->privateQModel,
+                     &QAbstractItemModel::rowsRemoved,
+                     [=](const QModelIndex & parent, int first, int last) {
+                         //NSLog(@"rows removed");
+                         for( int row = first; row <= last; row++) {
+                             if(parent.isValid())
+                             {
+                                 //Removing leaf
+                                 NSUInteger indexes[] = { (NSUInteger)parent.row(), (NSUInteger)row};
+                                 [self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:2]];
+                             } else
+                             {
+                                 [self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
+                             }
+                         }
+                     }
+                     );
+
+    QObject::connect(self->privateQModel,
+                     &QAbstractItemModel::layoutChanged,
+                     [=]() {
+                         //NSLog(@"layout changed");
+                     }
+                     );
+
+    QObject::connect(self->privateQModel,
+                     &QAbstractItemModel::dataChanged,
+                     [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
+                         //NSLog(@"data changed");
+                         for(int row = topLeft.row() ; row <= bottomRight.row() ; ++row)
+                         {
+                             QModelIndex tmpIdx = self->privateQModel->index(row, 0);
+                             if(tmpIdx.row() >= [self.arrangedObjects count]) {
+                                 Node* n = [[Node alloc] init];
+                                 if(tmpIdx.isValid())
+                                     [self insertObject:n atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
+                             }
+                         }
+                     });
+}
+
+@end
diff --git a/src/RingWindowController.h b/src/RingWindowController.h
new file mode 100644
index 0000000..77c93c4
--- /dev/null
+++ b/src/RingWindowController.h
@@ -0,0 +1,48 @@
+/*
+ *  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.
+ */
+#ifndef RINGWINDOWCONTROLLER_H
+#define RINGWINDOWCONTROLLER_H
+
+#import <Cocoa/Cocoa.h>
+#import "HistoryViewController.h"
+#import "PreferencesViewController.h"
+
+@interface RingWindowController : NSWindowController <NSToolbarDelegate, NSTextFieldDelegate>{
+    IBOutlet NSView *currentView;
+}
+@property (nonatomic, assign) NSViewController *myCurrentViewController;
+@property PreferencesViewController* preferencesViewController;
+
+- (IBAction)openPreferences:(id)sender;
+- (IBAction)closePreferences:(NSToolbarItem *)sender;
+
+@end
+
+#endif // RINGWINDOWCONTROLLER_H
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
new file mode 100644
index 0000000..f46bf66
--- /dev/null
+++ b/src/RingWindowController.mm
@@ -0,0 +1,261 @@
+/*
+ *  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.
+ */
+#import "RingWindowController.h"
+
+#import <accountmodel.h>
+#import <callmodel.h>
+#import <account.h>
+#import <call.h>
+
+#import "AppDelegate.h"
+
+@interface RingWindowController ()
+
+@property NSSearchField* callField;
+
+@end
+
+@implementation RingWindowController
+@synthesize callField;
+static NSString* const kSearchViewIdentifier = @"SearchViewIdentifier";
+static NSString* const kPreferencesIdentifier = @"PreferencesIdentifier";
+static NSString* const kCallButtonIdentifer = @"CallButtonIdentifier";
+
+- (void)windowDidLoad {
+    [super windowDidLoad];
+    [self.window setReleasedWhenClosed:FALSE];
+    [self displayMainToolBar];
+}
+
+- (IBAction)openPreferences:(id)sender
+{
+    if(self.preferencesViewController != nil) {
+        [self closePreferences:nil];
+        return;
+    }
+    NSToolbar* tb = [[NSToolbar alloc] initWithIdentifier: @"PreferencesToolbar"];
+
+    self.preferencesViewController = [[PreferencesViewController alloc] initWithNibName:@"PreferencesScreen" bundle:nil];
+    self.myCurrentViewController = self.preferencesViewController;
+
+    NSLayoutConstraint* test = [NSLayoutConstraint constraintWithItem:self.preferencesViewController.view
+                                                            attribute:NSLayoutAttributeWidth
+                                                            relatedBy:NSLayoutRelationEqual
+                                                               toItem:currentView
+                                                            attribute:NSLayoutAttributeWidth
+                                                           multiplier:1.0f
+                                                             constant:0.0f];
+
+    NSLayoutConstraint* test2 = [NSLayoutConstraint constraintWithItem:self.preferencesViewController.view
+                                                             attribute:NSLayoutAttributeHeight
+                                                             relatedBy:NSLayoutRelationEqual
+                                                                toItem:currentView
+                                                             attribute:NSLayoutAttributeHeight
+                                                            multiplier:1.0f
+                                                              constant:0.0f];
+
+    NSLayoutConstraint* test3 = [NSLayoutConstraint constraintWithItem:self.preferencesViewController.view
+                                                             attribute:NSLayoutAttributeCenterX
+                                                             relatedBy:NSLayoutRelationEqual
+                                                                toItem:currentView
+                                                             attribute:NSLayoutAttributeCenterX
+                                                            multiplier:1.0f
+                                                              constant:0.0f];
+
+
+    [currentView addSubview:[self.preferencesViewController view]];
+
+    [tb setDelegate: self.preferencesViewController];
+    [self.window setToolbar: tb];
+
+    [self.window.toolbar setSelectedItemIdentifier:@"GeneralPrefsIdentifier"];
+
+    [currentView addConstraint:test];
+    [currentView addConstraint:test2];
+    [currentView addConstraint:test3];
+    // make sure we automatically resize the controller's view to the current window size
+    [[self.myCurrentViewController view] setFrame:[currentView bounds]];
+
+    // set the view controller's represented object to the number of subviews in that controller
+    // (our NSTextField's value binding will reflect this value)
+    [self.myCurrentViewController setRepresentedObject:[NSNumber numberWithUnsignedInteger:[[[self.myCurrentViewController view] subviews] count]]];
+    
+}
+
+- (IBAction) closePreferences:(NSToolbarItem *)sender {
+    if(self.myCurrentViewController != nil)
+    {
+        [self.preferencesViewController close];
+        [self displayMainToolBar];
+        self.preferencesViewController = nil;
+    }
+}
+
+-(void) displayMainToolBar
+{
+    NSToolbar* tb = [[NSToolbar alloc] initWithIdentifier: @"MainToolbar"];
+    [tb setDisplayMode:NSToolbarDisplayModeIconAndLabel];
+    [tb setDelegate: self];
+    [self.window setToolbar: tb];
+}
+
+// FIXME: This is sick, NSWindowController is catching my selectors
+- (void)displayGeneral:(NSToolbarItem *)sender {
+    [self.preferencesViewController displayGeneral:sender];
+}
+
+- (void)displayAudio:(NSToolbarItem *)sender {
+    [self.preferencesViewController displayAudio:sender];
+}
+
+- (void)displayAncrage:(NSToolbarItem *)sender {
+    [self.preferencesViewController displayAncrage:sender];
+}
+
+- (void)displayVideo:(NSToolbarItem *)sender {
+    [self.preferencesViewController displayVideo:sender];
+}
+
+- (void)displayAccounts:(NSToolbarItem *)sender {
+    [self.preferencesViewController displayAccounts:sender];
+}
+
+- (void)togglePowerSettings:(id)sender
+{
+    BOOL advanced = [[NSUserDefaults standardUserDefaults] boolForKey:@"show_advanced"];
+    [[NSUserDefaults standardUserDefaults] setBool:!advanced forKey:@"show_advanced"];
+    [[NSUserDefaults standardUserDefaults] synchronize];
+
+    NSToolbar* tb = [[NSToolbar alloc] initWithIdentifier: @"PreferencesToolbar"];
+    [tb setDelegate: self.preferencesViewController];
+    [self.preferencesViewController displayGeneral:nil];
+    [self.window setToolbar:tb];
+}
+
+#pragma NSToolbar Delegate
+
+-(NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
+{
+    NSToolbarItem* item = nil;
+
+    if ([itemIdentifier isEqualToString: kSearchViewIdentifier]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kSearchViewIdentifier];
+        callField = [[NSSearchField alloc] initWithFrame:NSMakeRect(0,0,400,21)];
+        [[callField cell] setSearchButtonCell:nil];
+        [callField setToolTip:@"Call"];
+        [callField setAlignment:NSCenterTextAlignment];
+        [callField setDelegate:self];
+        [item setView:callField];
+    }
+
+    if ([itemIdentifier isEqualToString: kCallButtonIdentifer]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kCallButtonIdentifer];
+
+        NSButton *callButton = [[NSButton alloc] initWithFrame:NSMakeRect(0,0,80,30)];
+
+        [callButton setButtonType:NSMomentaryLightButton]; //Set what type button You want
+        [callButton setBezelStyle:NSRoundedBezelStyle]; //Set what style You want]
+        [callButton setBordered:YES];
+        [callButton setTitle:@"Call"];
+        [item setView:callButton];
+        [item setAction:@selector(placeCall:)];
+    }
+
+    if ([itemIdentifier isEqualToString: kPreferencesIdentifier]) {
+        item = [[NSToolbarItem alloc] initWithItemIdentifier: kPreferencesIdentifier];
+        [item setImage: [NSImage imageNamed: @"NSAdvanced"]];
+        [item setLabel: @"Settings"];
+        [item setAction:@selector(openPreferences:)];
+    }
+
+    return item;
+}
+
+- (IBAction)placeCall:(id)sender
+{
+    Call* c = CallModel::instance()->dialingCall();
+
+    // check for a valid ring hash
+    NSCharacterSet *hexSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdefABCDEF"];
+    BOOL valid = [[[callField stringValue] stringByTrimmingCharactersInSet:hexSet] isEqualToString:@""];
+
+    if(valid && callField.stringValue.length == 40) {
+        c->setDialNumber(QString::fromNSString([NSString stringWithFormat:@"ring:%@",[callField stringValue]]));
+    } else {
+        c->setDialNumber(QString::fromNSString([callField stringValue]));
+    }
+
+    c << Call::Action::ACCEPT;
+}
+
+-(NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
+{
+    return [NSArray arrayWithObjects:
+            NSToolbarSpaceItemIdentifier,
+            NSToolbarFlexibleSpaceItemIdentifier,
+            NSToolbarSpaceItemIdentifier,
+            NSToolbarSpaceItemIdentifier,
+            kSearchViewIdentifier,
+            kCallButtonIdentifer,
+            NSToolbarFlexibleSpaceItemIdentifier,
+            kPreferencesIdentifier,
+            nil];
+}
+
+-(NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
+{
+    return [NSArray arrayWithObjects:
+            kSearchViewIdentifier,
+            kCallButtonIdentifer,
+            kPreferencesIdentifier,
+            nil];
+}
+
+-(NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
+{
+    return nil;
+}
+
+#pragma NSTextField Delegate
+
+- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
+{
+    if (commandSelector == @selector(insertNewline:)) {
+        if([[callField stringValue] isNotEqualTo:@""]) {
+            [self placeCall:nil];
+            return YES;
+        }
+    }
+
+    return NO;
+}
+
+
+@end
diff --git a/src/RingWizardWC.h b/src/RingWizardWC.h
new file mode 100644
index 0000000..e3ca858
--- /dev/null
+++ b/src/RingWizardWC.h
@@ -0,0 +1,38 @@
+/*
+ *  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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface RingWizardWC : NSWindowController <NSWindowDelegate>{
+
+    NSButton *goToAppButton;
+}
+
+@end
diff --git a/src/RingWizardWC.mm b/src/RingWizardWC.mm
new file mode 100644
index 0000000..57ed1d9
--- /dev/null
+++ b/src/RingWizardWC.mm
@@ -0,0 +1,186 @@
+/*
+ *  Copyright (C) 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.
+ */
+#import "RingWizardWC.h"
+
+#import <accountmodel.h>
+#import <protocolmodel.h>
+#import <QItemSelectionModel>
+#import <account.h>
+
+#import "AppDelegate.h"
+
+
+@interface RingWizardWC ()
+@property (assign) IBOutlet NSButton *goToAppButton;
+@property (assign) IBOutlet NSTextField *nickname;
+@property (assign) IBOutlet NSProgressIndicator *progressBar;
+@property (assign) IBOutlet NSTextField *indicationLabel;
+@property (assign) IBOutlet NSButton *createButton;
+@end
+
+@implementation RingWizardWC
+@synthesize goToAppButton;
+@synthesize nickname;
+@synthesize progressBar;
+@synthesize indicationLabel;
+@synthesize createButton;
+
+- (void)windowDidLoad {
+    [super windowDidLoad];
+
+    [self.window makeKeyAndOrderFront:nil];
+    [self.window setLevel:NSStatusWindowLevel];
+    [self.window makeMainWindow];
+    [self checkForRingAccount];
+}
+
+- (void) checkForRingAccount
+{
+    for (int i = 0 ; i < AccountModel::instance()->rowCount() ; ++i) {
+        QModelIndex idx = AccountModel::instance()->index(i);
+        Account* acc = AccountModel::instance()->getAccountByModelIndex(idx);
+        if(acc->protocol() == Account::Protocol::RING) {
+            [indicationLabel setStringValue:@"Ring is already ready to work"];
+            [self displayHash:acc->username().toNSString()];
+        }
+    }
+}
+
+- (void) displayHash:(NSString* ) hash
+{
+    [nickname setFrameSize:NSMakeSize(400, nickname.frame.size.height)];
+    [nickname setStringValue:hash];
+    [nickname setEditable:NO];
+    [nickname setHidden:NO];
+
+    [goToAppButton setHidden:NO];
+
+    NSSharingService* emailSharingService = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
+
+    [createButton setTitle:@"Share by mail"];
+    //[createButton setImage:emailSharingService.image];
+    [createButton setAlternateImage:emailSharingService.alternateImage];
+    [createButton setAction:@selector(shareByEmail)];
+}
+
+- (IBAction)createRingAccount:(id)sender {
+
+    [nickname setHidden:YES];
+    [progressBar setHidden:NO];
+    [createButton setEnabled:NO];
+    [indicationLabel setStringValue:@"Just a moment..."];
+
+    QModelIndex qIdx =  AccountModel::instance()->protocolModel()->selectionModel()->currentIndex();
+
+    [self setCallback];
+    [self performSelector:@selector(saveAccount) withObject:nil afterDelay:1];
+
+}
+
+- (void) saveAccount
+{
+    NSString* newAccName = @"My Ring";
+    Account* newAcc = AccountModel::instance()->add([newAccName UTF8String], Account::Protocol::RING);
+    newAcc->setAlias([[nickname stringValue] UTF8String]);
+    newAcc << Account::EditAction::SAVE;
+}
+
+- (void) setCallback
+{
+    QObject::connect(AccountModel::instance(),
+                     &AccountModel::accountStateChanged,
+                     [=](Account *account, const Account::RegistrationState state) {
+                         NSLog(@"Account created!");
+                         [progressBar setHidden:YES];
+                         [createButton setEnabled:YES];
+                         [indicationLabel setStringValue:@"This is your number, share it with your friends!"];
+                         [self displayHash:account->username().toNSString()];
+                     });
+}
+
+- (IBAction)goToApp:(id)sender {
+    [self.window close];
+    AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
+    [appDelegate showMainWindow];
+}
+
+- (void) shareByEmail
+{
+    /*
+     Create the array of items to share.
+     Start with just the content of the text view. If there's an image, add that too.
+     */
+    NSMutableArray *shareItems = [[NSMutableArray alloc] initWithObjects:[nickname stringValue], nil];
+    NSSharingService* emailSharingService = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
+
+    /*
+     Perform the service using the array of items.
+     */
+    [emailSharingService performWithItems:shareItems];
+}
+
+
+# pragma NSWindowDelegate methods
+
+- (BOOL)windowShouldClose:(id)sender
+{
+   NSLog(@"windowShouldClose");
+    return YES;
+}
+
+- (void)windowDidBecomeKey:(NSNotification *)notification
+{
+    NSLog(@"windowDidBecomeKey");
+}
+
+- (void)windowDidResignKey:(NSNotification *)notification
+{
+    NSLog(@"windowDidResignKey");
+}
+
+- (void)windowDidBecomeMain:(NSNotification *)notification
+{
+    NSLog(@"windowDidBecomeMain");
+}
+
+- (void)windowDidResignMain:(NSNotification *)notification
+{
+    NSLog(@"windowDidResignMain");
+    [self.window close];
+}
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+    //NSLog(@"windowWillClose");
+    AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
+    [appDelegate showMainWindow];
+}
+
+@end
diff --git a/src/VideoPrefsVC.h b/src/VideoPrefsVC.h
new file mode 100644
index 0000000..8a85304
--- /dev/null
+++ b/src/VideoPrefsVC.h
@@ -0,0 +1,41 @@
+/*
+ *  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.
+ */
+#ifndef RING_VIDEOPREFSVC_H
+#define RING_VIDEOPREFSVC_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface VideoPrefsVC : NSViewController <NSMenuDelegate> {
+
+}
+
+@end
+
+#endif // RING_VIDEOPREFSVC_H
diff --git a/src/VideoPrefsVC.mm b/src/VideoPrefsVC.mm
new file mode 100644
index 0000000..79a9353
--- /dev/null
+++ b/src/VideoPrefsVC.mm
@@ -0,0 +1,239 @@
+/*
+ *  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.
+ */
+#import "VideoPrefsVC.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#import <QItemSelectionModel>
+#import <QAbstractProxyModel>
+
+#import <video/configurationproxy.h>
+#import <video/sourcemodel.h>
+#import <video/previewmanager.h>
+#import <video/renderer.h>
+#import <video/device.h>
+#import <video/devicemodel.h>
+
+@interface VideoPrefsVC ()
+
+@property (assign) IBOutlet NSView *previewView;
+@property (assign) IBOutlet NSPopUpButton *videoDevicesList;
+@property (assign) IBOutlet NSPopUpButton *sizesList;
+@property (assign) IBOutlet NSPopUpButton *ratesList;
+
+@end
+
+@implementation VideoPrefsVC
+@synthesize previewView;
+@synthesize videoDevicesList;
+@synthesize sizesList;
+@synthesize ratesList;
+
+QMetaObject::Connection frameUpdated;
+QMetaObject::Connection previewStarted;
+QMetaObject::Connection previewStopped;
+
+- (void)loadView
+{
+    [super loadView];
+
+    Video::ConfigurationProxy::deviceModel()->rowCount();
+    Video::ConfigurationProxy::resolutionModel()->rowCount();
+    Video::ConfigurationProxy::rateModel()->rowCount();
+
+    QModelIndex qDeviceIdx = Video::ConfigurationProxy::deviceSelectionModel()->currentIndex();
+    qDeviceIdx = Video::ConfigurationProxy::deviceSelectionModel()->currentIndex();
+
+    [videoDevicesList addItemWithTitle:Video::ConfigurationProxy::deviceModel()->data(qDeviceIdx, Qt::DisplayRole).toString().toNSString()];
+
+    QModelIndex qSizeIdx = Video::ConfigurationProxy::resolutionSelectionModel()->currentIndex();
+    [sizesList addItemWithTitle:Video::ConfigurationProxy::resolutionModel()->data(qSizeIdx, Qt::DisplayRole).toString().toNSString()];
+
+    if(qobject_cast<QAbstractProxyModel*>(Video::ConfigurationProxy::resolutionModel())) {
+        QObject::connect(qobject_cast<QAbstractProxyModel*>(Video::ConfigurationProxy::resolutionModel()),
+                         &QAbstractProxyModel::modelReset,
+                         [=]() {
+                             NSLog(@"resolution Source model changed!!!");
+                         });
+
+    }
+
+    QModelIndex qRate = Video::ConfigurationProxy::rateSelectionModel()->currentIndex();
+    [ratesList addItemWithTitle:Video::ConfigurationProxy::rateModel()->data(qDeviceIdx, Qt::DisplayRole).toString().toNSString()];
+
+    if(qobject_cast<QAbstractProxyModel*>(Video::ConfigurationProxy::rateModel())) {
+        QObject::connect(qobject_cast<QAbstractProxyModel*>(Video::ConfigurationProxy::rateModel()),
+                         &QAbstractProxyModel::modelReset,
+                         [=]() {
+                             NSLog(@"rates Source model changed!!!");
+                         });
+
+    }
+
+
+    [previewView setWantsLayer:YES];
+    [previewView setLayer:[CALayer layer]];
+    [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
+    [previewView.layer setContentsGravity:kCAGravityResizeAspect];
+    [previewView.layer setFrame:previewView.frame];
+    [previewView.layer setBounds:previewView.frame];
+
+    [self connectPreviewSignals];
+}
+
+- (IBAction)chooseDevice:(id)sender {
+    int index = [sender indexOfSelectedItem];
+    QModelIndex qIdx = Video::ConfigurationProxy::deviceModel()->index(index, 0);
+    Video::ConfigurationProxy::deviceSelectionModel()->setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
+}
+
+- (IBAction)chooseSize:(id)sender {
+    int index = [sender indexOfSelectedItem];
+    QModelIndex qIdx = Video::ConfigurationProxy::resolutionModel()->index(index, 0);
+    Video::ConfigurationProxy::resolutionSelectionModel()->setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
+}
+
+- (IBAction)chooseRate:(id)sender {
+    int index = [sender indexOfSelectedItem];
+    QModelIndex qIdx = Video::ConfigurationProxy::rateModel()->index(index, 0);
+    Video::ConfigurationProxy::rateSelectionModel()->setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
+}
+
+- (void) connectPreviewSignals
+{
+    QObject::disconnect(frameUpdated);
+    QObject::disconnect(previewStopped);
+    QObject::disconnect(previewStarted);
+    previewStarted = QObject::connect(Video::PreviewManager::instance(),
+                                             &Video::PreviewManager::previewStarted,
+                                             [=](Video::Renderer* renderer) {
+                                                 NSLog(@"Preview started");
+                                                 QObject::disconnect(frameUpdated);
+                                                 frameUpdated = QObject::connect(renderer,
+                                                                                 &Video::Renderer::frameUpdated,
+                                                                                 [=]() {
+                                                                                     [self renderer:Video::PreviewManager::instance()->previewRenderer() renderFrameForView:previewView];
+                                                                                 });
+                                             });
+
+    previewStopped = QObject::connect(Video::PreviewManager::instance(),
+                                             &Video::PreviewManager::previewStopped,
+                                             [=](Video::Renderer* renderer) {
+                                                 NSLog(@"Preview stopped");
+                                                 QObject::disconnect(frameUpdated);
+                                                 [previewView.layer setContents:nil];
+                                             });
+
+    frameUpdated = QObject::connect(Video::PreviewManager::instance()->previewRenderer(),
+                                                  &Video::Renderer::frameUpdated,
+                                                  [=]() {
+                                                      [self renderer:Video::PreviewManager::instance()->previewRenderer()
+                                                  renderFrameForView:previewView];
+                                                  });
+}
+
+-(void) renderer: (Video::Renderer*)renderer renderFrameForView:(NSView*) view
+{
+    const QByteArray& data = renderer->currentFrame();
+    QSize res = renderer->size();
+
+    auto buf = reinterpret_cast<const unsigned char*>(data.data());
+
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef newContext = CGBitmapContextCreate((void *)buf,
+                                                    res.width(),
+                                                    res.height(),
+                                                    8,
+                                                    4*res.width(),
+                                                    colorSpace,
+                                                    kCGImageAlphaPremultipliedLast);
+
+
+    CGImageRef newImage = CGBitmapContextCreateImage(newContext);
+
+    /*We release some components*/
+    CGContextRelease(newContext);
+    CGColorSpaceRelease(colorSpace);
+
+    [CATransaction begin];
+    view.layer.contents = (__bridge id)newImage;
+    [CATransaction commit];
+
+    CFRelease(newImage);
+}
+
+- (IBAction)togglePreview:(id)sender {
+    if([sender state] == NSOnState)
+        Video::PreviewManager::instance()->startPreview();
+    else
+        Video::PreviewManager::instance()->stopPreview();
+}
+
+- (void)viewWillDisappear
+{
+    Video::PreviewManager::instance()->stopPreview();
+}
+
+#pragma mark - NSMenuDelegate methods
+
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+    QModelIndex qIdx;
+    if([menu.title isEqualToString:@"devices"]) {
+
+        qIdx = Video::ConfigurationProxy::deviceModel()->index(index, 0);
+        [item setTitle:Video::ConfigurationProxy::deviceModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
+
+    } else if([menu.title isEqualToString:@"sizes"]) {
+
+        qIdx = Video::ConfigurationProxy::resolutionModel()->index(index, 0);
+        [item setTitle:Video::ConfigurationProxy::resolutionModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
+
+    } else if([menu.title isEqualToString:@"rates"]) {
+
+        qIdx = Video::ConfigurationProxy::rateModel()->index(index, 0);
+        [item setTitle:Video::ConfigurationProxy::rateModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
+
+    }
+    return YES;
+}
+
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+    if([menu.title isEqualToString:@"devices"]) {
+        return Video::ConfigurationProxy::deviceModel()->rowCount();
+    } else if([menu.title isEqualToString:@"sizes"]) {
+        return Video::ConfigurationProxy::resolutionModel()->rowCount();
+    } else if([menu.title isEqualToString:@"rates"]) {
+        return Video::ConfigurationProxy::rateModel()->rowCount();
+    }
+}
+
+@end
diff --git a/src/backends/MinimalHistoryBackend.h b/src/backends/MinimalHistoryBackend.h
new file mode 100644
index 0000000..50eef51
--- /dev/null
+++ b/src/backends/MinimalHistoryBackend.h
@@ -0,0 +1,50 @@
+/************************************************************************************
+ *   Copyright (C) 2014-2015 by Savoir-Faire Linux                                  *
+ *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>         *
+ *                                                                                  *
+ *   This library is free software; you can redistribute it and/or                  *
+ *   modify it under the terms of the GNU Lesser General Public                     *
+ *   License as published by the Free Software Foundation; either                   *
+ *   version 2.1 of the License, or (at your option) any later version.             *
+ *                                                                                  *
+ *   This library 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              *
+ *   Lesser General Public License for more details.                                *
+ *                                                                                  *
+ *   You should have received a copy of the GNU Lesser General Public               *
+ *   License along with this library; if not, write to the Free Software            *
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA *
+ ***********************************************************************************/
+#ifndef MINIMALHISTORYBACKEND_H
+#define MINIMALHISTORYBACKEND_H
+
+#import <collectioninterface.h>
+
+class Call;
+
+template<typename T> class CollectionMediator;
+
+class LIB_EXPORT MinimalHistoryBackend : public CollectionInterface
+{
+public:
+    explicit MinimalHistoryBackend(CollectionMediator<Call>* mediator);
+    virtual ~MinimalHistoryBackend();
+
+    virtual bool load() override;
+    virtual bool reload() override;
+    virtual bool clear() override;
+    virtual QString    name     () const override;
+    virtual QString    category () const override;
+    virtual QVariant   icon     () const override;
+    virtual bool       isEnabled() const override;
+    virtual QByteArray id       () const override;
+    virtual SupportedFeatures  supportedFeatures() const override;
+    int daysSince(time_t timestamp);
+
+
+private:
+    CollectionMediator<Call>*  m_pMediator;
+};
+
+#endif
diff --git a/src/backends/MinimalHistoryBackend.mm b/src/backends/MinimalHistoryBackend.mm
new file mode 100644
index 0000000..2f126cd
--- /dev/null
+++ b/src/backends/MinimalHistoryBackend.mm
@@ -0,0 +1,290 @@
+/************************************************************************************
+ *   Copyright (C) 2014-2015 by Savoir-Faire Linux                                       *
+ *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>         *
+ *                                                                                  *
+ *   This library is free software; you can redistribute it and/or                  *
+ *   modify it under the terms of the GNU Lesser General Public                     *
+ *   License as published by the Free Software Foundation; either                   *
+ *   version 2.1 of the License, or (at your option) any later version.             *
+ *                                                                                  *
+ *   This library 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              *
+ *   Lesser General Public License for more details.                                *
+ *                                                                                  *
+ *   You should have received a copy of the GNU Lesser General Public               *
+ *   License along with this library; if not, write to the Free Software            *
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA *
+ ***********************************************************************************/
+#import "minimalhistorybackend.h"
+
+#import <Cocoa/Cocoa.h>
+
+//Qt
+#import <QtCore/QFile>
+#import <QtCore/QDir>
+#import <QtCore/qlist.h>
+#import <QtCore/QHash>
+#import <QtWidgets/QApplication>
+#import <QtCore/QStandardPaths>
+#import <collectioneditor.h>
+
+//Ring
+#import <call.h>
+#import <account.h>
+#import <person.h>
+#import <contactmethod.h>
+#import <categorizedhistorymodel.h>
+
+class MinimalHistoryEditor : public CollectionEditor<Call>
+{
+public:
+    MinimalHistoryEditor(CollectionMediator<Call>* m, MinimalHistoryBackend* parent);
+    virtual bool save       ( const Call* item ) override;
+    virtual bool remove     ( const Call* item ) override;
+    virtual bool batchRemove(const QList<Call*> contacts) override;
+    virtual bool edit       ( Call*       item ) override;
+    virtual bool addNew     ( const Call* item ) override;
+    virtual bool addExisting( const Call* item ) override;
+
+private:
+    virtual QVector<Call*> items() const override;
+
+    //Helpers
+    void saveCall(QTextStream& stream, const Call* call);
+    bool regenFile(const Call* toIgnore);
+
+    //Attributes
+    QVector<Call*> m_lItems;
+    MinimalHistoryBackend* m_pCollection;
+};
+
+MinimalHistoryEditor::MinimalHistoryEditor(CollectionMediator<Call>* m, MinimalHistoryBackend* parent) :
+CollectionEditor<Call>(m),m_pCollection(parent)
+{
+
+}
+
+MinimalHistoryBackend::MinimalHistoryBackend(CollectionMediator<Call>* mediator) :
+CollectionInterface(new MinimalHistoryEditor(mediator,this)),m_pMediator(mediator)
+{
+
+}
+
+MinimalHistoryBackend::~MinimalHistoryBackend()
+{
+
+}
+
+void MinimalHistoryEditor::saveCall(QTextStream& stream, const Call* call)
+{
+    const QString direction = (call->direction()==Call::Direction::INCOMING)?
+    Call::HistoryStateName::INCOMING : Call::HistoryStateName::OUTGOING;
+
+    const Account* a = call->account();
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CALLID          ).arg(call->historyId()                     );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_START ).arg(call->startTimeStamp()         );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_STOP  ).arg(call->stopTimeStamp()          );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::ACCOUNT_ID      ).arg(a?QString(a->id()):""          );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DISPLAY_NAME    ).arg(call->peerName()               );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::PEER_NUMBER     ).arg(call->peerContactMethod()->uri() );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DIRECTION       ).arg(direction                      );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::MISSED          ).arg(call->isMissed()               );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::RECORDING_PATH  ).arg(call->recordingPath()          );
+    stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_USED    ).arg(false                          );//TODO
+    if (call->peerContactMethod()->contact()) {
+        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_UID  ).arg(
+                                                                                    QString(call->peerContactMethod()->contact()->uid())
+                                                                                    );
+    }
+    stream << "\n";
+    stream.flush();
+}
+
+bool MinimalHistoryEditor::regenFile(const Call* toIgnore)
+{
+    QDir dir(QString('/'));
+    dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + QString());
+
+    QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') +"history.ini");
+    if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) {
+        QTextStream stream(&file);
+        for (const Call* c : CategorizedHistoryModel::instance()->getHistoryCalls()) {
+            if (c != toIgnore)
+                saveCall(stream, c);
+        }
+        file.close();
+        return true;
+    }
+    return false;
+}
+
+bool MinimalHistoryEditor::save(const Call* call)
+{
+    if (call->collection()->editor<Call>() != this)
+        return addNew(call);
+
+    return regenFile(nullptr);
+}
+
+bool MinimalHistoryEditor::remove(const Call* item)
+{
+    mediator()->removeItem(item);
+    return regenFile(item);
+}
+
+bool MinimalHistoryEditor::batchRemove(const QList<Call*> calls) {
+    QFile::remove(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + "history.ini");
+    return YES;
+}
+
+bool MinimalHistoryEditor::edit( Call* item)
+{
+    Q_UNUSED(item)
+    return false;
+}
+
+bool MinimalHistoryEditor::addNew(const Call* call)
+{
+    QDir dir(QString('/'));
+    dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + QString());
+
+    if ((call->collection() && call->collection()->editor<Call>() == this)  || call->historyId().isEmpty()) return false;
+    //TODO support \r and \n\r end of line
+    QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/')+"history.ini");
+
+    if ( file.open(QIODevice::Append | QIODevice::Text) ) {
+        QTextStream streamFileOut(&file);
+        saveCall(streamFileOut, call);
+        file.close();
+
+        const_cast<Call*>(call)->setCollection(m_pCollection);
+        addExisting(call);
+        return true;
+    }
+    else
+        qWarning() << "Unable to save history";
+    return false;
+}
+
+bool MinimalHistoryEditor::addExisting(const Call* item)
+{
+    m_lItems << const_cast<Call*>(item);
+    mediator()->addItem(item);
+    return true;
+}
+
+QVector<Call*> MinimalHistoryEditor::items() const
+{
+    return m_lItems;
+}
+
+QString MinimalHistoryBackend::name () const
+{
+    return QObject::tr("Minimal history backend");
+}
+
+QString MinimalHistoryBackend::category () const
+{
+    return QObject::tr("History");
+}
+
+QVariant MinimalHistoryBackend::icon() const
+{
+    return QVariant();
+}
+
+bool MinimalHistoryBackend::isEnabled() const
+{
+    return true;
+}
+
+bool MinimalHistoryBackend::load()
+{
+    // get history limit from our preferences set
+    NSInteger historyLimit = [[NSUserDefaults standardUserDefaults] integerForKey:@"history_limit"];
+
+    QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') +"history.ini");
+    if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
+        QMap<QString,QString> hc;
+        while (!file.atEnd()) {
+            QByteArray line = file.readLine().trimmed();
+
+            //The item is complete
+            if ((line.isEmpty() || !line.size()) && hc.size()) {
+                Call* pastCall = Call::buildHistoryCall(hc);
+                if (pastCall->peerName().isEmpty()) {
+                    pastCall->setPeerName(QObject::tr("Unknown"));
+                }
+
+                if(daysSince(pastCall->startTimeStamp()) < historyLimit) {
+                    pastCall->setRecordingPath(hc[ Call::HistoryMapFields::RECORDING_PATH ]);
+                    pastCall->setCollection(this);
+
+                    editor<Call>()->addExisting(pastCall);
+                }
+                hc.clear();
+            }
+            // Add to the current set
+            else {
+                const int idx = line.indexOf("=");
+                if (idx >= 0)
+                    hc[line.left(idx)] = line.right(line.size()-idx-1);
+            }
+        }
+        return true;
+    }
+    else
+        qWarning() << "History doesn't exist or is not readable";
+    return false;
+}
+
+int MinimalHistoryBackend::daysSince(time_t timestamp)
+{
+    NSDate *fromDate;
+    NSDate *toDate;
+
+    NSDate* fromDateTime = [NSDate dateWithTimeIntervalSince1970:timestamp];
+
+    NSCalendar *calendar = [NSCalendar currentCalendar];
+
+    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
+                 interval:NULL forDate:fromDateTime];
+    [calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
+                 interval:NULL forDate:[NSDate date]];
+
+    NSDateComponents *difference = [calendar components:NSCalendarUnitDay
+                                               fromDate:fromDate toDate:toDate options:0];
+
+    return [difference day];
+}
+
+bool MinimalHistoryBackend::reload()
+{
+    return false;
+}
+
+CollectionInterface::SupportedFeatures MinimalHistoryBackend::supportedFeatures() const
+{
+    return (CollectionInterface::SupportedFeatures) (
+                                                     CollectionInterface::SupportedFeatures::NONE  |
+                                                     CollectionInterface::SupportedFeatures::LOAD  |
+                                                     CollectionInterface::SupportedFeatures::CLEAR |
+                                                     CollectionInterface::SupportedFeatures::REMOVE|
+                                                     CollectionInterface::SupportedFeatures::ADD   );
+}
+
+bool MinimalHistoryBackend::clear()
+{
+    editor<Call>()->batchRemove(items<Call>().toList());
+    QList<Call*> calls = items<Call>().toList();
+    for(int i = 0 ; i < calls.count() ; ++i) {
+        CategorizedHistoryModel::instance()->deleteItem(calls[i]);
+    }
+    return true;
+}
+
+QByteArray MinimalHistoryBackend::id() const
+{
+    return "mhb";
+}
diff --git a/src/main.mm b/src/main.mm
new file mode 100644
index 0000000..c1d8676
--- /dev/null
+++ b/src/main.mm
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+#import <AppKit/NSApplication.h> // NSApplicationMain
+#import <qapplication.h>
+#import <QDebug>
+#import <QDir>
+
+int main(int argc, const char *argv[]) {
+
+    QDir dir(QString::fromUtf8(argv[0]));
+    dir.cdUp();
+    dir.cdUp();
+    dir.cd("Plugins");
+    QCoreApplication::addLibraryPath(dir.absolutePath());
+    qDebug() << "" << QCoreApplication::libraryPaths();
+    //Qt event loop will override native event loop
+    QApplication* app = new QApplication(argc, const_cast<char**>(argv));
+    app->setAttribute(Qt::AA_MacPluginApplication);
+
+
+    return NSApplicationMain(argc, argv);
+}