CSearchToolbar.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. //
  2. // CSearchToolbar.m
  3. // ComPDFKit_Tools
  4. //
  5. // Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
  6. //
  7. // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  8. // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  9. // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  10. // This notice may not be removed from this file.
  11. //
  12. #import "CSearchToolbar.h"
  13. #import <ComPDFKit/ComPDFKit.h>
  14. #import "CPDFColorUtils.h"
  15. #import "CPDFListView.h"
  16. #import "CPDFSearchResultsViewController.h"
  17. #import "CNavigationController.h"
  18. #import "CActivityIndicatorView.h"
  19. #define offset 10
  20. @interface CSearchToolbar()<UISearchBarDelegate>
  21. @property (nonatomic, strong) UIButton *searchListItem;
  22. @property (nonatomic, strong) UIButton *nextListItem;
  23. @property (nonatomic, strong) UIButton *previousItem;
  24. @property (nonatomic, strong) UISearchBar *searchBar;
  25. @property (nonatomic, strong) UIButton *doneItem;
  26. @property (nonatomic, assign) NSInteger nowPageIndex;
  27. @property (nonatomic, assign) NSInteger nowNumber;
  28. @property (nonatomic, strong) NSArray *resultArray;
  29. @property(nonatomic, strong) CPDFListView *pdfView;
  30. @property (nonatomic, strong) CActivityIndicatorView *loadingView;
  31. @property (nonatomic, assign) BOOL isSearched;
  32. @end
  33. @implementation CSearchToolbar
  34. #pragma mark - Initializers
  35. - (instancetype)initWithPDFView:(CPDFListView *)pdfview {
  36. if (self = [super init]) {
  37. self.pdfView = pdfview;
  38. [self commonInit];
  39. }
  40. return self;
  41. }
  42. - (void)layoutSubviews {
  43. [super layoutSubviews];
  44. _doneItem.frame = CGRectMake(offset, 5, ((self.bounds.size.width - (6*offset)) / 9), 30);
  45. if(!self.isSearched) {
  46. _searchBar.frame = CGRectMake(((self.bounds.size.width - (6*offset)) / 9) + offset*2, 5, ((self.bounds.size.width - (6*offset)) / 9)*8, 30);
  47. }else{
  48. _searchBar.frame = CGRectMake(((self.bounds.size.width - (6*offset)) / 9) + offset*2, 5, ((self.bounds.size.width - (6*offset)) / 9)*5, 30);
  49. }
  50. _previousItem.frame = CGRectMake(6*((self.bounds.size.width - (6*offset)) / 9) + offset*3, 5, ((self.bounds.size.width - (6*offset)) / 9), 30);
  51. _nextListItem.frame = CGRectMake(self.bounds.size.width - (2*((self.bounds.size.width - (6*offset)) / 9) + 2*offset), 5, ((self.bounds.size.width - (6*offset)) / 9), 30);
  52. _searchListItem.frame = CGRectMake(self.bounds.size.width - (((self.bounds.size.width - (6*offset)) / 9) + offset), 5, ((self.bounds.size.width - (6*offset)) / 9), 30);
  53. }
  54. #pragma mark - Public method
  55. - (void)showInView:(UIView *)subView {
  56. [subView addSubview:self];
  57. self.frame = CGRectMake(0, 0, subView.bounds.size.width, 35);
  58. self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  59. [self.searchBar becomeFirstResponder];
  60. }
  61. - (void)beganSearchText:(NSString *)searchText {
  62. if ([searchText length] < 1){
  63. return;
  64. }
  65. if (self.pdfView.toolModel == CToolModelEdit) {
  66. [self conentEditSearch:searchText];
  67. } else {
  68. [self preViewSearch:searchText];
  69. }
  70. }
  71. - (void)preViewSearch:(NSString *)searchText {
  72. // The search for document characters cannot be repeated
  73. self.window.userInteractionEnabled = NO;
  74. if (![self.loadingView superview]) {
  75. [self.window addSubview:self.loadingView];
  76. }
  77. [self.loadingView startAnimating];
  78. __block __typeof(self) block_self = self;
  79. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  80. NSArray *results = [block_self.pdfView.document findString:searchText withOptions:CPDFSearchCaseInsensitive];
  81. dispatch_async(dispatch_get_main_queue(), ^{
  82. self.window.userInteractionEnabled = YES;
  83. [self.loadingView stopAnimating];
  84. [self.loadingView removeFromSuperview];
  85. block_self.resultArray = results;
  86. if(results.count > 0){
  87. self.isSearched = YES;
  88. self.previousItem.hidden = self.nextListItem.hidden = self.searchListItem.hidden = NO;
  89. [self layoutSubviews];
  90. }
  91. dispatch_async(dispatch_get_main_queue(), ^{
  92. if ([block_self.resultArray count] < 1) {
  93. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
  94. style:UIAlertActionStyleCancel
  95. handler:nil];
  96. UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
  97. message:NSLocalizedString(@"Text not found!", nil)
  98. preferredStyle:UIAlertControllerStyleAlert];
  99. UIViewController *tRootViewControl = [UIApplication sharedApplication].keyWindow.rootViewController;
  100. if ([tRootViewControl presentedViewController])
  101. tRootViewControl = [tRootViewControl presentedViewController];
  102. [alert addAction:cancelAction];
  103. [tRootViewControl presentViewController:alert animated:YES completion:nil];
  104. } else {
  105. block_self.nowNumber = 0;
  106. block_self.nowPageIndex = 0;
  107. if(block_self.resultArray.count > block_self.nowPageIndex) {
  108. NSArray *selections = [block_self.resultArray objectAtIndex:block_self.nowPageIndex];
  109. if(selections.count > block_self.nowNumber) {
  110. CPDFSelection *selection = [selections objectAtIndex:block_self.nowNumber];
  111. CGFloat offsetY = CGRectGetMaxY(block_self.superview.frame);
  112. NSInteger pageIndex = [block_self.pdfView.document indexForPage:selection.page];
  113. [block_self.pdfView goToRect:selection.bounds onPage:selection.page offsetY:offsetY animated:NO];
  114. [block_self.pdfView goToPageIndex:pageIndex animated:NO];
  115. [block_self.pdfView setHighlightedSelection:selection animated:YES];
  116. }
  117. }
  118. }
  119. });
  120. });
  121. });
  122. }
  123. - (void)conentEditSearch:(NSString *)searchText {
  124. // The search for document characters cannot be repeated
  125. self.window.userInteractionEnabled = NO;
  126. if (![self.loadingView superview]) {
  127. [self.window addSubview:self.loadingView];
  128. }
  129. [self.loadingView startAnimating];
  130. __block __typeof(self) block_self = self;
  131. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  132. [block_self.pdfView.document findEditString:searchText withOptions:CPDFSearchCaseInsensitive];
  133. NSArray *results = [block_self.pdfView.document findEditSelections];
  134. dispatch_async(dispatch_get_main_queue(), ^{
  135. self.window.userInteractionEnabled = YES;
  136. [self.loadingView stopAnimating];
  137. [self.loadingView removeFromSuperview];
  138. block_self.resultArray = results;
  139. if(results.count > 0){
  140. //To avoid modifying the text content when the text search results are available, set all operations to disable.
  141. self.pdfView.superview.userInteractionEnabled = NO;
  142. self.isSearched = YES;
  143. self.previousItem.hidden = self.nextListItem.hidden = self.searchListItem.hidden = NO;
  144. [self layoutSubviews];
  145. }
  146. dispatch_async(dispatch_get_main_queue(), ^{
  147. if ([block_self.resultArray count] < 1) {
  148. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
  149. style:UIAlertActionStyleCancel
  150. handler:nil];
  151. UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
  152. message:NSLocalizedString(@"Text not found!", nil)
  153. preferredStyle:UIAlertControllerStyleAlert];
  154. UIViewController *tRootViewControl = [UIApplication sharedApplication].keyWindow.rootViewController;
  155. if ([tRootViewControl presentedViewController])
  156. tRootViewControl = [tRootViewControl presentedViewController];
  157. [alert addAction:cancelAction];
  158. [tRootViewControl presentViewController:alert animated:YES completion:nil];
  159. } else {
  160. block_self.nowNumber = 0;
  161. block_self.nowPageIndex = 0;
  162. if(block_self.resultArray.count > block_self.nowPageIndex) {
  163. NSArray *selections = [block_self.resultArray objectAtIndex:block_self.nowPageIndex];
  164. if(selections.count > block_self.nowNumber) {
  165. CGFloat offsetY = CGRectGetMaxY(block_self.superview.frame);
  166. CPDFSelection *selection = [selections objectAtIndex:block_self.nowNumber];
  167. NSInteger pageIndex = [block_self.pdfView.document indexForPage:selection.page];
  168. [block_self.pdfView goToPageIndex:pageIndex animated:NO];
  169. [block_self.pdfView goToRect:selection.bounds onPage:selection.page offsetY:offsetY animated:NO];
  170. [block_self.pdfView setHighlightedSelection:selection animated:YES];
  171. }
  172. }
  173. }
  174. });
  175. });
  176. });
  177. }
  178. - (void)clearDatas {
  179. self.resultArray = nil;
  180. self.isSearched = NO;
  181. self.previousItem.hidden = self.nextListItem.hidden = self.searchListItem.hidden = YES;
  182. [self layoutSubviews];
  183. self.searchBar.text = @"";
  184. }
  185. #pragma mark - Accessors
  186. - (UIActivityIndicatorView *)loadingView {
  187. if (!_loadingView) {
  188. _loadingView = [[CActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
  189. _loadingView.center = self.window.center;
  190. _loadingView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
  191. }
  192. return _loadingView;
  193. }
  194. - (NSString *)searchKeyString {
  195. return self.searchBar.text;
  196. }
  197. #pragma mark - Private method
  198. - (void)commonInit{
  199. _searchListItem = [[UIButton alloc] init];
  200. _nextListItem = [[UIButton alloc] init];
  201. _previousItem = [[UIButton alloc] init];
  202. _searchBar = [[UISearchBar alloc] init];
  203. _doneItem = [[UIButton alloc] init];
  204. [self addSubview:self.searchBar];
  205. [self addSubview:self.searchListItem];
  206. [self addSubview:self.nextListItem];
  207. [self addSubview:self.previousItem];
  208. [self addSubview:self.doneItem];
  209. [_doneItem setImage:[UIImage imageNamed:@"CPDFSearchImageClose" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil] forState:UIControlStateNormal];
  210. _doneItem.titleLabel.adjustsFontSizeToFitWidth = YES;
  211. _searchBar.placeholder = NSLocalizedString(@"Search", nil);
  212. if (@available(iOS 13.0, *)) {
  213. _searchBar.searchTextField.adjustsFontSizeToFitWidth = YES;
  214. } else {
  215. UITextField *searchField = [_searchBar valueForKey:@"searchField"];
  216. searchField.adjustsFontSizeToFitWidth = YES;
  217. }
  218. [_previousItem setImage:[UIImage imageNamed:@"CPDFSearchImagePrevious" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil] forState:UIControlStateNormal];
  219. [_nextListItem setImage:[UIImage imageNamed:@"CPDFSearchImageNext" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil] forState:UIControlStateNormal];
  220. [_searchListItem setImage:[UIImage imageNamed:@"CPDFSearchImageList" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil] forState:UIControlStateNormal];
  221. [self.doneItem addTarget:self action:@selector(buttonItemClicked_Done:) forControlEvents:UIControlEventTouchUpInside];
  222. [self.previousItem addTarget:self action:@selector(buttonItemClicked_Previous:) forControlEvents:UIControlEventTouchUpInside];
  223. [self.nextListItem addTarget:self action:@selector(buttonItemClicked_Next:) forControlEvents:UIControlEventTouchUpInside];
  224. [self.searchListItem addTarget:self action:@selector(buttonItemClicked_SearchList:) forControlEvents:UIControlEventTouchUpInside];
  225. self.searchBar.delegate = self;
  226. self.previousItem.hidden = self.nextListItem.hidden = self.searchListItem.hidden = YES;
  227. }
  228. #pragma mark - Action
  229. - (void)buttonItemClicked_SearchList:(id)sender {
  230. if([self.delegate respondsToSelector:@selector(searchToolbar:onSearchQueryResults:)]) {
  231. [self.delegate searchToolbar:self onSearchQueryResults:self.resultArray];
  232. }
  233. }
  234. - (void)buttonItemClicked_Next:(id)sender {
  235. if (_nowNumber < [self.resultArray[self.nowPageIndex] count] - 1) {
  236. _nowNumber++;
  237. } else {
  238. if (self.nowPageIndex >= self.resultArray.count - 1) {
  239. self.nowNumber = 0;
  240. self.nowPageIndex = 0;
  241. } else {
  242. _nowPageIndex++;
  243. _nowNumber = 0;
  244. }
  245. }
  246. CGFloat offsetY = CGRectGetMaxY(self.superview.frame);
  247. CPDFSelection *selection = self.resultArray[self.nowPageIndex][self.nowNumber];
  248. NSInteger pageIndex = [self.pdfView.document indexForPage:selection.page];
  249. [self.pdfView goToPageIndex:pageIndex animated:NO];
  250. [self.pdfView goToRect:selection.bounds onPage:selection.page offsetY:offsetY animated:NO];
  251. [self.pdfView setHighlightedSelection:selection animated:YES];
  252. }
  253. - (void)buttonItemClicked_Previous:(id)sender {
  254. if (_nowNumber > 0) {
  255. _nowNumber--;
  256. } else {
  257. if (self.nowPageIndex == 0) {
  258. _nowPageIndex = self.resultArray.count - 1;
  259. _nowNumber = [self.resultArray[self.nowPageIndex] count] - 1;
  260. } else {
  261. _nowPageIndex--;
  262. _nowNumber = [self.resultArray[self.nowPageIndex] count] - 1;
  263. }
  264. }
  265. CGFloat offsetY = CGRectGetMaxY(self.superview.frame);
  266. CPDFSelection *selection = self.resultArray[self.nowPageIndex][self.nowNumber];
  267. NSInteger pageIndex = [self.pdfView.document indexForPage:selection.page];
  268. [self.pdfView goToPageIndex:pageIndex animated:NO];
  269. [self.pdfView goToRect:selection.bounds onPage:selection.page offsetY:offsetY animated:NO];
  270. [self.pdfView setHighlightedSelection:selection animated:YES];
  271. }
  272. - (void)buttonItemClicked_Done:(id)sender {
  273. [self clearDatas];
  274. self.pdfView.superview.userInteractionEnabled = YES;
  275. if ([self.delegate respondsToSelector:@selector(searchToolbarOnExitSearch:)])
  276. [self.delegate searchToolbarOnExitSearch:self];
  277. }
  278. #pragma mark - UISearchBarDelegate
  279. - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
  280. [searchBar resignFirstResponder];
  281. NSString *string = searchBar.text;
  282. if ([string length] < 1)
  283. return;
  284. [self beganSearchText:string];
  285. }
  286. - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
  287. if(searchText.length <1){
  288. self.isSearched = NO;
  289. self.previousItem.hidden = self.nextListItem.hidden = self.searchListItem.hidden = YES;
  290. [self layoutSubviews];
  291. }
  292. }
  293. @end