blob: 44c56ff772a9ffd280799006a384f35357acc0b9 [file] [log] [blame]
Alexandre Lision8521baa2015-03-13 11:08:00 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision8521baa2015-03-13 11:08:00 -04003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lision8521baa2015-03-13 11:08:00 -040018 */
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050019#import "AudioPrefsVC.h"
20
Alexandre Lision611b8c12015-03-20 18:07:17 -040021#import <audio/settings.h>
Alexandre Lision66643432015-06-04 11:59:36 -040022#import <media/recordingmodel.h>
Alexandre Lision611b8c12015-03-20 18:07:17 -040023#import <QUrl>
24#import <audio/inputdevicemodel.h>
25#import <audio/outputdevicemodel.h>
26#import <qitemselectionmodel.h>
Kateryna Kostiuk4138db12018-06-08 15:52:18 -040027#import "utils.h"
Alexandre Lision611b8c12015-03-20 18:07:17 -040028
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050029@interface AudioPrefsVC ()
30
Alexandre Lision611b8c12015-03-20 18:07:17 -040031@property (assign) IBOutlet NSPathControl *recordingsPathControl;
32@property (assign) IBOutlet NSPopUpButton *outputDeviceList;
33@property (assign) IBOutlet NSPopUpButton *inputDeviceList;
34@property (assign) IBOutlet NSButton *alwaysRecordingButton;
35@property (assign) IBOutlet NSButton *muteDTMFButton;
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040036@property (assign) IBOutlet NSTextField *recordingHeaderTitle;
37@property (assign) IBOutlet NSTextField *recordingpathLabel;
38@property (assign) IBOutlet NSLayoutConstraint* audioMarginTopConstraint;
39@property (assign) IBOutlet NSLayoutConstraint* audioMarginBottomConstraint;
40
41
42
Alexandre Lision611b8c12015-03-20 18:07:17 -040043
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050044@end
45
46@implementation AudioPrefsVC
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040047@synthesize recordingsPathControl, recordingHeaderTitle, recordingpathLabel;
Alexandre Lision611b8c12015-03-20 18:07:17 -040048@synthesize outputDeviceList;
49@synthesize inputDeviceList;
50@synthesize alwaysRecordingButton;
51@synthesize muteDTMFButton;
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040052@synthesize audioMarginTopConstraint, audioMarginBottomConstraint;
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050053
Alexandre Lision611b8c12015-03-20 18:07:17 -040054- (void)loadView
55{
56 [super loadView];
57
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040058 QModelIndex qInputIdx = Audio::Settings::instance().inputDeviceModel()->selectionModel()->currentIndex();
59 QModelIndex qOutputIdx = Audio::Settings::instance().outputDeviceModel()->selectionModel()->currentIndex();
Alexandre Lision611b8c12015-03-20 18:07:17 -040060
61 [self.outputDeviceList addItemWithTitle:
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040062 Audio::Settings::instance().outputDeviceModel()->data(qOutputIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lision611b8c12015-03-20 18:07:17 -040063
64 [self.inputDeviceList addItemWithTitle:
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040065 Audio::Settings::instance().inputDeviceModel()->data(qInputIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lision611b8c12015-03-20 18:07:17 -040066 [self.alwaysRecordingButton setState:
Kateryna Kostiukf9a72c02018-08-01 14:28:49 -040067 media::RecordingModel::instance().isAlwaysRecording() ? NSOnState:NSOffState];
Alexandre Lision611b8c12015-03-20 18:07:17 -040068
69 [self.muteDTMFButton setState:
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040070 Audio::Settings::instance().areDTMFMuted()?NSOnState:NSOffState];
Kateryna Kostiukf9a72c02018-08-01 14:28:49 -040071 NSArray* pathComponentArray = [self pathComponentArrayWithCurrentUrl:media::RecordingModel::instance().recordPath().toNSString()];
Kateryna Kostiuk4138db12018-06-08 15:52:18 -040072 [recordingsPathControl setPathComponentCells:pathComponentArray];
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -040073
74 if (appSandboxed()) {
75 [alwaysRecordingButton setHidden:YES];
76 [recordingsPathControl setEnabled:NO];
77 [recordingsPathControl setHidden: YES];
78 [recordingHeaderTitle setHidden: YES];
79 [recordingpathLabel setHidden: YES];
80 audioMarginTopConstraint.constant = 10.0f;
81 audioMarginBottomConstraint.constant = 67.0f;
82 }
Alexandre Lision611b8c12015-03-20 18:07:17 -040083}
84
85- (IBAction)toggleMuteDTMF:(NSButton *)sender
86{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040087 Audio::Settings::instance().setDTMFMuted([sender state] == NSOnState);
Alexandre Lision611b8c12015-03-20 18:07:17 -040088}
89
90- (IBAction)toggleAlwaysRecording:(NSButton *)sender
91{
Kateryna Kostiukf9a72c02018-08-01 14:28:49 -040092 media::RecordingModel::instance().setAlwaysRecording([sender state] == NSOnState);
Alexandre Lision611b8c12015-03-20 18:07:17 -040093}
94
95- (IBAction)pathControlSingleClick:(id)sender {
96 // Select that chosen component of the path.
Kateryna Kostiuk4138db12018-06-08 15:52:18 -040097 NSArray* pathComponentArray = [self pathComponentArrayWithCurrentUrl:[[self.recordingsPathControl clickedPathComponentCell] URL].path];
98 [recordingsPathControl setPathComponentCells:pathComponentArray];
Kateryna Kostiukf9a72c02018-08-01 14:28:49 -040099 media::RecordingModel::instance().setRecordPath(QString::fromNSString([self.recordingsPathControl.URL path]));
Alexandre Lision611b8c12015-03-20 18:07:17 -0400100}
101
102- (IBAction)chooseOutput:(id)sender {
103 int index = [sender indexOfSelectedItem];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400104 QModelIndex qIdx = Audio::Settings::instance().outputDeviceModel()->index(index, 0);
105 Audio::Settings::instance().outputDeviceModel()->selectionModel()->setCurrentIndex(
Alexandre Lision611b8c12015-03-20 18:07:17 -0400106 qIdx, QItemSelectionModel::ClearAndSelect);
107}
108
109- (IBAction)chooseInput:(id)sender {
110 int index = [sender indexOfSelectedItem];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400111 QModelIndex qIdx = Audio::Settings::instance().inputDeviceModel()->index(index, 0);
112 Audio::Settings::instance().inputDeviceModel()->selectionModel()->setCurrentIndex(
Alexandre Lision611b8c12015-03-20 18:07:17 -0400113 qIdx, QItemSelectionModel::ClearAndSelect);
114}
115
116#pragma mark - NSPathControl delegate methods
117
118/*
119 Assemble a set of custom cells to display into an array to pass to the path control.
120 */
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400121- (NSArray *)pathComponentArrayWithCurrentUrl:(NSString *) url
Alexandre Lision611b8c12015-03-20 18:07:17 -0400122{
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400123
Alexandre Lision611b8c12015-03-20 18:07:17 -0400124 NSMutableArray *pathComponentArray = [[NSMutableArray alloc] init];
125
126 NSFileManager *fileManager = [[NSFileManager alloc] init];
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400127 NSURL* downloadURL = [fileManager URLForDirectory:NSDownloadsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
Alexandre Lision611b8c12015-03-20 18:07:17 -0400128
129 NSPathComponentCell *componentCell;
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400130 componentCell = [self componentCellForType:kGenericFolderIcon withTitle:@"Downloads" URL:downloadURL];
Alexandre Lision611b8c12015-03-20 18:07:17 -0400131 [pathComponentArray addObject:componentCell];
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400132 NSString * downloads = [downloadURL path];
133 if([url isEqualToString:downloads]) {
134 return pathComponentArray;
135 }
136 if(![url isEqualToString:@""]) {
137 NSString * name = [url componentsSeparatedByString:@"/"].lastObject;
138 if(!name) {
139 return pathComponentArray;
140 }
141 componentCell = [self componentCellForType:kGenericFolderIcon withTitle:name URL:[NSURL URLWithString: url]];
142 [pathComponentArray addObject:componentCell];
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400143 }
Kateryna Kostiuke184f2e2018-06-11 15:31:31 -0400144 return pathComponentArray;
Alexandre Lision611b8c12015-03-20 18:07:17 -0400145}
146
147/*
Kateryna Kostiuke184f2e2018-06-11 15:31:31 -0400148 This method is used by pathComponentArray to create a NSPathComponent cell based on icon, title and URL information.
Alexandre Lision611b8c12015-03-20 18:07:17 -0400149 Each path component needs an icon, URL and title.
150 */
151- (NSPathComponentCell *)componentCellForType:(OSType)withIconType withTitle:(NSString *)title URL:(NSURL *)url
152{
153 NSPathComponentCell *componentCell = [[NSPathComponentCell alloc] init];
154
155 NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(withIconType)];
156 [componentCell setImage:iconImage];
157 [componentCell setURL:url];
158 [componentCell setTitle:title];
159
160 return componentCell;
161}
162
163/*
164 Delegate method of NSPathControl to determine how the NSOpenPanel will look/behave.
165 */
166- (void)pathControl:(NSPathControl *)pathControl willDisplayOpenPanel:(NSOpenPanel *)openPanel
167{
168 NSLog(@"willDisplayOpenPanel");
169 [openPanel setAllowsMultipleSelection:NO];
170 [openPanel setCanChooseDirectories:YES];
171 [openPanel setCanChooseFiles:NO];
172 [openPanel setResolvesAliases:YES];
Alexandre Lisionc8180112016-01-27 11:27:50 -0500173 [openPanel setTitle:NSLocalizedString(@"Choose a directory", @"Open panel title")];
174 [openPanel setPrompt:NSLocalizedString(@"Choose directory", @"Open panel prompt for 'Choose a directory'")];
Alexandre Lision611b8c12015-03-20 18:07:17 -0400175 [openPanel setDelegate:self];
176}
177
178- (void)pathControl:(NSPathControl *)pathControl willPopUpMenu:(NSMenu *)menu
179{
180
181}
182
183#pragma mark - NSOpenSavePanelDelegate delegate methods
184
185- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError
186{
187 [recordingsPathControl setURL:url];
188 return YES;
189}
190
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400191- (BOOL) panel:(id)sender shouldEnableURL:(NSURL*)url {
Kateryna Kostiuk74fe20c2018-06-14 12:05:53 -0400192 return YES;
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400193}
194
Alexandre Lision611b8c12015-03-20 18:07:17 -0400195#pragma mark - NSMenuDelegate methods
196
197- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
198{
199 QModelIndex qIdx;
200
Alexandre Lision51ff1492016-04-15 11:38:37 -0400201 if (inputDeviceList.menu == menu) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400202 qIdx = Audio::Settings::instance().inputDeviceModel()->index(index);
203 [item setTitle:Audio::Settings::instance().inputDeviceModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lision51ff1492016-04-15 11:38:37 -0400204 } else {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400205 qIdx = Audio::Settings::instance().outputDeviceModel()->index(index);
206 [item setTitle:Audio::Settings::instance().outputDeviceModel()->data(qIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lision611b8c12015-03-20 18:07:17 -0400207 }
208
209 return YES;
210}
211
212- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
213{
Alexandre Lision51ff1492016-04-15 11:38:37 -0400214 if (inputDeviceList.menu == menu)
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400215 return Audio::Settings::instance().inputDeviceModel()->rowCount();
Alexandre Lision611b8c12015-03-20 18:07:17 -0400216 else
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400217 return Audio::Settings::instance().outputDeviceModel()->rowCount();
Alexandre Lision611b8c12015-03-20 18:07:17 -0400218}
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500219
220@end