File indexing completed on 2024-12-22 04:40:10
0001 /* 0002 SPDX-FileCopyrightText: 2022 Mladen Milinkovic <max@smoothware.net> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "subtitlemetawidget.h" 0008 #include "ui_subtitlepositionwidget.h" 0009 0010 #include "appglobal.h" 0011 #include "application.h" 0012 #include "actions/useractionnames.h" 0013 #include "core/subtitle.h" 0014 #include "core/subtitleline.h" 0015 #include "core/richtext/richcss.h" 0016 #include "gui/subtitlemeta/csshighlighter.h" 0017 0018 #include <QHBoxLayout> 0019 #include <QLabel> 0020 #include <QMouseEvent> 0021 #include <QStackedLayout> 0022 #include <QTabBar> 0023 #include <QTabWidget> 0024 #include <QTextEdit> 0025 0026 #include <QDebug> 0027 0028 #include <KLocalizedString> 0029 #include <KTextEdit> 0030 0031 0032 using namespace SubtitleComposer; 0033 0034 SubtitleMetaWidget::SubtitleMetaWidget(QWidget *parent) 0035 : QWidget(parent), 0036 m_subtitle(nullptr), 0037 m_dockTitleWidget(new QWidget(parent)), 0038 m_tabBar(new QTabBar(m_dockTitleWidget)), 0039 m_cssEdit(new QTextEdit(this)), 0040 m_commentIntroEdit(new KTextEdit(this)), 0041 m_commentTopEdit(new KTextEdit(this)), 0042 m_commentBottomEdit(new KTextEdit(this)), 0043 m_subPosition(new SubtitlePositionWidget(this)) 0044 { 0045 m_tabBar->setExpanding(false); 0046 m_tabBar->addTab(i18n("&Stylesheet")); 0047 m_tabBar->addTab(i18n("&Comments")); 0048 m_tabBar->addTab(i18n("&Position")); 0049 m_tabBar->installEventFilter(this); 0050 0051 // parent title widget otherwise QTabBar has strange margins 0052 QHBoxLayout *titleLayout = new QHBoxLayout(); 0053 titleLayout->setContentsMargins(0, 0, 0, 0); 0054 titleLayout->addWidget(m_tabBar); 0055 m_dockTitleWidget->setLayout(titleLayout); 0056 m_dockTitleWidget->setContentsMargins(1, 0, 0, 0); 0057 0058 m_cssEdit->setAcceptRichText(false); 0059 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) 0060 textEdit->setTabStopWidth(4 * QFontMetrics(textEdit->currentFont()).width(QChar::Space)); 0061 #else 0062 m_cssEdit->setTabStopDistance(4 * QFontMetrics(m_cssEdit->currentFont()).horizontalAdvance(QChar::Space)); 0063 #endif 0064 new CSSHighlighter(m_cssEdit->document()); 0065 #if 0 0066 m_cssEdit->setPlainText(R"END(/* example stylesheet */ 0067 0068 ::cue { 0069 background-url: url("base64;something ; something"); 0070 background-image: linear-gradient(to bottom, dimgray, lightgray); 0071 color: papayawhip; 0072 } 0073 /* Style blocks cannot use blank lines nor "dash dash greater than" */ 0074 ::cue(b) { 0075 color: peachpuff; 0076 } 0077 0078 ::cue(#\31) { 0079 color: lime; 0080 } 0081 ::cue(#crédit\ de\ transcription) { 0082 color: red; 0083 } 0084 )END"); 0085 #endif 0086 0087 QTabWidget *comments = new QTabWidget(); 0088 comments->setTabPosition(QTabWidget::East); 0089 comments->addTab(m_commentIntroEdit, i18n("Intro")); 0090 m_commentIntroEdit->installEventFilter(this); 0091 comments->addTab(m_commentTopEdit, i18n("Header")); 0092 m_commentTopEdit->installEventFilter(this); 0093 comments->addTab(m_commentBottomEdit, i18n("Footer")); 0094 m_commentBottomEdit->installEventFilter(this); 0095 0096 QStackedLayout *mainLayout = new QStackedLayout(); 0097 mainLayout->setContentsMargins(0, 0, 0, 0); 0098 mainLayout->addWidget(m_cssEdit); 0099 m_cssEdit->installEventFilter(this); 0100 mainLayout->addWidget(comments); 0101 mainLayout->addWidget(m_subPosition); 0102 setLayout(mainLayout); 0103 0104 connect(m_tabBar, &QTabBar::currentChanged, mainLayout, &QStackedLayout::setCurrentIndex); 0105 } 0106 0107 SubtitleMetaWidget::~SubtitleMetaWidget() 0108 { 0109 } 0110 0111 static QString 0112 mergedComments(const Subtitle *subtitle, const QByteArray &prefix) 0113 { 0114 QString comments; 0115 for(int i = 0;; i++) { 0116 const QByteArray key = prefix + QByteArray::number(i); 0117 if(!subtitle->metaExists(key)) 0118 break; 0119 comments.append(subtitle->meta(key)); 0120 } 0121 return comments; 0122 } 0123 0124 static void 0125 setComments(Subtitle *subtitle, const QByteArray &prefix, const QString &comments) 0126 { 0127 subtitle->meta(prefix + QByteArray("0"), comments); 0128 for(int i = 1; subtitle->metaRemove(prefix + QByteArray::number(i)); i++); 0129 } 0130 0131 void 0132 SubtitleMetaWidget::setSubtitle(Subtitle *subtitle) 0133 { 0134 if(m_subtitle) { 0135 disconnect(m_commentIntroEdit, &KTextEdit::textChanged, this, nullptr); 0136 disconnect(m_commentTopEdit, &KTextEdit::textChanged, this, nullptr); 0137 disconnect(m_commentBottomEdit, &KTextEdit::textChanged, this, nullptr); 0138 disconnect(m_cssEdit->document(), &QTextDocument::contentsChanged, this, nullptr); 0139 } 0140 0141 m_subtitle = subtitle; 0142 0143 if(subtitle) { 0144 m_commentIntroEdit->setPlainText(mergedComments(m_subtitle.constData(), "comment.intro.")); 0145 m_commentTopEdit->setPlainText(mergedComments(m_subtitle.constData(), "comment.top.")); 0146 m_commentBottomEdit->setPlainText(mergedComments(m_subtitle.constData(), "comment.bottom.")); 0147 m_cssEdit->setPlainText(m_subtitle->stylesheet()->unformattedCSS()); 0148 0149 connect(m_commentIntroEdit, &KTextEdit::textChanged, this, [&](){ 0150 setComments(m_subtitle.data(), "comment.intro.", m_commentIntroEdit->toPlainText()); 0151 }); 0152 connect(m_commentTopEdit, &KTextEdit::textChanged, this, [&](){ 0153 setComments(m_subtitle.data(), "comment.top.", m_commentTopEdit->toPlainText()); 0154 }); 0155 connect(m_commentBottomEdit, &KTextEdit::textChanged, this, [&](){ 0156 setComments(m_subtitle.data(), "comment.bottom.", m_commentBottomEdit->toPlainText()); 0157 }); 0158 connect(m_cssEdit->document(), &QTextDocument::contentsChanged, this, [&](){ 0159 m_subtitle->stylesheetEdit(m_cssEdit); 0160 }); 0161 } else { 0162 m_cssEdit->clear(); 0163 m_commentIntroEdit->clear(); 0164 m_commentTopEdit->clear(); 0165 m_commentBottomEdit->clear(); 0166 m_subPosition->setCurrentLine(nullptr); 0167 } 0168 } 0169 0170 static QAction * 0171 actionGet(const QKeySequence &key) 0172 { 0173 QAction *action = app()->action(ACT_UNDO); 0174 if(action->shortcuts().contains(key)) 0175 return action; 0176 action = app()->action(ACT_REDO); 0177 if(action->shortcuts().contains(key)) 0178 return action; 0179 return nullptr; 0180 } 0181 0182 bool 0183 SubtitleMetaWidget::eventFilter(QObject *obj, QEvent *event) 0184 { 0185 // workaround to forward (mouse) events to parent QDockWidget, otherwise it's impossible to drag the dock 0186 if(obj == m_tabBar) { 0187 // grab the mouse so move events are sent 0188 if(event->type() == QEvent::MouseButtonPress) 0189 m_tabBar->grabMouse(); 0190 else if(event->type() == QEvent::MouseButtonRelease && reinterpret_cast<QMouseEvent *>(event)->buttons() == 0) 0191 m_tabBar->releaseMouse(); 0192 // make sure m_tabBar handles the event 0193 static_cast<QObject *>(m_tabBar)->event(event); 0194 // flag it as ignored so QDockWidget can handle it 0195 event->ignore(); 0196 return true; 0197 } else if(event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress) { 0198 if(obj == m_cssEdit || obj == m_commentIntroEdit || obj == m_commentTopEdit || obj == m_commentBottomEdit) { 0199 const QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); 0200 QAction *action = actionGet(keyEvent->modifiers() | keyEvent->key()); 0201 if(action) { 0202 if(event->type() == QEvent::KeyPress) 0203 action->trigger(); 0204 event->accept(); 0205 return true; 0206 } 0207 } 0208 } 0209 return QObject::eventFilter(obj, event); 0210 }