File indexing completed on 2022-11-22 14:07:15

0001 /*
0002     SPDX-FileCopyrightText: 2021 Jean-Baptiste Mardelle
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #pragma once
0007 
0008 #include "ui_textbasededit_ui.h"
0009 #include "definitions.h"
0010 #include "pythoninterfaces/speechtotext.h"
0011 
0012 #include <QProcess>
0013 #include <QAction>
0014 #include <QTextEdit>
0015 #include <QMouseEvent>
0016 #include <QTimer>
0017 #include <QTemporaryFile>
0018 
0019 class ProjectClip;
0020 
0021 /**
0022  * @class VideoTextEdit: Video speech text editor
0023  * @brief A dialog for editing markers and guides.
0024  * @author Jean-Baptiste Mardelle
0025  */
0026 class VideoTextEdit : public QTextEdit
0027 {
0028     Q_OBJECT
0029 
0030 public:
0031     explicit VideoTextEdit(QWidget *parent = nullptr);
0032     void lineNumberAreaPaintEvent(QPaintEvent *event);
0033     int lineNumberAreaWidth();
0034     void repaintLines();
0035     void cleanup();
0036     /** @brief returns the link for the first word at position start in the text.
0037      *    This will seek forwards until a word is found in case selection starts with a space
0038      * @param cursor the current text cursor
0039      * @param start the first position of the selection
0040      * @param max the last position to check in seek operation*/
0041     const QString selectionStartAnchor(QTextCursor &cursor, int start, int max);
0042     /** @brief returns the link for the last word at position end in the text.
0043      *    This will seek backwards until a word is found in case selection ends with a space
0044      * @param cursor the current text cursor
0045      * @param end the last position of the selection
0046      * @param min the first position to check in seek operation*/
0047     const QString selectionEndAnchor(QTextCursor &cursor, int end, int min);
0048     void checkHoverBlock(int yPos);
0049     void blockClicked(Qt::KeyboardModifiers modifiers, bool play = false);
0050     QVector<QPoint> processedZones(const QVector<QPoint> &sourceZones);
0051     QVector<QPoint> getInsertZones();
0052     /** @brief Remove all text outside loadZones
0053      */
0054     void processCutZones(const QList <QPoint> &loadZones);
0055     void rebuildZones();
0056     QVector< QPair<double, double> > speechZones;
0057     QVector <QPoint> cutZones;
0058     QAction *bookmarkAction;
0059     QAction *deleteAction;
0060     
0061 protected:
0062     void mouseMoveEvent(QMouseEvent *e) override;
0063     void mousePressEvent(QMouseEvent *e) override;
0064     void mouseReleaseEvent(QMouseEvent *e) override;
0065     void keyPressEvent(QKeyEvent *e) override;
0066     void resizeEvent(QResizeEvent *e) override;
0067     void contextMenuEvent(QContextMenuEvent *event) override;
0068 
0069 private slots:
0070     void updateLineNumberArea(const QRect &rect, int dy);
0071     
0072 private:
0073     QWidget *lineNumberArea;
0074     int m_hoveredBlock{-1};
0075     int m_lastClickedBlock{-1};
0076     QVector <int> m_selectedBlocks;
0077     int getFirstVisibleBlockId();
0078 };
0079 
0080 class LineNumberArea : public QWidget
0081 {
0082 public:
0083     LineNumberArea(VideoTextEdit *editor) : QWidget(editor), codeEditor(editor)
0084     {
0085         setMouseTracking(true);
0086     }
0087 
0088     QSize sizeHint() const override
0089     {
0090         return QSize(codeEditor->lineNumberAreaWidth(), 0);
0091     }
0092 
0093 protected:
0094     void paintEvent(QPaintEvent *event) override
0095     {
0096         codeEditor->lineNumberAreaPaintEvent(event);
0097     }
0098     void mouseMoveEvent(QMouseEvent *e) override
0099     {
0100         codeEditor->checkHoverBlock(e->pos().y());
0101         QWidget::mouseMoveEvent(e);
0102     }
0103     void mousePressEvent(QMouseEvent *e) override
0104     {
0105         codeEditor->blockClicked(e->modifiers());
0106         QWidget::mousePressEvent(e);
0107     }
0108     void mouseDoubleClickEvent(QMouseEvent *e) override
0109     {
0110         codeEditor->blockClicked(e->modifiers(), true);
0111         QWidget::mouseDoubleClickEvent(e);
0112     }
0113     void wheelEvent(QWheelEvent *e) override
0114     {
0115         qDebug()<<"==== WHEEL OVER LINEAREA";
0116         e->ignore();
0117         //QWidget::wheelEvent(e);
0118     }
0119     void leaveEvent(QEvent *e) override
0120     {
0121         codeEditor->checkHoverBlock(-1);
0122         QWidget::leaveEvent(e);
0123     }
0124 
0125 private:
0126     VideoTextEdit *codeEditor;
0127 };
0128 
0129 /**
0130  * @class TextBasedEdit: Subtitle edit widget
0131  * @brief A dialog for editing markers and guides.
0132  * @author Jean-Baptiste Mardelle
0133  */
0134 class TextBasedEdit : public QWidget, public Ui::TextBasedEdit_UI
0135 {
0136     Q_OBJECT
0137 
0138 public:
0139     explicit TextBasedEdit(QWidget *parent = nullptr);
0140     ~TextBasedEdit() override;
0141     void openClip(std::shared_ptr<ProjectClip>);
0142 
0143 public slots:
0144     void deleteItem();
0145 
0146 private slots:
0147     void startRecognition();
0148     void slotProcessSpeech();
0149     void slotProcessSpeechError();
0150     void slotProcessSpeechStatus(int, QProcess::ExitStatus status);
0151     /** @brief insert currently selected zones to timeline */
0152     void insertToTimeline();
0153     /** @brief Preview current edited text in the clip monitor */
0154     void previewPlaylist(bool createNew = true);
0155     /** @brief Display info message */
0156     void showMessage(const QString &text, KMessageWidget::MessageType type, QAction *action = nullptr);
0157     void addBookmark();
0158 
0159 protected:
0160     bool eventFilter(QObject *obj, QEvent *event) override;
0161 
0162 private:
0163     std::unique_ptr<QProcess> m_speechJob;
0164     std::unique_ptr<QProcess> m_tCodeJob;
0165     /** @brief Id of the master bin clip on which speech processing is done */
0166     QString m_binId;
0167     /** @brief Id of the playlist which is processed from the master clip */
0168     QString m_refId;
0169     QString m_sourceUrl;
0170     double m_clipDuration{0.};
0171     int m_lastPosition;
0172     QString m_errorString;
0173     QAction *m_logAction;
0174     QAction *m_voskConfig;
0175     QAction *m_currentMessageAction{nullptr};
0176     VideoTextEdit *m_visualEditor;
0177     QTextDocument m_document;
0178     QString m_playlist;
0179     QTimer m_hideTimer;
0180     double m_clipOffset;
0181     QTemporaryFile m_playlistWav;
0182     SpeechToText *m_stt;
0183 };