CPDFAnnotationListUI.xaml.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. using ComPDFKit.PDFAnnotation;
  2. using ComPDFKit.Tool;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Collections.ObjectModel;
  6. using System.ComponentModel;
  7. using System.Text.RegularExpressions;
  8. using System.Windows;
  9. using System.Windows.Controls;
  10. using System.Windows.Data;
  11. using System.Windows.Input;
  12. using ComPDFKit.Controls.Helper;
  13. using System.Collections.Specialized;
  14. using ComPDFKit.Controls.PDFControl;
  15. using static ComPDFKit.Controls.PDFControlUI.CPDFAnnotationListUI;
  16. using ComPDFKit.Controls.Data;
  17. namespace ComPDFKit.Controls.PDFControlUI
  18. {
  19. public class ShowReplyListCommand : ICommand
  20. {
  21. public event EventHandler CanExecuteChanged;
  22. public bool CanExecute(object parameter)
  23. {
  24. return true;
  25. }
  26. public void Execute(object parameter)
  27. {
  28. if (parameter is AnnotationBindData data)
  29. {
  30. data.IsReplyListVisible = !data.IsReplyListVisible;
  31. }
  32. }
  33. }
  34. public class ShowReplyInputCommand : ICommand
  35. {
  36. public event EventHandler CanExecuteChanged;
  37. public bool CanExecute(object parameter)
  38. {
  39. return true;
  40. }
  41. public void Execute(object parameter)
  42. {
  43. if (parameter is AnnotationBindData data)
  44. {
  45. data.IsReplyInputVisible = !data.IsReplyInputVisible;
  46. if(data.IsReplyInputVisible)
  47. {
  48. data.IsReplyListVisible = true;
  49. }
  50. }
  51. }
  52. }
  53. internal class AnnotationBindData : INotifyPropertyChanged
  54. {
  55. public PDFViewControl pdfViewer { get; set; }
  56. public AnnotParam annotationData { get; set; }
  57. public string ReplyCount
  58. {
  59. get => ReplyList.Count.ToString();
  60. }
  61. private bool _isReplyListVisible = true;
  62. public bool IsReplyListVisible
  63. {
  64. get { return _isReplyListVisible; }
  65. set
  66. {
  67. _isReplyListVisible = value;
  68. OnPropertyChanged(nameof(IsReplyListVisible));
  69. }
  70. }
  71. private bool _isReplyInputVisible;
  72. public bool IsReplyInputVisible
  73. {
  74. get { return _isReplyInputVisible; }
  75. set
  76. {
  77. _isReplyInputVisible = value;
  78. OnPropertyChanged(nameof(IsReplyInputVisible));
  79. }
  80. }
  81. public int PageIndex { get; set; }
  82. public int AnnotIndex { get => annotationData.AnnotIndex; }
  83. public string Author
  84. {
  85. get => annotationData.Author;
  86. }
  87. public string Note
  88. {
  89. get => annotationData.Content;
  90. }
  91. private CPDFAnnotation _annotation;
  92. public CPDFAnnotation Annotation
  93. {
  94. get
  95. {
  96. List<CPDFAnnotation> annotCoreList = pdfViewer?.GetCPDFViewer()?.GetDocument()?.PageAtIndex(annotationData.PageIndex, false)?.GetAnnotations();
  97. return annotCoreList[annotationData.AnnotIndex];
  98. }
  99. }
  100. private ObservableCollection<ReplyData> _replyList = new ObservableCollection<ReplyData>();
  101. public ObservableCollection<ReplyData> ReplyList
  102. {
  103. get => _replyList;
  104. set
  105. {
  106. if (_replyList != value)
  107. {
  108. if (_replyList != null)
  109. {
  110. // Unsubscribe from the previous collection
  111. _replyList.CollectionChanged -= ReplyList_CollectionChanged;
  112. }
  113. _replyList = value;
  114. if (_replyList != null)
  115. {
  116. // Subscribe to the new collection
  117. _replyList.CollectionChanged += ReplyList_CollectionChanged;
  118. }
  119. OnPropertyChanged(nameof(ReplyList));
  120. }
  121. }
  122. }
  123. private ObservableCollection<AnnotationBindData> annotationList = new ObservableCollection<AnnotationBindData>();
  124. private void ReplyList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  125. {
  126. // Notify that the ReplyCount has changed when the collection changes
  127. OnPropertyChanged(nameof(ReplyCount));
  128. }
  129. public BindAnnotationResult BindProperty { get; set; }
  130. public AnnotationBindData()
  131. {
  132. BindProperty = new BindAnnotationResult();
  133. }
  134. public int ShowPageIndex { get { return BindProperty.PageIndex + 1; } set { BindProperty.PageIndex = value; } }
  135. public event PropertyChangedEventHandler PropertyChanged;
  136. protected void OnPropertyChanged(string propertyName)
  137. {
  138. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  139. }
  140. }
  141. public partial class CPDFAnnotationListUI : UserControl
  142. {
  143. public event EventHandler<CPDFAnnotationState> ReplyStatusChanged;
  144. public class ReplyData
  145. {
  146. public CPDFAnnotation ReplyAnnotation { get; set; }
  147. public string Author
  148. {
  149. get => ReplyAnnotation.GetAuthor();
  150. set => ReplyAnnotation.SetAuthor(value);
  151. }
  152. public string Date
  153. {
  154. get
  155. {
  156. try
  157. {
  158. if (Regex.IsMatch(ReplyAnnotation.GetCreationDate(), "(?<=D\\:)[0-9]+(?=[\\+\\-])"))
  159. {
  160. string dateStr = Regex.Match(ReplyAnnotation.GetCreationDate(), "(?<=D\\:)[0-9]+(?=[\\+\\-])").Value;
  161. return (dateStr.Substring(0, 4) + "-" + dateStr.Substring(4, 2) + "-" + dateStr.Substring(6, 2) + ", " + dateStr.Substring(8, 2) + ":" +
  162. dateStr.Substring(10, 2));
  163. }
  164. else
  165. {
  166. return string.Empty;
  167. }
  168. }
  169. catch (Exception)
  170. {
  171. return string.Empty;
  172. }
  173. }
  174. set => ReplyAnnotation.SetCreationDate(value);
  175. }
  176. public string Content
  177. {
  178. get => ReplyAnnotation.GetContent();
  179. set => ReplyAnnotation.SetContent(value);
  180. }
  181. }
  182. public class BindAnnotationResult : INotifyPropertyChanged
  183. {
  184. private ObservableCollection<ReplyData> _replyList = new ObservableCollection<ReplyData>();
  185. public ObservableCollection<ReplyData> ReplyList
  186. {
  187. get => _replyList;
  188. set
  189. {
  190. if (_replyList != value)
  191. {
  192. if (_replyList != null)
  193. {
  194. // Unsubscribe from the previous collection
  195. _replyList.CollectionChanged -= ReplyList_CollectionChanged;
  196. }
  197. _replyList = value;
  198. if (_replyList != null)
  199. {
  200. // Subscribe to the new collection
  201. _replyList.CollectionChanged += ReplyList_CollectionChanged; ;
  202. }
  203. OnPropertyChanged(nameof(ReplyList));
  204. }
  205. }
  206. }
  207. private void ReplyList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  208. {
  209. OnPropertyChanged(nameof(ReplyCount));
  210. }
  211. private Visibility _isAnnotListVisible = Visibility.Visible;
  212. public Visibility IsAnnotListVisible
  213. {
  214. get { return _isAnnotListVisible; }
  215. set
  216. {
  217. _isAnnotListVisible = value;
  218. OnPropertyChanged(nameof(IsAnnotListVisible));
  219. }
  220. }
  221. public int PageIndex { get; set; }
  222. public int AnnotIndex { get => annotationData.AnnotIndex; }
  223. public string Author
  224. {
  225. get => annotationData.Author;
  226. }
  227. public string ReplyCount
  228. {
  229. get => ReplyList.Count.ToString();
  230. }
  231. public string CreateDate
  232. {
  233. get
  234. {
  235. if (Regex.IsMatch(annotationData.CreateTime, "(?<=D\\:)[0-9]+(?=[\\+\\-])"))
  236. {
  237. string dateStr = Regex.Match(annotationData.CreateTime, "(?<=D\\:)[0-9]+(?=[\\+\\-])").Value;
  238. return (dateStr.Substring(0, 4) + "-" + dateStr.Substring(4, 2) + "-" + dateStr.Substring(6, 2) + ", " + dateStr.Substring(8, 2) + ":" +
  239. dateStr.Substring(10, 2));
  240. }
  241. else
  242. {
  243. return string.Empty;
  244. }
  245. }
  246. }
  247. public string Note
  248. {
  249. get => annotationData.Content;
  250. }
  251. public CPDFAnnotationType CurrentAnnotationType
  252. {
  253. get
  254. {
  255. switch(Annotation.Type)
  256. {
  257. case C_ANNOTATION_TYPE.C_ANNOTATION_CIRCLE:
  258. return CPDFAnnotationType.Circle;
  259. case C_ANNOTATION_TYPE.C_ANNOTATION_SQUARE:
  260. return CPDFAnnotationType.Square;
  261. case C_ANNOTATION_TYPE.C_ANNOTATION_LINE:
  262. {
  263. if(Annotation.IsMeasured())
  264. return CPDFAnnotationType.LineMeasure;
  265. else
  266. return CPDFAnnotationType.Line;
  267. }
  268. case C_ANNOTATION_TYPE.C_ANNOTATION_FREETEXT:
  269. return CPDFAnnotationType.FreeText;
  270. case C_ANNOTATION_TYPE.C_ANNOTATION_HIGHLIGHT:
  271. return CPDFAnnotationType.Highlight;
  272. case C_ANNOTATION_TYPE.C_ANNOTATION_SQUIGGLY:
  273. return CPDFAnnotationType.Squiggly;
  274. case C_ANNOTATION_TYPE.C_ANNOTATION_STRIKEOUT:
  275. return CPDFAnnotationType.Strikeout;
  276. case C_ANNOTATION_TYPE.C_ANNOTATION_UNDERLINE:
  277. return CPDFAnnotationType.Underline;
  278. case C_ANNOTATION_TYPE.C_ANNOTATION_INK:
  279. return CPDFAnnotationType.Freehand;
  280. case C_ANNOTATION_TYPE.C_ANNOTATION_TEXT:
  281. return CPDFAnnotationType.Note;
  282. case C_ANNOTATION_TYPE.C_ANNOTATION_STAMP:
  283. return CPDFAnnotationType.Stamp;
  284. case C_ANNOTATION_TYPE.C_ANNOTATION_POLYLINE:
  285. {
  286. if (Annotation.IsMeasured())
  287. return CPDFAnnotationType.PolyLineMeasure;
  288. else
  289. return CPDFAnnotationType.PolyLine;
  290. }
  291. case C_ANNOTATION_TYPE.C_ANNOTATION_POLYGON:
  292. {
  293. if (Annotation.IsMeasured())
  294. return CPDFAnnotationType.PolygonMeasure;
  295. else
  296. return CPDFAnnotationType.Polygon;
  297. }
  298. default:
  299. return CPDFAnnotationType.Note;
  300. }
  301. }
  302. }
  303. public AnnotParam annotationData { get; set; }
  304. private CPDFAnnotation _annotation;
  305. public CPDFAnnotation Annotation
  306. {
  307. get
  308. {
  309. List<CPDFAnnotation> annotCoreList = pdfViewer?.GetCPDFViewer()?.GetDocument()?.PageAtIndex(annotationData.PageIndex, false)?.GetAnnotations();
  310. return annotCoreList[annotationData.AnnotIndex];
  311. }
  312. }
  313. public PDFViewControl pdfViewer { get; set; }
  314. public CPDFAnnotationState ReplyState { get; set; }
  315. public bool IsMarkState { get; set; }
  316. public BindAnnotationResult()
  317. {
  318. ReplyList.CollectionChanged += ReplyList_CollectionChanged;
  319. }
  320. public event PropertyChangedEventHandler PropertyChanged;
  321. protected void OnPropertyChanged(string propertyName)
  322. {
  323. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  324. }
  325. }
  326. private ObservableCollection<AnnotationBindData> annotationList = new ObservableCollection<AnnotationBindData>();
  327. public event EventHandler<object> AnnotationSelectionChanged;
  328. public event EventHandler<Dictionary<int, List<int>>> DeleteItemHandler;
  329. private ContextMenu popContextMenu;
  330. private bool enableSelectEvent = true;
  331. public CPDFAnnotationListUI()
  332. {
  333. InitializeComponent();
  334. ICollectionView groupView = CollectionViewSource.GetDefaultView(annotationList);
  335. groupView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(AnnotationBindData.ShowPageIndex)));
  336. AnnotationList.PreviewMouseRightButtonUp += ((sender, args) => { SetContextMenu(); });
  337. }
  338. private void SetContextMenu()
  339. {
  340. if (AnnotationList.SelectedIndex == -1)
  341. {
  342. return;
  343. }
  344. popContextMenu = new ContextMenu();
  345. AnnotationBindData data = annotationList[AnnotationList.SelectedIndex];
  346. MenuItem deleteMenu = new MenuItem();
  347. deleteMenu.Header = LanguageHelper.BotaManager.GetString("Menu_Delete");
  348. deleteMenu.Click -= DeleteMenu_Click;
  349. deleteMenu.Click += DeleteMenu_Click;
  350. popContextMenu.Items.Add(deleteMenu);
  351. MenuItem deleteAllMenu = new MenuItem();
  352. deleteAllMenu.Header = LanguageHelper.BotaManager.GetString("Menu_DeleteAll");
  353. deleteAllMenu.Click -= DeleteAllMenu_Click;
  354. deleteAllMenu.Click += DeleteAllMenu_Click;
  355. popContextMenu.Items.Add(deleteAllMenu);
  356. MenuItem replyMenu = new MenuItem();
  357. replyMenu.Header = LanguageHelper.BotaManager.GetString("Menu_AddReply");
  358. replyMenu.Click += (sender, e) =>
  359. {
  360. if (AnnotationList != null && AnnotationList.SelectedIndex >= 0)
  361. {
  362. data.IsReplyInputVisible = true;
  363. }
  364. };
  365. popContextMenu.Items.Add(replyMenu);
  366. MenuItem showReplyMenu = new MenuItem();
  367. if (data.IsReplyListVisible)
  368. {
  369. showReplyMenu.Header = LanguageHelper.BotaManager.GetString("Menu_FoldReply");
  370. }
  371. else
  372. {
  373. showReplyMenu.Header = LanguageHelper.BotaManager.GetString("Menu_ExpandReply");
  374. }
  375. showReplyMenu.Click += (sender, e) =>
  376. {
  377. if (AnnotationList != null && AnnotationList.SelectedIndex >= 0)
  378. {
  379. data.IsReplyListVisible = !data.IsReplyListVisible;
  380. }
  381. };
  382. popContextMenu.Items.Add(showReplyMenu);
  383. AnnotationList.ContextMenu = popContextMenu;
  384. }
  385. public void DeleteAllAnnot()
  386. {
  387. try
  388. {
  389. Dictionary<int, List<int>> delDict = new Dictionary<int, List<int>>();
  390. foreach (AnnotationBindData bindData in annotationList)
  391. {
  392. if (delDict.ContainsKey(bindData.BindProperty.PageIndex) == false)
  393. {
  394. delDict[bindData.BindProperty.PageIndex] = new List<int>();
  395. }
  396. delDict[bindData.BindProperty.PageIndex].Add(bindData.BindProperty.AnnotIndex);
  397. }
  398. if (delDict.Count > 0)
  399. {
  400. DeleteItemHandler?.Invoke(this, delDict);
  401. }
  402. }
  403. catch (Exception ex)
  404. {
  405. return;
  406. }
  407. }
  408. public void DeleteAllReply()
  409. {
  410. try
  411. {
  412. foreach (var data in annotationList)
  413. {
  414. foreach (var replyData in data.BindProperty.ReplyList)
  415. {
  416. replyData.ReplyAnnotation.RemoveAnnot();
  417. }
  418. }
  419. }
  420. catch (Exception ex)
  421. {
  422. return;
  423. }
  424. }
  425. public void ExpandAllReply(bool isExpand)
  426. {
  427. foreach (AnnotationBindData data in annotationList)
  428. {
  429. data.IsReplyListVisible = isExpand;
  430. }
  431. }
  432. public void ExpandAnnotList(bool isExpand)
  433. {
  434. foreach (AnnotationBindData data in annotationList)
  435. {
  436. if (isExpand)
  437. data.BindProperty.IsAnnotListVisible = Visibility.Visible;
  438. else
  439. data.BindProperty.IsAnnotListVisible = Visibility.Collapsed;
  440. }
  441. }
  442. private void DeleteAllMenu_Click(object sender, RoutedEventArgs e)
  443. {
  444. try
  445. {
  446. Dictionary<int, List<int>> delDict = new Dictionary<int, List<int>>();
  447. foreach (AnnotationBindData bindData in annotationList)
  448. {
  449. if (delDict.ContainsKey(bindData.BindProperty.PageIndex) == false)
  450. {
  451. delDict[bindData.BindProperty.PageIndex] = new List<int>();
  452. }
  453. delDict[bindData.BindProperty.PageIndex].Add(bindData.BindProperty.AnnotIndex);
  454. }
  455. if (delDict.Count > 0)
  456. {
  457. DeleteItemHandler?.Invoke(this, delDict);
  458. }
  459. }
  460. catch (Exception ex)
  461. {
  462. }
  463. }
  464. private void DeleteMenu_Click(object sender, RoutedEventArgs e)
  465. {
  466. try
  467. {
  468. if (AnnotationList != null && AnnotationList.SelectedIndex >= 0)
  469. {
  470. AnnotationBindData bindData = annotationList[AnnotationList.SelectedIndex];
  471. Dictionary<int, List<int>> delDict = new Dictionary<int, List<int>>();
  472. delDict[bindData.BindProperty.PageIndex] = new List<int>()
  473. {
  474. bindData.BindProperty.AnnotIndex
  475. };
  476. DeleteItemHandler?.Invoke(this, delDict);
  477. }
  478. }
  479. catch (Exception ex)
  480. {
  481. }
  482. }
  483. public void SetAnnotationList(List<BindAnnotationResult> results)
  484. {
  485. annotationList.Clear();
  486. AnnotationList.ContextMenu = null;
  487. if (results == null || results.Count == 0)
  488. {
  489. AnnotationList.ItemsSource = null;
  490. NoContentText.Visibility = Visibility.Visible;
  491. return;
  492. }
  493. foreach (BindAnnotationResult item in results)
  494. {
  495. annotationList.Add(new AnnotationBindData()
  496. {
  497. BindProperty = item
  498. });
  499. }
  500. AnnotationList.ItemsSource = annotationList;
  501. if (annotationList.Count > 0)
  502. {
  503. AnnotationList.ContextMenu = popContextMenu;
  504. }
  505. AnnotationList.Visibility = Visibility.Visible;
  506. NoContentText.Visibility = Visibility.Collapsed;
  507. }
  508. private void AnnotationListControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
  509. {
  510. if (enableSelectEvent)
  511. {
  512. try
  513. {
  514. if (e.AddedItems[0] is AnnotationBindData annotationBindData)
  515. {
  516. AnnotationSelectionChanged?.Invoke(this, (annotationBindData).BindProperty);
  517. }
  518. }
  519. catch { }
  520. }
  521. }
  522. public void CancelSelected()
  523. {
  524. AnnotationList.SelectedIndex = -1;
  525. }
  526. public void SelectAnnotationChanged(int annotationIndex = -1)
  527. {
  528. AnnotationList.SelectedIndex = annotationIndex;
  529. }
  530. public void SelectAnnotationChanged(int pageIIndex, int annotIndex)
  531. {
  532. if (annotationList != null && annotationList.Count > 0)
  533. {
  534. for (int i = 0; i < annotationList.Count; i++)
  535. {
  536. AnnotationBindData data = annotationList[i];
  537. if (data.BindProperty.PageIndex == pageIIndex && data.BindProperty.AnnotIndex == annotIndex)
  538. {
  539. enableSelectEvent = false;
  540. AnnotationList.SelectedIndex = i;
  541. enableSelectEvent = true;
  542. break;
  543. }
  544. }
  545. }
  546. }
  547. private void AnnotationList_ContextMenuOpening(object sender, ContextMenuEventArgs e)
  548. {
  549. try
  550. {
  551. if (popContextMenu.Items[0] is MenuItem checkMenu)
  552. {
  553. if (checkMenu != null)
  554. {
  555. checkMenu.IsEnabled = true;
  556. }
  557. if (AnnotationList != null && AnnotationList.SelectedIndex == -1)
  558. {
  559. checkMenu.IsEnabled = false;
  560. }
  561. }
  562. }
  563. catch (Exception ex)
  564. {
  565. }
  566. }
  567. private void AnnotationList_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
  568. {
  569. CancelSelected();
  570. }
  571. private void ToggleButton_Checked(object sender, RoutedEventArgs e)
  572. {
  573. ReplyStatusChanged?.Invoke(sender, CPDFAnnotationState.C_ANNOTATION_MARKED);
  574. }
  575. private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
  576. {
  577. ReplyStatusChanged?.Invoke(sender, CPDFAnnotationState.C_ANNOTATION_UNMARKED);
  578. }
  579. private void StatusControl_ReplyStatusChanged(object sender, CPDFAnnotationState e)
  580. {
  581. ReplyStatusChanged?.Invoke(sender, e);
  582. }
  583. }
  584. }