plover2cat 3.1.0a0__tar.gz → 3.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. {plover2cat-3.1.0a0/plover2cat.egg-info → plover2cat-3.1.1}/PKG-INFO +4 -3
  2. {plover2cat-3.1.0a0 → plover2cat-3.1.1/plover2cat.egg-info}/PKG-INFO +4 -3
  3. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover2cat.egg-info/requires.txt +1 -1
  4. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/PloverCATWindow.py +45 -38
  5. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/TextEditor.py +50 -80
  6. plover2cat-3.1.1/plover_cat/__version__.py +2 -0
  7. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/captionWorker.py +47 -8
  8. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/caption_dialog.ui +32 -15
  9. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/rtf_parsing.py +25 -0
  10. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/pyproject.toml +1 -1
  11. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/setup.cfg +1 -1
  12. plover2cat-3.1.0a0/plover_cat/__version__.py +0 -2
  13. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/LICENSE.txt +0 -0
  14. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/MANIFEST.in +0 -0
  15. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/README.md +0 -0
  16. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover2cat.egg-info/SOURCES.txt +0 -0
  17. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover2cat.egg-info/dependency_links.txt +0 -0
  18. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover2cat.egg-info/entry_points.txt +0 -0
  19. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover2cat.egg-info/top_level.txt +0 -0
  20. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover2cat.egg-info/zip-safe +0 -0
  21. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/FlowLayout.py +0 -0
  22. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/__init__.py +0 -0
  23. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/affixDialogWindow.py +0 -0
  24. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/affix_dialog.ui +0 -0
  25. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/captionDialogWindow.py +0 -0
  26. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/constants.py +0 -0
  27. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/create_dialog.ui +0 -0
  28. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/documentWorker.py +0 -0
  29. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/export_helpers.py +0 -0
  30. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/fieldDialogWindow.py +0 -0
  31. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/field_dialog.ui +0 -0
  32. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/helpers.py +0 -0
  33. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/indexDialogWindow.py +0 -0
  34. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/index_dialog.ui +0 -0
  35. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/plover_cat.ui +0 -0
  36. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/qcommands.py +0 -0
  37. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/recorderDialogWindow.py +0 -0
  38. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/recorder_dialog.ui +0 -0
  39. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-270-medium.png +0 -0
  40. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-circle-double-135.png +0 -0
  41. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-curve-180.png +0 -0
  42. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-curve.png +0 -0
  43. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-join.png +0 -0
  44. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-skip-180.png +0 -0
  45. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-skip.png +0 -0
  46. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-split.png +0 -0
  47. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/arrow-stop-180.png +0 -0
  48. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/book-question.png +0 -0
  49. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/card--pencil.png +0 -0
  50. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/card--plus.png +0 -0
  51. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/clipboard--plus.png +0 -0
  52. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/clipboard-paste-document-text.png +0 -0
  53. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/clipboard-paste.png +0 -0
  54. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/clipboard.png +0 -0
  55. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/control-cursor.png +0 -0
  56. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/control-record.png +0 -0
  57. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/control-skip-180.png +0 -0
  58. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/control-skip.png +0 -0
  59. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/control-stop-square.png +0 -0
  60. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/control-stop.png +0 -0
  61. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/cross.png +0 -0
  62. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/disk-black.png +0 -0
  63. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/document-copy.png +0 -0
  64. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/document-import.png +0 -0
  65. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/document-resize-actual.png +0 -0
  66. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/document-text-large.png +0 -0
  67. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/document-text.png +0 -0
  68. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/document.png +0 -0
  69. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-alignment-center.png +0 -0
  70. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-alignment-justify-distribute.png +0 -0
  71. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-alignment-right.png +0 -0
  72. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-alignment.png +0 -0
  73. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-bold.png +0 -0
  74. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-italic.png +0 -0
  75. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-pilcrow.png +0 -0
  76. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-style.png +0 -0
  77. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit-underline.png +0 -0
  78. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/edit.png +0 -0
  79. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/folder-open-document-music.png +0 -0
  80. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/folder-open-document-text.png +0 -0
  81. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/icon.svg +0 -0
  82. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/image--plus.png +0 -0
  83. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/information.png +0 -0
  84. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/lightning.png +0 -0
  85. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/lock.png +0 -0
  86. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/magnifier-zoom-in.png +0 -0
  87. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/magnifier-zoom-out.png +0 -0
  88. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/magnifier.png +0 -0
  89. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/microphone.png +0 -0
  90. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/minus-button.png +0 -0
  91. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/palette.png +0 -0
  92. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/plus-button.png +0 -0
  93. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/resources.qrc +0 -0
  94. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/scissors-blue.png +0 -0
  95. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/spell-check-error.png +0 -0
  96. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/spell-check.png +0 -0
  97. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/resources/wand.png +0 -0
  98. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/shortcutDialogWindow.py +0 -0
  99. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/shortcut_dialog.ui +0 -0
  100. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/spellcheck.py +0 -0
  101. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/steno_objects.py +0 -0
  102. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/suggestDialogWindow.py +0 -0
  103. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/suggest_dialog.ui +0 -0
  104. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/testDialogWindow.py +0 -0
  105. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/plover_cat/test_dialog.ui +0 -0
  106. {plover2cat-3.1.0a0 → plover2cat-3.1.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: plover2cat
3
- Version: 3.1.0a0
3
+ Version: 3.1.1
4
4
  Summary: A CAT software for Plover
5
5
  Home-page: https://github.com/greenwyrt/plover2CAT/
6
6
  Author: plants
@@ -18,12 +18,13 @@ Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE.txt
21
- Requires-Dist: plover>=4.0.0.dev8
21
+ Requires-Dist: plover<5.0.0,>=4.0.0.dev8
22
22
  Requires-Dist: odfpy
23
23
  Requires-Dist: pyparsing>3.0.7
24
24
  Requires-Dist: spylls
25
25
  Requires-Dist: dulwich
26
26
  Requires-Dist: obsws-python>1.6.0
27
+ Dynamic: license-file
27
28
 
28
29
  # plover2CAT
29
30
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: plover2cat
3
- Version: 3.1.0a0
3
+ Version: 3.1.1
4
4
  Summary: A CAT software for Plover
5
5
  Home-page: https://github.com/greenwyrt/plover2CAT/
6
6
  Author: plants
@@ -18,12 +18,13 @@ Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE.txt
21
- Requires-Dist: plover>=4.0.0.dev8
21
+ Requires-Dist: plover<5.0.0,>=4.0.0.dev8
22
22
  Requires-Dist: odfpy
23
23
  Requires-Dist: pyparsing>3.0.7
24
24
  Requires-Dist: spylls
25
25
  Requires-Dist: dulwich
26
26
  Requires-Dist: obsws-python>1.6.0
27
+ Dynamic: license-file
27
28
 
28
29
  # plover2CAT
29
30
 
@@ -1,4 +1,4 @@
1
- plover>=4.0.0.dev8
1
+ plover<5.0.0,>=4.0.0.dev8
2
2
  odfpy
3
3
  pyparsing>3.0.7
4
4
  spylls
@@ -3,17 +3,12 @@ import string
3
3
  import re
4
4
  import pathlib
5
5
  import json
6
- from datetime import datetime, timezone, timedelta
6
+ from datetime import datetime, timedelta
7
7
  import time
8
8
  from collections import Counter, deque
9
- from shutil import copyfile
10
- from copy import deepcopy, copy
9
+ from copy import deepcopy
11
10
  from sys import platform
12
- from tempfile import gettempdir
13
- from spylls.hunspell import Dictionary
14
- from dulwich.repo import Repo
15
- from dulwich.errors import NotGitRepository
16
- from dulwich import porcelain
11
+ from tempfile import gettempdir, TemporaryDirectory
17
12
 
18
13
 
19
14
  from PyQt5 import QtCore, QtGui, QtWidgets
@@ -22,7 +17,7 @@ QCursor, QStandardItem, QStandardItemModel, QPageSize, QTextBlock, QTextFormat,
22
17
  QTextOption, QTextCharFormat, QKeySequence, QPalette, QDesktopServices, QPixmap, QIcon)
23
18
  from PyQt5.QtWidgets import (QMainWindow, QFileDialog, QInputDialog, QListWidgetItem, QTableWidgetItem,
24
19
  QStyle, QMessageBox, QDialog, QFontDialog, QColorDialog, QLabel, QMenu,
25
- QCompleter, QApplication, QTextEdit, QPlainTextEdit, QProgressBar, QAction, QToolButton)
20
+ QCompleter, QApplication, QTextEdit, QPlainTextEdit, QProgressBar, QAction, QToolButton, QDockWidget)
26
21
  from PyQt5.QtMultimedia import (QMediaPlayer, QMediaRecorder,
27
22
  QMultimedia, QVideoEncoderSettings, QAudioEncoderSettings)
28
23
  from PyQt5.QtMultimediaWidgets import QVideoWidget
@@ -117,6 +112,11 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
117
112
  self.flowparent.addLayout(self.recentfileflow)
118
113
  self.flowparent.addStretch()
119
114
  self.video = None
115
+ self.dock_status = {}
116
+ for doc in self.findChildren(QDockWidget):
117
+ self.dock_status[doc.objectName()] = False
118
+ doc.visibilityChanged.connect(lambda status, dock = doc.objectName(): self.dock_handler(status, dock))
119
+ doc.visibilityChanged.connect(lambda status: self.update_gui())
120
120
  # vars for startup
121
121
  ## on very first startup, set tabs up
122
122
  ## later configs will use window settings
@@ -373,9 +373,15 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
373
373
  self.statusBar.showMessage(txt)
374
374
  log.debug(txt)
375
375
 
376
+ def dock_handler(self, status, name):
377
+ """Update dock visibility status"""
378
+ self.dock_status[name] = status
379
+
376
380
  def update_gui(self):
377
381
  """Wrapper for updating parts of GUI when cursor changes position.
378
382
  """
383
+ if not self.textEdit:
384
+ return
379
385
  current_cursor = self.textEdit.textCursor()
380
386
  if current_cursor.block().userData():
381
387
  self.text_to_stroke_move()
@@ -443,6 +449,10 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
443
449
 
444
450
  :param cursor: a ``QTextCursor``, default ``None`` for current cursor
445
451
  """
452
+ if not self.textEdit:
453
+ return
454
+ if not self.dock_status["dockStenoData"]:
455
+ return
446
456
  if not cursor:
447
457
  cursor = self.textEdit.textCursor()
448
458
  block_strokes = cursor.block().userData()["strokes"]
@@ -456,30 +466,20 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
456
466
  if user_choice == QMessageBox.No:
457
467
  return
458
468
  self.textEdit.gen_style_formats()
459
- block = self.textEdit.document().begin()
460
- current_cursor = self.textEdit.textCursor()
461
- self.progressBar = QProgressBar(self)
462
- self.progressBar.setMaximum(self.textEdit.document().blockCount())
463
- self.progressBar.setFormat("Re-style paragraph %v")
464
- self.statusBar.addWidget(self.progressBar)
465
- self.progressBar.show()
469
+ # self.progressBar = QProgressBar(self)
470
+ # self.progressBar.setMaximum(self.textEdit.document().blockCount())
471
+ # self.progressBar.setFormat("Re-style paragraph %v")
472
+ # self.statusBar.addWidget(self.progressBar)
473
+ # self.progressBar.show()
466
474
  self.mainTabs.hide()
467
475
  self.textEdit.setUpdatesEnabled(False)
468
476
  self.textEdit.document().blockSignals(True)
469
477
  self.textEdit.blockSignals(True)
470
- while True:
471
- block_data = block.userData()["strokes"]
472
- try:
473
- block_style = block.userData()["style"]
474
- except TypeError:
475
- # block_style = ""
476
- continue
477
- self.textEdit.refresh_par_style(block)
478
- self.progressBar.setValue(block.blockNumber())
479
- QApplication.processEvents()
480
- if block == self.textEdit.document().lastBlock():
481
- break
482
- block = block.next()
478
+ # todo: make tempfile, use with, then autosave to tempfile, then reload from tempfile with load_transcript
479
+ with TemporaryDirectory() as f:
480
+ temp_path = pathlib.Path(f, "temp.transcript")
481
+ self.textEdit.save_transcript(temp_path)
482
+ self.textEdit.load_transcript(temp_path)
483
483
  self.textEdit.setUpdatesEnabled(True)
484
484
  self.textEdit.document().blockSignals(False)
485
485
  self.textEdit.blockSignals(False)
@@ -723,7 +723,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
723
723
  """
724
724
  if not self.textEdit:
725
725
  return
726
- if not self.dockSuggest.isVisible():
726
+ if not self.dock_status["dockSuggest"]:
727
727
  return
728
728
  if self.suggest_source.currentText() == "tapey-tape":
729
729
  self.get_tapey_tape()
@@ -828,6 +828,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
828
828
  self.update_highlight_color()
829
829
  if self.textEdit:
830
830
  self.textEdit.get_highlight_colors()
831
+ self.refresh_editor_styles()
831
832
 
832
833
  def update_highlight_color(self):
833
834
  settings = QSettings("Plover2CAT", "OpenCAT")
@@ -873,7 +874,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
873
874
 
874
875
  :param pane: a ``QWidget`` in the Toolbox dock's ``QTabWidget``
875
876
  """
876
- if not self.dockProp.isVisible():
877
+ if not self.dock_status["dockProp"]:
877
878
  self.dockProp.setVisible(True)
878
879
  self.tabWidget.setCurrentWidget(pane)
879
880
  log.debug(f"User set {pane.objectName()} pane.")
@@ -883,7 +884,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
883
884
  """
884
885
  if self.textEdit.textCursor().hasSelection() and self.search_text.isChecked():
885
886
  self.search_term.setText(self.textEdit.textCursor().selectedText())
886
- if not self.dockProp.isVisible():
887
+ if not self.dock_status["dockProp"]:
887
888
  self.dockProp.setVisible(True)
888
889
  self.tabWidget.setCurrentWidget(self.find_replace_pane)
889
890
  log.debug("User set find pane visible.")
@@ -901,7 +902,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
901
902
  underlying_strokes = current_block.userData()["strokes"].extract_steno(start_stroke_pos[0], end_stroke_pos[1])
902
903
  underlying_steno = underlying_strokes.to_strokes()
903
904
  self.steno_outline.setText(underlying_steno)
904
- if not self.dockProp.isVisible():
905
+ if not self.dock_status["dockProp"]:
905
906
  self.dockProp.setVisible(True)
906
907
  self.tabWidget.setCurrentWidget(self.stenospell_pane)
907
908
  log.debug("User set steno spell pane visible.")
@@ -1034,11 +1035,12 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
1034
1035
  def update_navigation(self):
1035
1036
  """Create ``QListWidgetItems`` to display headings in navigation dock.
1036
1037
  """
1037
- if not self.dockNavigation.isVisible():
1038
+ self.navigationList.clear()
1039
+ if not self.dock_status["dockNavigation"]:
1040
+ return
1041
+ if not self.textEdit:
1038
1042
  return
1039
1043
  block = self.textEdit.document().begin()
1040
- self.navigationList.clear()
1041
- log.debug("Nagivation pane updated.")
1042
1044
  for i in range(self.textEdit.document().blockCount()):
1043
1045
  block_data = block.userData()
1044
1046
  if not block_data: continue
@@ -1052,6 +1054,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
1052
1054
  if block == self.textEdit.document().lastBlock():
1053
1055
  break
1054
1056
  block = block.next()
1057
+ log.debug("Nagivation pane updated.")
1055
1058
 
1056
1059
  def stroke_to_text_move(self):
1057
1060
  """Locate text in transcript based on selected line in tape.
@@ -1079,6 +1082,10 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
1079
1082
  def text_to_stroke_move(self):
1080
1083
  """Locate stroke line in tape based on cursor position in transcript.
1081
1084
  """
1085
+ if not self.dock_status["dockPaper"]:
1086
+ return
1087
+ if not self.textEdit:
1088
+ return
1082
1089
  stroke_cursor = self.strokeList.textCursor()
1083
1090
  edit_cursor = self.textEdit.textCursor()
1084
1091
  edit_block = edit_cursor.block()
@@ -2726,7 +2733,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
2726
2733
  # if captions are enabled in middle of document, don't start from beginning
2727
2734
  self.caption_cursor_pos = self.textEdit.textCursor().position()
2728
2735
  self.thread = QThread()
2729
- self.cap_worker = captionWorker(max_length = self.caption_dialog.capLength.value(), max_lines = self.caption_dialog.maxDisplayLines.value(),
2736
+ self.cap_worker = captionWorker(roll_caps=self.caption_dialog.rollCaptions.isChecked(), max_length = self.caption_dialog.capLength.value(), max_lines = self.caption_dialog.maxDisplayLines.value(),
2730
2737
  remote = self.caption_dialog.remoteCapHost.currentText(), endpoint = self.caption_dialog.hostURL.text(),
2731
2738
  port = self.caption_dialog.serverPort.text(), password = self.caption_dialog.serverPassword.text())
2732
2739
  self.cap_worker.moveToThread(self.thread)
@@ -2758,7 +2765,7 @@ class PloverCATWindow(QMainWindow, Ui_PloverCAT):
2758
2765
  current_block = current_cursor.block()
2759
2766
  stroke_data = current_block.userData()["strokes"]
2760
2767
  track_pos = current_block.position()
2761
- print(f"initial: {track_pos}")
2768
+ # print(f"initial: {track_pos}")
2762
2769
  while True:
2763
2770
  # this loop can be slow if enormous paragraph
2764
2771
  for el in stroke_data.data:
@@ -12,9 +12,9 @@ from spylls.hunspell import Dictionary
12
12
  from PyQt5 import QtCore, QtGui, QtWidgets
13
13
  from PyQt5.QtGui import QCursor, QKeySequence, QTextCursor, QTextDocument, QColor
14
14
  from PyQt5.QtCore import QFile, QStringListModel, Qt, QModelIndex, pyqtSignal, QUrl, QSettings
15
- from PyQt5.QtWidgets import QPlainTextEdit, QCompleter, QTextEdit, QUndoStack, QMessageBox, QApplication
15
+ from PyQt5.QtWidgets import QCompleter, QTextEdit, QUndoStack, QMessageBox, QApplication
16
16
  from PyQt5.QtMultimedia import (QMediaContent, QMediaPlayer, QMediaRecorder,
17
- QAudioRecorder, QMultimedia, QVideoEncoderSettings, QAudioEncoderSettings)
17
+ QAudioRecorder)
18
18
 
19
19
  _ = lambda txt: QtCore.QCoreApplication.translate("Plover2CAT", txt)
20
20
 
@@ -25,6 +25,7 @@ from plover import log
25
25
 
26
26
  from plover_cat.qcommands import *
27
27
  from plover_cat.steno_objects import *
28
+ from plover_cat.rtf_parsing import *
28
29
  from plover_cat.export_helpers import load_odf_styles, recursive_style_format, parprop_to_blockformat, txtprop_to_textformat
29
30
  from plover_cat.helpers import ms_to_hours, save_json, backup_dictionary_stack, add_custom_dicts, load_dictionary_stack_from_backup, return_commits, hide_file
30
31
  from plover_cat.constants import default_styles, default_config, default_dict
@@ -176,7 +177,7 @@ class PloverCATEditor(QTextEdit):
176
177
  if event.key() != Qt.Key_Return:
177
178
  if event.modifiers() in [Qt.NoModifier, Qt.ShiftModifier]:
178
179
  self.mock_type(event.text())
179
- print(event.key())
180
+ # print(event.key())
180
181
  QTextEdit.keyPressEvent(self, event)
181
182
 
182
183
  def load(self, path, engine, load_transcript = True):
@@ -220,86 +221,55 @@ class PloverCATEditor(QTextEdit):
220
221
  self.send_message.emit("Reading transcript data.")
221
222
  json_document = json.loads(f.read())
222
223
  self.backup_document = deepcopy(json_document)
223
- self.moveCursor(QTextCursor.Start)
224
- self.clear()
225
- document_cursor = self.textCursor()
226
224
  self.send_message.emit("Loading transcript data.")
227
- ef = element_factory()
228
- ea = element_actions()
229
- self.clear()
230
225
  # check if json document is older format
231
226
  if "data" in json_document[next(iter(json_document))]:
232
- # old format json
233
- for key, value in json_document.items():
234
- if not key.isdigit():
235
- continue
236
- block_data = BlockUserData()
237
- el_list = []
238
- for el in value["data"]["strokes"]:
239
- el_dict = {"time": el[0], "stroke": el[1], "data": el[2]}
240
- if len(el) == 4:
241
- el_dict["audiotime"] = el[4]
242
- new_stroke = stroke_text()
243
- new_stroke.from_dict(el_dict)
244
- el_list.append(new_stroke)
245
- for k, v in value["data"].items():
246
- block_data[k] = v
247
- block_data["strokes"] = element_collection(el_list)
248
- document_cursor.setBlockFormat(self.par_formats[block_data["style"]])
249
- current_format = self.txt_formats[block_data["style"]]
250
- current_format.setForeground(self.highlight_colors["stroke"])
251
- # document_cursor.setCharFormat(current_format)
252
- document_cursor.insertText(value["text"], current_format)
253
- document_cursor.block().setUserData(block_data)
254
- document_cursor.block().setUserState(1)
255
- if len(block_data["strokes"]) > 0 and block_data["strokes"].ends_with("\n"):
256
- document_cursor.insertText("\n")
257
- self.send_message.emit(f"Loading paragraph {document_cursor.blockNumber()} of {len(json_document)}")
258
- QApplication.processEvents()
259
- else:
260
- # new format json
261
- for key, value in json_document.items():
262
- # skip if key is not a digit
263
- if not key.isdigit():
264
- continue
265
- block_data = BlockUserData()
266
- el_list = [ef.gen_element(element_dict = i, user_field_dict = self.user_field_dict) for i in value["strokes"]]
267
- # document_cursor.movePosition(QTextCursor.Start)
268
- self.setTextCursor(document_cursor)
269
- for k, v in value.items():
270
- block_data[k] = v
271
- block_data["strokes"] = element_collection()
272
- document_cursor.block().setUserData(block_data)
273
- block_data["strokes"] = element_collection(el_list)
274
- if block_data["style"] not in self.par_formats:
275
- block_data["style"] = next(iter(self.par_formats))
276
- document_cursor.setBlockFormat(self.par_formats[block_data["style"]])
277
- document_cursor.setCharFormat(self.txt_formats[block_data["style"]])
278
- # if any([el.element == "image" for el in el_list]):
279
- for el in el_list:
280
- if el.element == "image":
281
- i_path = self.file_name / pathlib.Path(el.path)
282
- imageUri = QUrl(i_path.as_uri())
283
- el.path = i_path.as_posix()
284
- image = QImage(QImageReader(el.path).read())
285
- self.document().addResource(
286
- QTextDocument.ImageResource,
287
- imageUri,
288
- QVariant(image)
289
- )
290
- imageFormat = QTextImageFormat()
291
- imageFormat.setWidth(image.width())
292
- imageFormat.setHeight(image.height())
293
- imageFormat.setName(imageUri.toString())
294
- document_cursor.insertImage(imageFormat)
295
- document_cursor.setCharFormat(self.txt_formats[block_data["style"]])
296
- else:
297
- current_format = self.txt_formats[block_data["style"]]
298
- current_format.setForeground(self.highlight_colors[el.element])
299
- # document_cursor.setCharFormat(current_format)
300
- document_cursor.insertText(el.to_text(), current_format)
301
- self.send_message.emit(f"Loading paragraph {document_cursor.blockNumber()} of {len(json_document)}")
302
- QApplication.processEvents()
227
+ self.backup_document = import_version_one(json_document)
228
+ else:
229
+ self.backup_document = import_version_two(json_document)
230
+ self.clear()
231
+ self.moveCursor(QTextCursor.Start)
232
+ document_cursor = self.textCursor()
233
+ ef = element_factory()
234
+ for key, value in self.backup_document.items():
235
+ # skip if key is not a digit
236
+ if not key.isdigit():
237
+ continue
238
+ block_data = BlockUserData()
239
+ el_list = [ef.gen_element(element_dict = i, user_field_dict = self.user_field_dict) for i in value["strokes"]]
240
+ self.setTextCursor(document_cursor)
241
+ for k, v in value.items():
242
+ block_data[k] = v
243
+ block_data["strokes"] = element_collection()
244
+ document_cursor.block().setUserData(block_data)
245
+ block_data["strokes"] = element_collection(el_list)
246
+ if block_data["style"] not in self.par_formats:
247
+ block_data["style"] = next(iter(self.par_formats))
248
+ document_cursor.setBlockFormat(self.par_formats[block_data["style"]])
249
+ document_cursor.setCharFormat(self.txt_formats[block_data["style"]])
250
+ for el in el_list:
251
+ if el.element == "image":
252
+ i_path = self.file_name / pathlib.Path(el.path)
253
+ imageUri = QUrl(i_path.as_uri())
254
+ el.path = i_path.as_posix()
255
+ image = QImage(QImageReader(el.path).read())
256
+ self.document().addResource(
257
+ QTextDocument.ImageResource,
258
+ imageUri,
259
+ QVariant(image)
260
+ )
261
+ imageFormat = QTextImageFormat()
262
+ imageFormat.setWidth(image.width())
263
+ imageFormat.setHeight(image.height())
264
+ imageFormat.setName(imageUri.toString())
265
+ document_cursor.insertImage(imageFormat)
266
+ document_cursor.setCharFormat(self.txt_formats[block_data["style"]])
267
+ else:
268
+ current_format = self.txt_formats[block_data["style"]]
269
+ current_format.setForeground(self.highlight_colors[el.element])
270
+ document_cursor.insertText(el.to_text(), current_format)
271
+ self.send_message.emit(f"Loading paragraph {document_cursor.blockNumber()} of {len(json_document)}")
272
+ QApplication.processEvents()
303
273
  if document_cursor.block().userData() == None:
304
274
  document_cursor.block().setUserData(BlockUserData())
305
275
  self.to_next_style()
@@ -0,0 +1,2 @@
1
+ __version__ = "3.1.1"
2
+
@@ -1,4 +1,5 @@
1
- from urllib import request, parse
1
+ from urllib import request
2
+ from urllib.parse import urlunparse, urlparse
2
3
  from urllib.error import HTTPError
3
4
  from PyQt5.QtCore import QObject, pyqtSignal
4
5
  from queue import Queue, Empty
@@ -14,7 +15,8 @@ class captionWorker(QObject):
14
15
 
15
16
  ``captionWorker`` is put into another thread and doesn't run on the main event thread.
16
17
  Text gets ingested and then sent out as formatted caption lines.
17
-
18
+
19
+ :param roll_caps: boolean, whether to use incremental captions or transcript-like
18
20
  :param max_length: maximum number of characters for each caption line,
19
21
  suggested value 32, default None
20
22
  :type max_length: int, optional
@@ -37,8 +39,9 @@ class captionWorker(QObject):
37
39
  """Signal sent when worker is done."""
38
40
  postMessage = pyqtSignal(str)
39
41
  """Signal sent with message to display."""
40
- def __init__(self, max_length = None, max_lines = None, remote = None, endpoint = None, port = None, password = None):
42
+ def __init__(self, roll_caps = True, max_length = None, max_lines = None, remote = None, endpoint = None, port = None, password = None):
41
43
  QObject.__init__(self)
44
+ self.roll_caps = roll_caps
42
45
  self.max_length = max_length
43
46
  self.max_lines = max_lines
44
47
  self.remote = remote
@@ -52,13 +55,28 @@ class captionWorker(QObject):
52
55
  self.endpoint = "localhost"
53
56
  self.obs = obs.ReqClient(host=self.endpoint, port=self.port, password=self.password, timeout=3)
54
57
  self.obs_queue = deque(maxlen = self.max_lines)
58
+ if self.remote == "Zoom":
59
+ self.zoom_seq = 1
60
+ zoom_url = urlparse(self.endpoint)
61
+ zoom_params = zoom_url._replace(path="/closedcaption/seq")
62
+ seq_url = urlunparse(zoom_params)
63
+ req = request.Request(seq_url, method = "GET")
64
+ r = request.urlopen(req)
65
+ if r.status == 200:
66
+ string_seq = r.read()
67
+ self.zoom_seq = int(string_seq.decode()) + 1
55
68
  self.word_queue = Queue()
56
69
  """Queue containing text split into word chunks."""
57
- self.cap_queue = deque(maxlen = max_lines)
70
+ if not self.roll_caps:
71
+ self.cap_queue = Queue()
72
+ else:
73
+ self.cap_queue = deque(maxlen = max_lines)
58
74
  """Queue containing formatted caption lines ready for display."""
59
75
  self.next_word = ""
60
- self.zoom_seq = 1
61
76
  """Line number for caption, required for Zoom captions."""
77
+ self.cap_line = ""
78
+ """Buffer for holding caption, when non-rolling"""
79
+
62
80
  def intake(self, text):
63
81
  """Receive text from main editor and create work chunks for captions
64
82
  :param text: text written into editor
@@ -69,8 +87,26 @@ class captionWorker(QObject):
69
87
  for i in chunks:
70
88
  # tuple, first text, then time
71
89
  self.word_queue.put((i, text_time))
72
- self.make_caps()
90
+ if not self.roll_caps:
91
+ self.make_caps()
92
+ else:
93
+ self.make_roll_caps()
73
94
  def make_caps(self):
95
+ while not self.word_queue.empty():
96
+ self.next_word, text_time = self.word_queue.get()
97
+ if self.max_length != 0 and (len(self.cap_line) + len(self.next_word)) > self.max_length:
98
+ self.cap_queue.put((self.cap_line, text_time))
99
+ self.cap_line = self.next_word
100
+ # self.send_cap()
101
+ elif "\u2029" in self.next_word:
102
+ self.cap_line += self.next_word.replace("\u2029", "")
103
+ self.cap_queue.put((self.cap_line, text_time))
104
+ self.cap_line = ""
105
+ # self.send_cap()
106
+ else:
107
+ self.cap_line += self.next_word
108
+ self.send_cap()
109
+ def make_roll_caps(self):
74
110
  """Ingest word chunks from queue and put lines into caption queue.
75
111
  """
76
112
  while not self.word_queue.empty():
@@ -92,8 +128,11 @@ class captionWorker(QObject):
92
128
  """Take caption from queue and send to display, and also if endpoint is defined.
93
129
  """
94
130
  try:
95
- last_caps = list(self.cap_queue)
96
- cap = "\n".join(c[0].lstrip(" ") for c in last_caps if c[0].lstrip(" "))
131
+ if not self.roll_caps:
132
+ cap, time = self.cap_queue.get_nowait()
133
+ else:
134
+ last_caps = list(self.cap_queue)
135
+ cap = "\n".join(c[0].lstrip(" ") for c in last_caps if c[0].lstrip(" "))
97
136
  self.capSend.emit(cap)
98
137
  if self.endpoint:
99
138
  if self.remote == "Microsoft Teams":
@@ -7,7 +7,7 @@
7
7
  <x>0</x>
8
8
  <y>0</y>
9
9
  <width>555</width>
10
- <height>237</height>
10
+ <height>243</height>
11
11
  </rect>
12
12
  </property>
13
13
  <property name="windowTitle">
@@ -26,14 +26,14 @@
26
26
  </property>
27
27
  </widget>
28
28
  </item>
29
- <item row="2" column="0">
29
+ <item row="3" column="0">
30
30
  <widget class="QLabel" name="label">
31
31
  <property name="text">
32
32
  <string>Maximum caption length:</string>
33
33
  </property>
34
34
  </widget>
35
35
  </item>
36
- <item row="2" column="1">
36
+ <item row="3" column="1">
37
37
  <widget class="QSpinBox" name="capLength">
38
38
  <property name="toolTip">
39
39
  <string>Maximum number of characters in one line</string>
@@ -46,7 +46,7 @@
46
46
  </property>
47
47
  </widget>
48
48
  </item>
49
- <item row="3" column="1">
49
+ <item row="4" column="1">
50
50
  <widget class="QSpinBox" name="maxDisplayLines">
51
51
  <property name="toolTip">
52
52
  <string>Only display this number of lines in caption window</string>
@@ -59,14 +59,14 @@
59
59
  </property>
60
60
  </widget>
61
61
  </item>
62
- <item row="3" column="0">
62
+ <item row="4" column="0">
63
63
  <widget class="QLabel" name="label_6">
64
64
  <property name="text">
65
65
  <string>Display max lines:</string>
66
66
  </property>
67
67
  </widget>
68
68
  </item>
69
- <item row="4" column="1">
69
+ <item row="5" column="1">
70
70
  <widget class="QPushButton" name="fontSelector">
71
71
  <property name="toolTip">
72
72
  <string>Font for display</string>
@@ -76,14 +76,14 @@
76
76
  </property>
77
77
  </widget>
78
78
  </item>
79
- <item row="4" column="0">
79
+ <item row="5" column="0">
80
80
  <widget class="QLabel" name="label_7">
81
81
  <property name="text">
82
82
  <string>Display font:</string>
83
83
  </property>
84
84
  </widget>
85
85
  </item>
86
- <item row="5" column="1">
86
+ <item row="6" column="1">
87
87
  <widget class="QComboBox" name="remoteCapHost">
88
88
  <property name="toolTip">
89
89
  <string>Destination to send captions to</string>
@@ -110,14 +110,14 @@
110
110
  </item>
111
111
  </widget>
112
112
  </item>
113
- <item row="5" column="0">
113
+ <item row="6" column="0">
114
114
  <widget class="QLabel" name="label_5">
115
115
  <property name="text">
116
116
  <string>Remote Endpoint:</string>
117
117
  </property>
118
118
  </widget>
119
119
  </item>
120
- <item row="6" column="1">
120
+ <item row="7" column="1">
121
121
  <widget class="QLineEdit" name="hostURL">
122
122
  <property name="enabled">
123
123
  <bool>false</bool>
@@ -127,28 +127,28 @@
127
127
  </property>
128
128
  </widget>
129
129
  </item>
130
- <item row="6" column="0">
130
+ <item row="7" column="0">
131
131
  <widget class="QLabel" name="label_4">
132
132
  <property name="text">
133
133
  <string>Remote URL/Token:</string>
134
134
  </property>
135
135
  </widget>
136
136
  </item>
137
- <item row="7" column="1">
137
+ <item row="8" column="1">
138
138
  <widget class="QLineEdit" name="serverPort">
139
139
  <property name="enabled">
140
140
  <bool>false</bool>
141
141
  </property>
142
142
  </widget>
143
143
  </item>
144
- <item row="7" column="0">
144
+ <item row="8" column="0">
145
145
  <widget class="QLabel" name="label_2">
146
146
  <property name="text">
147
147
  <string>Port:</string>
148
148
  </property>
149
149
  </widget>
150
150
  </item>
151
- <item row="8" column="1">
151
+ <item row="9" column="1">
152
152
  <widget class="QLineEdit" name="serverPassword">
153
153
  <property name="enabled">
154
154
  <bool>false</bool>
@@ -158,7 +158,7 @@
158
158
  </property>
159
159
  </widget>
160
160
  </item>
161
- <item row="8" column="0">
161
+ <item row="9" column="0">
162
162
  <widget class="QLabel" name="label_9">
163
163
  <property name="text">
164
164
  <string>Password:</string>
@@ -198,6 +198,23 @@
198
198
  </property>
199
199
  </widget>
200
200
  </item>
201
+ <item row="2" column="0">
202
+ <widget class="QLabel" name="label_3">
203
+ <property name="text">
204
+ <string>Roll Captions</string>
205
+ </property>
206
+ </widget>
207
+ </item>
208
+ <item row="2" column="1">
209
+ <widget class="QCheckBox" name="rollCaptions">
210
+ <property name="text">
211
+ <string>Yes (Default)</string>
212
+ </property>
213
+ <property name="checked">
214
+ <bool>true</bool>
215
+ </property>
216
+ </widget>
217
+ </item>
201
218
  </layout>
202
219
  </item>
203
220
  <item>
@@ -29,6 +29,7 @@ from pyparsing import (
29
29
  from plover import log
30
30
 
31
31
  from plover_cat.steno_objects import *
32
+
32
33
  # control chars \ { }
33
34
 
34
35
 
@@ -479,3 +480,27 @@ def load_rtf_styles(parse_results):
479
480
  renamed_indiv_style.append(new_style_name)
480
481
  return(style_dict, renamed_indiv_style)
481
482
 
483
+ def import_version_one(json_document):
484
+ """Formats JSON file with older transcript format into standard transcript dict form"""
485
+ transcript_dict = {}
486
+ for key, value in json_document.items():
487
+ if not key.isdigit():
488
+ continue
489
+ el_list = []
490
+ for el in value["data"]["strokes"]:
491
+ el_dict = {"time": el[0], "stroke": el[1], "data": el[2]}
492
+ if len(el) == 4:
493
+ el_dict["audiotime"] = el[4]
494
+ new_stroke = stroke_text()
495
+ new_stroke.from_dict(el_dict)
496
+ el_list.append(new_stroke)
497
+ block_data = {}
498
+ for k, v in value["data"].items():
499
+ block_data[k] = v
500
+ block_data["strokes"] = element_collection(el_list).to_json()
501
+ transcript_dict[str(key)] = block_data
502
+ return(transcript_dict)
503
+
504
+ def import_version_two(json_document):
505
+ """Formats JSON file with newer transcript format into standard transcript dict form"""
506
+ return(json_document)
@@ -1,6 +1,6 @@
1
1
  [build-system]
2
2
  requires = [
3
- "plover[gui_qt]>=4.0.0.dev10",
3
+ "plover[gui_qt]>=4.0.0.dev10,<5.0.0",
4
4
  "setuptools>=38.2.4",
5
5
  "wheel",
6
6
  ]
@@ -23,7 +23,7 @@ keywords = plover plover_plugin
23
23
  [options]
24
24
  zip_safe = True
25
25
  install_requires =
26
- plover>=4.0.0.dev8
26
+ plover>=4.0.0.dev8,<5.0.0
27
27
  odfpy
28
28
  pyparsing > 3.0.7
29
29
  spylls
@@ -1,2 +0,0 @@
1
- __version__ = "3.1.0-alpha"
2
-
File without changes
File without changes
File without changes
File without changes