VMConfigDriveCreateViewController.m 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. //
  2. // Copyright © 2019 osy. All rights reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #import "VMConfigDriveCreateViewController.h"
  17. #import "UTMQcow2.h"
  18. extern NSString *const kUTMErrorDomain;
  19. @interface VMConfigDriveCreateViewController ()
  20. @end
  21. @implementation VMConfigDriveCreateViewController
  22. - (void)viewDidLoad {
  23. [super viewDidLoad];
  24. _imageExpanding = self.imageExpandingSwitch.on;
  25. }
  26. - (void)viewWillAppear:(BOOL)animated {
  27. [super viewWillAppear:animated];
  28. [self refreshViewFromConfiguration];
  29. }
  30. - (void)refreshViewFromConfiguration {
  31. self.imagePathField.text = self.changePath.lastPathComponent;
  32. // TODO: allow resizing, change format
  33. if (self.existingPath) {
  34. self.imageSizeField.enabled = NO;
  35. self.imageExpandingSwitch.enabled = NO;
  36. }
  37. }
  38. - (void)setExistingPath:(NSURL *)existingPath {
  39. _existingPath = existingPath;
  40. self.changePath = existingPath;
  41. [self refreshViewFromConfiguration];
  42. }
  43. #pragma mark - Operations
  44. - (void)showAlert:(NSString *)msg completion:(nullable void (^)(UIAlertAction *action))completion {
  45. UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:msg preferredStyle:UIAlertControllerStyleAlert];
  46. UIAlertAction *okay = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK button") style:UIAlertActionStyleDefault handler:completion];
  47. [alert addAction:okay];
  48. dispatch_async(dispatch_get_main_queue(), ^{
  49. [self presentViewController:alert animated:YES completion:nil];
  50. });
  51. }
  52. - (BOOL)createDisk:(NSError * _Nullable *)err {
  53. if (!GenerateDefaultQcow2File((__bridge CFURLRef)self.changePath, self.size)) {
  54. if (err) {
  55. NSString *msg = NSLocalizedString(@"Disk creation failed.", @"VMConfigDriveCreateViewController");
  56. *err = [NSError errorWithDomain:kUTMErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: msg}];
  57. }
  58. return NO;
  59. }
  60. return YES;
  61. }
  62. - (void)workWithIndicator:(NSString *)msg block:(void(^)(void))block completion:(void (^)(void))completion {
  63. UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:msg preferredStyle:UIAlertControllerStyleAlert];
  64. UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(10, 5, 50, 50)];
  65. spinner.hidesWhenStopped = YES;
  66. spinner.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
  67. [spinner startAnimating];
  68. [alert.view addSubview:spinner];
  69. [self presentViewController:alert animated:YES completion:nil];
  70. dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
  71. block();
  72. dispatch_async(dispatch_get_main_queue(), ^{
  73. [alert dismissViewControllerAnimated:YES completion:completion];
  74. });
  75. });
  76. }
  77. #pragma mark - Event handlers
  78. - (IBAction)imageExpandingSwitchChanged:(UISwitch *)sender {
  79. _imageExpanding = sender.on;
  80. }
  81. - (IBAction)imagePathFieldChanged:(UITextField *)sender {
  82. // TODO: validate input
  83. // check if existing file
  84. self.changePath = [self.imagesPath URLByAppendingPathComponent:sender.text];
  85. if (!self.shownExistingWarning && ![self.changePath isEqual:self.existingPath] && [[NSFileManager defaultManager] fileExistsAtPath:self.changePath.path]) {
  86. [self showAlert:NSLocalizedString(@"A file already exists for this name, if you proceed, it will be replaced.", @"VMConfigDriveCreateViewController") completion:^(UIAlertAction *action){
  87. self.shownExistingWarning = YES;
  88. }];
  89. }
  90. }
  91. - (IBAction)imageSizeFieldChanged:(UITextField *)sender {
  92. // TODO: validate input
  93. _size = [self.imageSizeField.text intValue];
  94. if (self.size == 0) {
  95. [self showAlert:NSLocalizedString(@"Invalid size", @"VMConfigDriveCreateViewController") completion:nil];
  96. }
  97. }
  98. - (IBAction)saveButtonPressed:(UIBarButtonItem *)sender {
  99. [self.view endEditing:YES];
  100. if (!self.existingPath) {
  101. if (!self.changePath) {
  102. [self showAlert:NSLocalizedString(@"Invalid name", @"VMConfigDriveCreateViewController") completion:nil];
  103. } else if (self.size == 0) {
  104. [self showAlert:NSLocalizedString(@"Invalid size", @"VMConfigDriveCreateViewController") completion:nil];
  105. } else {
  106. __block NSError *err;
  107. [self workWithIndicator:NSLocalizedString(@"Creating disk...", @"VMConfigDriveCreateViewController") block:^{
  108. BOOL isdir;
  109. BOOL direxists = NO;
  110. // create images directory
  111. if (![[NSFileManager defaultManager] fileExistsAtPath:self.imagesPath.path isDirectory:&isdir]) {
  112. if ([[NSFileManager defaultManager] createDirectoryAtURL:self.imagesPath withIntermediateDirectories:NO attributes:nil error:&err]) {
  113. direxists = YES;
  114. }
  115. } else if (!isdir) {
  116. err = [NSError errorWithDomain:kUTMErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Cannot create directory for disk image.", @"VMConfigDriveCreateViewController")}];
  117. } else {
  118. direxists = YES;
  119. }
  120. if (direxists) {
  121. [self createDisk:&err];
  122. }
  123. } completion:^{
  124. dispatch_async(dispatch_get_main_queue(), ^{
  125. if (err) {
  126. [self showAlert:err.localizedDescription completion:^(UIAlertAction *action){
  127. [self.navigationController popViewControllerAnimated:YES];
  128. }];
  129. } else {
  130. [self.navigationController popViewControllerAnimated:YES];
  131. }
  132. });
  133. }];
  134. }
  135. } else if (![self.changePath isEqual:self.existingPath]) {
  136. if (![[NSFileManager defaultManager] moveItemAtURL:self.existingPath toURL:self.changePath error:nil]) {
  137. [self showAlert:NSLocalizedString(@"Error renaming file", @"VMConfigDriveCreateViewController") completion:nil];
  138. }
  139. [self.navigationController popViewControllerAnimated:YES];
  140. } else {
  141. [self.navigationController popViewControllerAnimated:YES];
  142. }
  143. }
  144. @end