2018-12-04 14:01:45 -06:00
|
|
|
// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
2019-03-28 10:04:58 -05:00
|
|
|
#import <LibreOfficeKit/LibreOfficeKitInit.h>
|
|
|
|
|
2019-10-11 04:18:27 -05:00
|
|
|
#import "ios.h"
|
2018-12-10 11:48:15 -06:00
|
|
|
#import "AppDelegate.h"
|
2018-12-13 08:02:04 -06:00
|
|
|
#import "L10n.h"
|
2018-12-04 14:01:45 -06:00
|
|
|
#import "TemplateCollectionViewController.h"
|
|
|
|
#import "TemplateSectionHeaderView.h"
|
|
|
|
|
2022-04-14 05:53:32 -05:00
|
|
|
#import "svtools/strings.hrc"
|
|
|
|
|
2018-12-06 09:14:47 -06:00
|
|
|
static NSString *mapTemplateExtensionToActual(NSString *templateName) {
|
2018-12-05 12:12:34 -06:00
|
|
|
NSString *baseName = [templateName stringByDeletingPathExtension];
|
|
|
|
NSString *extension = [templateName substringFromIndex:baseName.length];
|
|
|
|
|
|
|
|
if ([extension isEqualToString:@".ott"])
|
|
|
|
return [baseName stringByAppendingString:@".odt"];
|
|
|
|
else if ([extension isEqualToString:@".ots"])
|
|
|
|
return [baseName stringByAppendingString:@".ods"];
|
|
|
|
else if ([extension isEqualToString:@".otp"])
|
|
|
|
return [baseName stringByAppendingString:@".odp"];
|
|
|
|
else
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
2018-12-04 14:01:45 -06:00
|
|
|
@implementation TemplateCollectionViewController
|
|
|
|
|
2018-12-06 09:14:47 -06:00
|
|
|
- (void)viewDidLoad {
|
2018-12-04 14:01:45 -06:00
|
|
|
|
2023-03-17 14:46:37 -05:00
|
|
|
// Partial fix for issue #1962 Dismiss view by tapping outside of the view
|
|
|
|
// Setting modalInPresentation to YES will ignore all events outside of
|
|
|
|
// the view so set self.modalInPresentation to NO.
|
|
|
|
self.modalInPresentation = NO;
|
2021-03-19 04:06:08 -05:00
|
|
|
|
Add a way to have templates specific to a customer deployment
Add two settings: One setting "Template list URL" is a string that
should either be empty (the typical case for a random user of the
app), or contain a https: URL. If this setting is empty, only the
templates bundled in the app are provided.
If the "Template list URL" is non-empty, it should be a https: URL
pointing to a text file (or dynamically generated text resource). That
file is downloaded and read when the app starts. Each line in the file
should either be a comment (starting with a hash '#'), or a https: URL
pointing to a template document, that is of type .ott, .ots, or .otp.
That document is downloaded if it hasn't been downloaded already, or
if its time stamp is newer than that of the already downloaded copy.
Also a thumbnail image for the template, formed by appending ".png" to
its URL, is downloaded, if available.
Any previously downloaded templates that aren't mentioned in the list
file are removed.
The intent is that in some managed mass deployment environment, the
mobile device management software would set up this setting, so that
the end-user devices would see the same templates.
Obviously, this URL does not have to point to a static file on a web
server, but could point to some dynamically generated resource on a
web server, that enumerates the templates available on the server and
returns their URLs as a text document.
Another setting is "Empty tile cache next time". This is a toggle. If
toggled on, the next time a document is opened in the app, the tile
cache is emptied (and the toggle is reset off). This is mostly for
potential problem solving, and might be removd later.
Various refactoring to support the new functionality.
Change-Id: Ie2ebf032acb9e43bb1c6f7ae4d0c449ae66eaa05
2018-12-17 14:18:49 -06:00
|
|
|
static NSString *downloadedTemplates = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingString:@"/downloadedTemplates/"];
|
|
|
|
|
|
|
|
// Scan for available templates. First downloaded ones.
|
|
|
|
NSDirectoryEnumerator<NSString *> *e = [[NSFileManager defaultManager] enumeratorAtPath:downloadedTemplates];
|
|
|
|
|
|
|
|
templates[0] = [@[] mutableCopy];
|
|
|
|
templates[1] = [@[] mutableCopy];
|
|
|
|
templates[2] = [@[] mutableCopy];
|
|
|
|
|
|
|
|
NSString *subPath;
|
|
|
|
while ((subPath = [e nextObject]) != nil) {
|
|
|
|
NSString *path = [downloadedTemplates stringByAppendingString:subPath];
|
|
|
|
if ([[path pathExtension] isEqualToString:@"ott"]) {
|
|
|
|
[templates[0] addObject:[NSURL fileURLWithPath:path]];
|
|
|
|
} else if ([[path pathExtension] isEqualToString:@"ots"]) {
|
|
|
|
[templates[1] addObject:[NSURL fileURLWithPath:path]];
|
|
|
|
} else if ([[path pathExtension] isEqualToString:@"otp"]) {
|
|
|
|
[templates[2] addObject:[NSURL fileURLWithPath:path]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([templates[0] count] == 0)
|
|
|
|
templates[0] = [[[NSBundle mainBundle] URLsForResourcesWithExtension:@".ott" subdirectory:@"Templates"] mutableCopy];
|
|
|
|
if ([templates[1] count] == 0)
|
|
|
|
templates[1] = [[[NSBundle mainBundle] URLsForResourcesWithExtension:@".ots" subdirectory:@"Templates"] mutableCopy];
|
|
|
|
if ([templates[2] count] == 0)
|
|
|
|
templates[2] = [[[NSBundle mainBundle] URLsForResourcesWithExtension:@".otp" subdirectory:@"Templates"] mutableCopy];
|
2018-12-04 14:01:45 -06:00
|
|
|
}
|
|
|
|
|
2023-03-17 14:46:37 -05:00
|
|
|
- (void)viewDidDisappear:(BOOL)animated {
|
|
|
|
// Partial fix for issue #1962 Invoke import handler when view is dismissed
|
|
|
|
// If the import handler has not already been invoked, invoke it or else
|
|
|
|
// -[DocumentBrowserViewController
|
|
|
|
// documentBrowser:didRequestDocumentCreationWithHandler:] will never be
|
|
|
|
// hcalled again.
|
|
|
|
if (self.importHandler) {
|
|
|
|
self.importHandler(nil, UIDocumentBrowserImportModeNone);
|
|
|
|
self.importHandler = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-04 14:01:45 -06:00
|
|
|
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
|
|
|
// Three sections: Document, Spreadsheet, and Presentation
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
|
|
|
assert(section >= 0 && section <= 2);
|
|
|
|
return templates[section].count;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
assert(indexPath.length == 2);
|
|
|
|
assert([indexPath indexAtPosition:0] <= 2);
|
|
|
|
assert([indexPath indexAtPosition:1] < templates[[indexPath indexAtPosition:0]].count);
|
|
|
|
|
|
|
|
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
|
|
|
|
|
|
|
|
UIImageView *image = (UIImageView *)[cell viewWithTag:1];
|
|
|
|
UILabel *title = (UILabel *)[cell viewWithTag:2];
|
|
|
|
|
2018-12-06 08:33:39 -06:00
|
|
|
NSString *templateThumbnail = [[templates[[indexPath indexAtPosition:0]][[indexPath indexAtPosition:1]] path] stringByAppendingString:@".png"];
|
2018-12-06 09:14:47 -06:00
|
|
|
UIImage *thumbnail;
|
2018-12-06 08:33:39 -06:00
|
|
|
if ([NSFileManager.defaultManager fileExistsAtPath:templateThumbnail])
|
2018-12-06 09:14:47 -06:00
|
|
|
thumbnail = [UIImage imageWithContentsOfFile:templateThumbnail];
|
2018-12-06 08:33:39 -06:00
|
|
|
else
|
2018-12-06 09:14:47 -06:00
|
|
|
thumbnail = [UIImage imageNamed:@"AppIcon"];
|
|
|
|
|
|
|
|
image.image = thumbnail;
|
2018-12-04 14:01:45 -06:00
|
|
|
|
|
|
|
NSString *fileName = [templates[[indexPath indexAtPosition:0]][[indexPath indexAtPosition:1]] lastPathComponent];
|
|
|
|
|
|
|
|
title.text = [fileName stringByDeletingPathExtension];
|
|
|
|
|
|
|
|
return cell;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
return CGSizeMake(150, 150);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
assert(kind == UICollectionElementKindSectionHeader);
|
|
|
|
|
|
|
|
assert(indexPath.length == 2);
|
|
|
|
assert([indexPath indexAtPosition:1] == 0);
|
|
|
|
|
|
|
|
NSUInteger index = [indexPath indexAtPosition:0];
|
|
|
|
assert(index <= 2);
|
|
|
|
|
|
|
|
TemplateSectionHeaderView *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"SectionHeaderView" forIndexPath:indexPath];
|
|
|
|
|
2018-12-10 11:48:15 -06:00
|
|
|
char *translatedHeader;
|
|
|
|
|
2018-12-04 14:01:45 -06:00
|
|
|
if (index == 0)
|
2018-12-13 08:02:04 -06:00
|
|
|
translatedHeader = _(STR_DESCRIPTION_FACTORY_WRITER, "svt");
|
2018-12-04 14:01:45 -06:00
|
|
|
else if (index == 1)
|
2018-12-13 08:02:04 -06:00
|
|
|
translatedHeader = _(STR_DESCRIPTION_FACTORY_CALC, "svt");
|
2018-12-04 14:01:45 -06:00
|
|
|
else if (index == 2)
|
2018-12-13 08:02:04 -06:00
|
|
|
translatedHeader = _(STR_DESCRIPTION_FACTORY_IMPRESS, "svt");
|
2018-12-10 11:48:15 -06:00
|
|
|
else
|
|
|
|
abort();
|
|
|
|
|
|
|
|
header.title.text = [NSString stringWithUTF8String:translatedHeader];
|
|
|
|
|
|
|
|
free(translatedHeader);
|
2018-12-04 14:01:45 -06:00
|
|
|
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
2018-12-05 12:12:34 -06:00
|
|
|
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
NSURL *selectedTemplate = templates[[indexPath indexAtPosition:0]][[indexPath indexAtPosition:1]];
|
|
|
|
|
|
|
|
NSURL *cacheDirectory = [NSFileManager.defaultManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask][0];
|
|
|
|
NSURL *newURL = [cacheDirectory URLByAppendingPathComponent:mapTemplateExtensionToActual(selectedTemplate.lastPathComponent)
|
|
|
|
isDirectory:NO];
|
|
|
|
// Load the template into LibreOffice core, save as the corresponding document type (with the
|
|
|
|
// same basename), and then proceed to edit that.
|
2019-03-28 10:04:58 -05:00
|
|
|
|
Add a way to have templates specific to a customer deployment
Add two settings: One setting "Template list URL" is a string that
should either be empty (the typical case for a random user of the
app), or contain a https: URL. If this setting is empty, only the
templates bundled in the app are provided.
If the "Template list URL" is non-empty, it should be a https: URL
pointing to a text file (or dynamically generated text resource). That
file is downloaded and read when the app starts. Each line in the file
should either be a comment (starting with a hash '#'), or a https: URL
pointing to a template document, that is of type .ott, .ots, or .otp.
That document is downloaded if it hasn't been downloaded already, or
if its time stamp is newer than that of the already downloaded copy.
Also a thumbnail image for the template, formed by appending ".png" to
its URL, is downloaded, if available.
Any previously downloaded templates that aren't mentioned in the list
file are removed.
The intent is that in some managed mass deployment environment, the
mobile device management software would set up this setting, so that
the end-user devices would see the same templates.
Obviously, this URL does not have to point to a static file on a web
server, but could point to some dynamically generated resource on a
web server, that enumerates the templates available on the server and
returns their URLs as a text document.
Another setting is "Empty tile cache next time". This is a toggle. If
toggled on, the next time a document is opened in the app, the tile
cache is emptied (and the toggle is reset off). This is mostly for
potential problem solving, and might be removd later.
Various refactoring to support the new functionality.
Change-Id: Ie2ebf032acb9e43bb1c6f7ae4d0c449ae66eaa05
2018-12-17 14:18:49 -06:00
|
|
|
LibreOfficeKitDocument *doc = lo_kit->pClass->documentLoad(lo_kit, [[selectedTemplate absoluteString] UTF8String]);
|
2018-12-05 12:12:34 -06:00
|
|
|
doc->pClass->saveAs(doc, [[newURL absoluteString] UTF8String], nullptr, nullptr);
|
|
|
|
doc->pClass->destroy(doc);
|
|
|
|
|
2023-03-17 14:46:37 -05:00
|
|
|
// Partial fix for issue #1962 Set import handler to nil after use
|
2023-03-17 19:18:44 -05:00
|
|
|
if (self.importHandler) {
|
|
|
|
self.importHandler(newURL, UIDocumentBrowserImportModeMove);
|
|
|
|
self.importHandler = nil;
|
|
|
|
}
|
2023-03-17 14:46:37 -05:00
|
|
|
|
2018-12-05 14:13:26 -06:00
|
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
2018-12-05 12:12:34 -06:00
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2023-03-17 19:18:44 -05:00
|
|
|
- (void)cancel {
|
|
|
|
// Partial fix for issue #1962 Set import handler to nil after use
|
|
|
|
if (self.importHandler) {
|
|
|
|
self.importHandler(nil, UIDocumentBrowserImportModeNone);
|
|
|
|
self.importHandler = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
|
|
}
|
|
|
|
|
2018-12-04 14:01:45 -06:00
|
|
|
@end
|
|
|
|
|
|
|
|
// vim:set shiftwidth=4 softtabstop=4 expandtab:
|