Commit 31d5cc0e authored by Loïc Siret's avatar Loïc Siret Committed by Alexandre Lision

pathpasswordvc: refactoring/extract superclass

This patch extracts superclass and protocols from PathPasswordVC.
Allowing to reuse code for futur components needed by futur releases
like AddingDevices.

Change-Id: I9cc8c88489f14841e5c8f36cc2fa2eb9d967b1b0
Tuleap: #959
parent 72a669e2
......@@ -136,7 +136,11 @@ SET(ringclient_CONTROLLERS
src/BrokerVC.mm
src/BrokerVC.h
src/ConversationVC.mm
src/ConversationVC.h)
src/ConversationVC.h
src/LoadingWCDelegate.h
src/AbstractLoadingWC.h
src/AbstractLoadingWC.mm
)
SET(ringclient_BACKENDS
src/backends/AddressBookBackend.mm
......
/*
* Copyright (C) 2015-2016 Savoir-faire Linux Inc.
* Author: Loïc Siret <loic.siret@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import <Cocoa/Cocoa.h>
#import "LoadingWCDelegate.h"
#import "views/ITProgressIndicator.h"
@interface AbstractLoadingWC : NSWindowController
{
@protected
__unsafe_unretained IBOutlet NSView* errorContainer;
__unsafe_unretained IBOutlet NSView* progressContainer;
__unsafe_unretained IBOutlet NSView* initialContainer;
__unsafe_unretained IBOutlet NSView* finalContainer;
}
/*
* Delegate to inform about completion of the linking process between
* a ContactMethod and a Person.
*/
@property (retain, nonatomic) id <LoadingWCDelegate> delegate;
/*
* caller specific code to identify ongoing action
*/
@property (nonatomic) NSInteger actionCode;
- (id)initWithWindowNibName:(NSString *)nibName
delegate:(id <LoadingWCDelegate>) del
actionCode:(NSInteger) code;
- (id)initWithDelegate:(id <LoadingWCDelegate>) del
actionCode:(NSInteger) code;
- (void)close;
- (void)showLoading;
- (void)showError;
- (void)showFinal;
@end
/*
* Copyright (C) 2015-2016 Savoir-faire Linux Inc.
* Author: Loïc Siret <loic.siret@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "AbstractLoadingWC.h"
@interface AbstractLoadingWC() <NSTextFieldDelegate>
{
}
@end
@implementation AbstractLoadingWC
{
struct {
unsigned int didComplete:1;
unsigned int didCompleteWithActionCode:1;
} delegateRespondsTo;
}
- (id)initWithWindowNibName:(NSString *)nibName delegate:(id <LoadingWCDelegate>) del actionCode:(NSInteger) code
{
if ((self = [super initWithWindowNibName:nibName]) != nil) {
[self setDelegate:del];
self.actionCode = code;
}
return self;
}
- (id)initWithDelegate:(id <LoadingWCDelegate>) del actionCode:(NSInteger) code
{
[NSException raise:NSInternalInconsistencyException
format:@"You must override %@ in a subclass",NSStringFromSelector(_cmd)];
return nil;
}
- (void)windowDidLoad
{
[super windowDidLoad];
[initialContainer setHidden:NO];
[progressContainer setHidden:YES];
[errorContainer setHidden:YES];
[finalContainer setHidden:YES];
}
- (IBAction) cancelPressed:(id)sender
{
[self close];
}
- (IBAction)completeAction:(id)sender
{
[NSException raise:NSInternalInconsistencyException
format:@"You must override %@ in a subclass",NSStringFromSelector(_cmd)];
}
- (void)close
{
[NSApp endSheet:self.window];
[self.window orderOut:self];
}
- (void)showLoading
{
[initialContainer setHidden:YES];
[progressContainer setHidden:NO];
[errorContainer setHidden:YES];
[finalContainer setHidden:YES];
}
- (void)showError
{
[initialContainer setHidden:YES];
[progressContainer setHidden:YES];
[errorContainer setHidden:NO];
[finalContainer setHidden:YES];
}
- (void)showFinal
{
[initialContainer setHidden:YES];
[progressContainer setHidden:YES];
[errorContainer setHidden:YES];
[finalContainer setHidden:NO];
}
@end
......@@ -81,10 +81,6 @@ NSInteger const TAG_NAME = 200;
NSInteger const TAG_STATUS = 300;
NSInteger const TAG_TYPE = 400;
typedef NS_ENUM(NSUInteger, Action) {
ACTION_EXPORT = 0,
ACTION_IMPORT = 1,
};
- (void)awakeFromNib
{
......@@ -199,8 +195,8 @@ typedef NS_ENUM(NSUInteger, Action) {
[configPanels insertTabViewItem:ringTabItem atIndex:0];
[configPanels insertTabViewItem:mediaTabItem atIndex:1];
[configPanels insertTabViewItem:advancedTabItem atIndex:2];
}
- (IBAction)exportAccount:(id)sender
{
passwordWC = [[PathPasswordWC alloc] initWithDelegate:self actionCode:Action::ACTION_EXPORT];
......@@ -214,6 +210,15 @@ typedef NS_ENUM(NSUInteger, Action) {
contextInfo: nil];
#endif
[passwordWC setAllowFileSelection:NO];
if(treeController.selectedNodes.count > 0) {
QStringList accounts;
for (id item : [treeController selectedNodes]) {
QModelIndex accIdx = [treeController toQIdx:item];
accounts << AccountModel::instance().getAccountByModelIndex(accIdx)->id();
}
[passwordWC setAccounts:accounts];
}
[passwordWC showWindow:self];
}
- (IBAction)importAccount:(id)sender
......@@ -228,6 +233,8 @@ typedef NS_ENUM(NSUInteger, Action) {
didEndSelector: nil
contextInfo: nil];
#endif
[passwordWC setAllowFileSelection:YES];
[passwordWC showWindow:self];
}
- (IBAction)toggleAccount:(NSButton*)sender {
......@@ -329,66 +336,6 @@ typedef NS_ENUM(NSUInteger, Action) {
}
}
-(void) didCompleteWithPath:(NSURL*) path Password:(NSString*) password ActionCode:(NSInteger)requestCode
{
switch (requestCode) {
case Action::ACTION_EXPORT:
if(treeController.selectedNodes.count > 0) {
QStringList accounts;
for (id item : [treeController selectedNodes]) {
QModelIndex accIdx = [treeController toQIdx:item];
accounts << AccountModel::instance().getAccountByModelIndex(accIdx)->id();
}
auto finalURL = [path URLByAppendingPathComponent:@"accounts.ring"];
[passwordWC showLoading];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int result = AccountModel::instance().exportAccounts(accounts, finalURL.path.UTF8String, password.UTF8String);
switch (result) {
case 0:
[[NSWorkspace sharedWorkspace] selectFile:finalURL.path inFileViewerRootedAtPath:@""];
[passwordWC close];
break;
default:
[passwordWC showError:NSLocalizedString(@"An error occured during the export", @"Error shown to the user" )];
break;
}
});
}
break;
case Action::ACTION_IMPORT: {
[passwordWC showLoading];
SEL sel = @selector(importAccountsWithPath:andPassword:);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:self];
//arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv setArgument:&path atIndex:2];
[inv setArgument:&password atIndex:3];
// Schedule import for next iteration of event loop in order to let us start the loading anim
[inv performSelector:@selector(invoke) withObject:nil afterDelay:0];
}
break;
default:
NSLog(@"Unrecognized action %d", requestCode);
break;
}
}
- (void) importAccountsWithPath:(NSURL*) path andPassword:(NSString*) password
{
int result = AccountModel::instance().importAccounts(path.path.UTF8String, password.UTF8String);
switch (result) {
case 0:
[passwordWC close];
break;
default:
[passwordWC showError:NSLocalizedString(@"An error occured during the import", @"Error shown to the user" )];
break;
}
}
#pragma mark - NSMenuDelegate methods
......@@ -407,4 +354,10 @@ typedef NS_ENUM(NSUInteger, Action) {
return AccountModel::instance().protocolModel()->rowCount();
}
#pragma mark - PathPasswordDelegate methods
-(void) didCompleteExportWithPath:(NSURL*) fileUrl
{
[[NSWorkspace sharedWorkspace] selectFile:fileUrl.path inFileViewerRootedAtPath:@""];
}
@end
/*
* Copyright (C) 2015-2016 Savoir-faire Linux Inc.
* Author: Loïc Siret <loic.siret@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import <Foundation/Foundation.h>
@protocol LoadingWCDelegate <NSObject>
@end
......@@ -19,32 +19,33 @@
#import <Cocoa/Cocoa.h>
@protocol PathPasswordDelegate <NSObject>
#import <QtCore/qdir.h>
#import "LoadingWCDelegate.h"
#import "AbstractLoadingWC.h"
typedef NS_ENUM(NSUInteger, Action) {
ACTION_EXPORT = 0,
ACTION_IMPORT = 1,
};
@protocol PathPasswordDelegate <LoadingWCDelegate>
@optional
-(void) didCompleteWithPath:(NSURL*) path Password:(NSString*) password;
-(void) didCompleteWithPath:(NSURL*) path Password:(NSString*) password ActionCode:(NSInteger) requestCode;
-(void) didCompleteExportWithPath:(NSURL*) path;
-(void) didCompleteImport;
@end
@interface PathPasswordWC : NSWindowController
/*
* Delegate to inform about completion of the linking process between
* a ContactMethod and a Person.
*/
@property (nonatomic) id <PathPasswordDelegate> delegate;
@interface PathPasswordWC : AbstractLoadingWC
/*
* caller specific code to identify ongoing action
*/
@property (nonatomic) NSInteger actionCode;
/*
* Custom init
/**
* Allow the NSPathControl of this window to select files or not
*/
- (id)initWithDelegate:(id <PathPasswordDelegate>) del actionCode:(NSInteger) code;
@property (nonatomic) BOOL allowFileSelection;
/**
* password string contained in passwordField.
......@@ -54,20 +55,8 @@
@property (retain) NSString* password;
/**
* Allow the NSPathControl of this window to select files or not
*/
@property (nonatomic) BOOL allowFileSelection;
/*
* Show progress during action completion
* Object uses to store account to exports
*/
- (void)showLoading;
/*
* Display error message to the user
*/
- (void)showError:(NSString*) error;
@property (assign) QStringList accounts;
@end
......@@ -18,56 +18,46 @@
*/
#import "PathPasswordWC.h"
//LRC
#import <accountmodel.h>
//Ring
#import "views/ITProgressIndicator.h"
@interface PathPasswordWC() <NSTextFieldDelegate>{
__unsafe_unretained IBOutlet NSView* errorContainer;
__unsafe_unretained IBOutlet NSTextField* errorLabel;
__unsafe_unretained IBOutlet ITProgressIndicator* progressView;
__unsafe_unretained IBOutlet NSView* pathPasswordContainer;
__unsafe_unretained IBOutlet NSSecureTextField* passwordField;
__unsafe_unretained IBOutlet NSPathControl* path;
__unsafe_unretained IBOutlet NSSecureTextField* passwordField;
__unsafe_unretained IBOutlet NSTextField* errorField;
__unsafe_unretained IBOutlet ITProgressIndicator* progressIndicator;
}
@end
@implementation PathPasswordWC {
struct {
unsigned int didComplete:1;
unsigned int didCompleteWithActionCode:1;
unsigned int didCompleteExport:1;
unsigned int didCompleteImport:1;
} delegateRespondsTo;
}
@synthesize accounts;
- (id)initWithDelegate:(id <PathPasswordDelegate>) del actionCode:(NSInteger) code
{
if ((self = [super initWithWindowNibName:@"PathPasswordWindow"]) != nil) {
[self setDelegate:del];
self.actionCode = code;
}
return self;
return [super initWithWindowNibName:@"PathPasswordWindow" delegate:del actionCode:code];
}
- (void)windowDidLoad
{
[super windowDidLoad];
[path setURL: [NSURL fileURLWithPath:NSHomeDirectory()]];
[progressView setNumberOfLines:30];
[progressView setWidthOfLine:2];
[progressView setLengthOfLine:5];
[progressView setInnerMargin:20];
[progressView setHidden:YES];
}
- (void)setDelegate:(id <PathPasswordDelegate>)aDelegate
{
if (self.delegate != aDelegate) {
_delegate = aDelegate;
delegateRespondsTo.didComplete = [self.delegate respondsToSelector:@selector(didCompleteWithPath:Password:)];
delegateRespondsTo.didCompleteWithActionCode = [self.delegate respondsToSelector:@selector(didCompleteWithPath:Password:ActionCode:)];
[super setDelegate: aDelegate];
delegateRespondsTo.didCompleteExport = [self.delegate respondsToSelector:@selector(didCompleteExportWithPath:)];
delegateRespondsTo.didCompleteImport = [self.delegate respondsToSelector:@selector(didCompleteWithImport)];
}
}
......@@ -77,34 +67,83 @@
[path setAllowedTypes:_allowFileSelection ? nil : [NSArray arrayWithObject:@"public.folder"]];
}
- (IBAction) cancelPressed:(id)sender
{
[NSApp endSheet:self.window];
[self.window orderOut:self];
}
- (IBAction)completeAction:(id)sender
{
if (delegateRespondsTo.didComplete)
[self.delegate didCompleteWithPath:path.URL Password:passwordField.stringValue];
else if (delegateRespondsTo.didCompleteWithActionCode)
[self.delegate didCompleteWithPath:path.URL Password:passwordField.stringValue ActionCode:self.actionCode];
[self didCompleteWithPath:path.URL Password:passwordField.stringValue ActionCode:self.actionCode];
}
- (void)showLoading
{
[progressView setHidden:NO];
[pathPasswordContainer setHidden:YES];
[errorContainer setHidden:YES];
[progressView setAnimates:YES];
[progressIndicator setNumberOfLines:30];
[progressIndicator setWidthOfLine:2];
[progressIndicator setLengthOfLine:5];
[progressIndicator setInnerMargin:20];
[super showLoading];
}
-(void) didCompleteWithPath:(NSURL*) path Password:(NSString*) password ActionCode:(NSInteger)requestCode
{
switch (requestCode) {
case Action::ACTION_EXPORT:
{
auto finalURL = [path URLByAppendingPathComponent:@"accounts.ring"];
[self showLoading];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int result = AccountModel::instance().exportAccounts(accounts, finalURL.path.UTF8String, password.UTF8String);
switch (result) {
case 0:
if (delegateRespondsTo.didCompleteExport){
[((id<PathPasswordDelegate>)self.delegate) didCompleteExportWithPath:finalURL];
}
[self close];
break;
default:{
[errorField setStringValue:NSLocalizedString(@"An error occured during the export", @"Error shown to the user" )];
[self showError] ;
}break;
}
});
}
break;
case Action::ACTION_IMPORT: {
[self showLoading];
SEL sel = @selector(importAccountsWithPath:andPassword:);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:self];
//arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv setArgument:&path atIndex:2];
[inv setArgument:&password atIndex:3];
// Schedule import for next iteration of event loop in order to let us start the loading anim
[inv performSelector:@selector(invoke) withObject:nil afterDelay:0];
}
break;
default:
NSLog(@"Unrecognized action %d", requestCode);
break;
}
}
- (void)showError:(NSString*) error
- (void) importAccountsWithPath:(NSURL*) path andPassword:(NSString*) password
{
[progressView setHidden:YES];
[pathPasswordContainer setHidden:YES];
[errorContainer setHidden:NO];
[errorLabel setStringValue:error];
int result = AccountModel::instance().importAccounts(path.path.UTF8String, password.UTF8String);
switch (result) {
case 0:
if (delegateRespondsTo.didCompleteImport)
[((id<PathPasswordDelegate>)self.delegate) didCompleteImport];
[self close];
break;
default:
{
[errorField setStringValue:NSLocalizedString(@"An error occured during the import", @"Error shown to the user" )];
[self showError];
}
break;
}
}
@end
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9532"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="PathPasswordWC">
<connections>
<outlet property="errorContainer" destination="ty1-sj-tT6" id="eEy-Cr-yiw"/>
<outlet property="errorLabel" destination="G1N-th-ZtP" id="PMs-b1-oJo"/>
<outlet property="errorField" destination="G1N-th-ZtP" id="tha-8j-8jR"/>
<outlet property="finalContainer" destination="XMQ-jJ-yqG" id="tI5-N3-LpJ"/>
<outlet property="initialContainer" destination="xUT-yB-g8Q" id="nwe-zs-Gxs"/>
<outlet property="passwordField" destination="vej-Z8-dOm" id="Ff0-Rb-Al6"/>
<outlet property="path" destination="ww6-ha-GhI" id="gdx-sh-x5J"/>
<outlet property="pathPasswordContainer" destination="xUT-yB-g8Q" id="xyd-vF-fD8"/>
<outlet property="progressView" destination="Ovf-4O-7LZ" id="BgC-sc-6GS"/>
<outlet property="progressContainer" destination="3Jv-gr-8Hf" id="S5k-hc-NeK"/>
<outlet property="progressIndicator" destination="Ovf-4O-7LZ" id="mq3-1b-ts5"/>
<outlet property="window" destination="QvC-M9-y7g" id="bos-rN-Jgz"/>
</connections>
</customObject>
......@@ -21,13 +24,29 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="351" height="131"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1050"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="351" height="131"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView hidden="YES" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ovf-4O-7LZ" customClass="ITProgressIndicator">
<rect key="frame" x="140" y="30" width="70" height="70"/>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="3Jv-gr-8Hf">
<rect key="frame" x="15" y="15" width="321" height="106"/>
<subviews>
<customView hidden="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ovf-4O-7LZ" customClass="ITProgressIndicator">
<rect key="frame" x="125" y="18" width="70" height="70"/>
<constraints>
<constraint firstAttribute="width" secondItem="Ovf-4O-7LZ" secondAttribute="height" multiplier="1:1" id="NK5-73-b6c"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="Ovf-4O-7LZ" firstAttribute="centerX" secondItem="3Jv-gr-8Hf" secondAttribute="centerX" id="Zyc-7w-gXf"/>
<constraint firstItem="Ovf-4O-7LZ" firstAttribute="centerY" secondItem="3Jv-gr-8Hf" secondAttribute="centerY" id="dyd-7a-HdM"/>
<constraint firstItem="Ovf-4O-7LZ" firstAttribute="top" secondItem="3Jv-gr-8Hf" secondAttribute="top" constant="18" id="lKK-Xi-PVF"/>
</constraints>
</customView>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XMQ-jJ-yqG">
<rect key="frame" x="15" y="12" width="321" height="106"/>
</customView>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xUT-yB-g8Q">
<rect key="frame" x="1" y="0.0" width="350" height="131"/>
......@@ -134,9 +153,16 @@ DQ
</subviews>
</customView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="3Jv-gr-8Hf" secondAttribute="trailing" constant="15" id="JJw-qT-SLD"/>
<constraint firstItem="3Jv-gr-8Hf" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" constant="15" id="LCu-zR-e4t"/>
<constraint firstItem="3Jv-gr-8Hf" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" constant="10" id="UYR-BR-G4e"/>
<constraint firstAttribute="bottom" secondItem="3Jv-gr-8Hf" secondAttribute="bottom" constant="15" id="jr4-Qd-mQ6"/>
</constraints>
</view>
<connections>
<outlet property="delegate" destination="-2" id="3wn-SC-48D"/>
<outlet property="initialFirstResponder" destination="xUT-yB-g8Q" id="WGS-1O-JBF"/>
</connections>
<point key="canvasLocation" x="-363.5" y="-97.5"/>
</window>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment