File indexing completed on 2024-06-16 04:38:23

0001 /*
0002     SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar>
0003     SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "currentlinewidget.h"
0009 #include "core/richtext/richdocument.h"
0010 #include "helpers/common.h"
0011 #include "scconfig.h"
0012 #include "widgets/timeedit.h"
0013 #include "widgets/simplerichtextedit.h"
0014 
0015 #include <QComboBox>
0016 #include <QCursor>
0017 #include <QDebug>
0018 #include <QGridLayout>
0019 #include <QGroupBox>
0020 #include <QIcon>
0021 #include <QKeyEvent>
0022 #include <QLabel>
0023 #include <QLineEdit>
0024 #include <QPushButton>
0025 #include <QStringBuilder>
0026 #include <QTextDocument>
0027 #include <QTimer>
0028 #include <QToolButton>
0029 
0030 #include <KConfigGroup>
0031 #include <KLocalizedString>
0032 
0033 #include <forward_list>
0034 
0035 #define TOOLBUTTON_SIZE 21
0036 
0037 using namespace SubtitleComposer;
0038 
0039 enum { COL_TIME, COL_PRIMARY, COL_SECONDARY };
0040 
0041 QTextDocument CurrentLineWidget::m_blankDoc;
0042 
0043 
0044 /// Breadcrumb Widget
0045 
0046 namespace SubtitleComposer {
0047 
0048 class Breadcrumb : public QWidget {
0049     using WidgetList = std::forward_list<QWidget *>;
0050 
0051 public:
0052     Breadcrumb(SimpleRichTextEdit *textEdit, CurrentLineWidget *parent);
0053 
0054 private:
0055     void crumbUpdate();
0056     void scheduleUpdate() { m_timer->start(100); }
0057     QPushButton *addButton();
0058     QLabel *addSeparator();
0059     void startLayout();
0060     void finishLayout();
0061     void hideAll();
0062 
0063 private:
0064     QTimer *m_timer;
0065     WidgetList m_elements;
0066     WidgetList::const_iterator m_iter;
0067     WidgetList::const_iterator m_last;
0068     CurrentLineWidget *m_lineWidget;
0069     QHBoxLayout *m_layout;
0070     SimpleRichTextEdit *m_textEdit;
0071 };
0072 
0073 }
0074 
0075 Breadcrumb::Breadcrumb(SimpleRichTextEdit *textEdit, CurrentLineWidget *parent)
0076     : QWidget(parent),
0077       m_timer(new QTimer(this)),
0078       m_lineWidget(parent),
0079       m_layout(new QHBoxLayout(this)),
0080       m_textEdit(textEdit)
0081 {
0082     QFont f = font();
0083     f.setPointSize(f.pointSize() - 1);
0084     setFont(f);
0085     setContentsMargins(3, 0, 3, 0);
0086 
0087     m_layout->setContentsMargins(0, 0, 0, 0);
0088     m_layout->setSpacing(0);
0089 
0090     connect(m_textEdit, &SimpleRichTextEdit::textChanged, this, &Breadcrumb::scheduleUpdate);
0091     connect(m_textEdit, &SimpleRichTextEdit::cursorPositionChanged, this, &Breadcrumb::scheduleUpdate);
0092     connect(m_timer, &QTimer::timeout, this, &Breadcrumb::crumbUpdate);
0093     m_timer->setSingleShot(true);
0094 }
0095 
0096 void
0097 Breadcrumb::startLayout()
0098 {
0099     m_iter = m_elements.cbegin();
0100     if(m_iter != m_elements.cend()) {
0101         ++m_iter;
0102         return;
0103     }
0104     m_layout->addStretch(1);
0105     m_elements.push_front(nullptr);
0106     m_last = m_elements.cbegin();
0107 }
0108 
0109 QPushButton *
0110 Breadcrumb::addButton()
0111 {
0112     QPushButton *b;
0113     if(m_iter != m_elements.cend()) {
0114         b = static_cast<QPushButton *>(*m_iter);
0115         b->show();
0116         ++m_iter;
0117         return b;
0118     }
0119 
0120     b = new QPushButton(this);
0121     connect(b, &QPushButton::clicked, this, [&](){
0122         m_lineWidget->onBreadcrumbClick(
0123                     static_cast<QPushButton *>(QObject::sender()),
0124                     m_textEdit);
0125     });
0126     b->setFocusPolicy(Qt::NoFocus);
0127     m_layout->insertWidget(0, b);
0128     m_last = m_elements.insert_after(m_last, b);
0129     return b;
0130 }
0131 
0132 QLabel *
0133 Breadcrumb::addSeparator()
0134 {
0135     QLabel *l;
0136     if(m_iter != m_elements.cend()) {
0137         l = static_cast<QLabel *>(*m_iter);
0138         l->show();
0139         ++m_iter;
0140         return l;
0141     }
0142 
0143     l = new QLabel($(" > "), this);
0144     m_layout->insertWidget(0, l);
0145     m_last = m_elements.insert_after(m_last, l);
0146     return l;
0147 }
0148 
0149 void
0150 Breadcrumb::finishLayout()
0151 {
0152     while(m_iter != m_elements.cend()) {
0153         (*m_iter)->hide();
0154         ++m_iter;
0155     }
0156 }
0157 
0158 void
0159 Breadcrumb::hideAll()
0160 {
0161     m_iter = m_elements.cbegin();
0162     while(m_iter != m_elements.cend()) {
0163         if(*m_iter)
0164             (*m_iter)->hide();
0165         ++m_iter;
0166     }
0167 }
0168 
0169 void
0170 Breadcrumb::crumbUpdate()
0171 {
0172     RichDocument *doc = qobject_cast<RichDocument *>(m_textEdit->document());
0173     if(!doc)
0174         return hideAll();
0175     QFontMetrics fm(font());
0176     const quint32 pos = m_textEdit->textCursor().position();
0177     RichDOM::Node *n = doc->nodeAt(pos ? pos - 1 : 0);
0178     if(!n)
0179         return hideAll();
0180 
0181     startLayout();
0182     for(;;) {
0183         QPushButton *b = addButton();
0184         b->setText(n->cssSel());
0185         b->setProperty("start", n->nodeStart);
0186         b->setProperty("end", n->nodeEnd);
0187         b->setFixedSize(fm.size(0, b->text()) + QSize(fm.height(), 2));
0188         n = n->parent;
0189         if(!n)
0190             break;
0191         addSeparator();
0192     }
0193     finishLayout();
0194 }
0195 
0196 
0197 /// CurrentLineWidget
0198 
0199 CurrentLineWidget::CurrentLineWidget(QWidget *parent)
0200     : QWidget(parent),
0201       m_subtitle(nullptr),
0202       m_currentLine(nullptr),
0203       m_translationMode(false)
0204 {
0205     QGridLayout *mainLayout = new QGridLayout(this);
0206     mainLayout->setContentsMargins(0, 0, 0, 0);
0207     mainLayout->setSpacing(0);
0208 
0209     QGroupBox *timesControlsGroupBox = new QGroupBox(this);
0210     {
0211         QGridLayout *timesControlsLayout = new QGridLayout(timesControlsGroupBox);
0212         timesControlsLayout->setContentsMargins(5, 4, 4, 4);
0213         timesControlsLayout->setHorizontalSpacing(5);
0214         timesControlsLayout->setVerticalSpacing(2);
0215 
0216         QLabel *showTimeLabel = new QLabel(timesControlsGroupBox);
0217         showTimeLabel->setText(i18n("<b>Show</b>"));
0218         timesControlsLayout->addWidget(showTimeLabel, 0, 0);
0219 
0220         m_showTimeEdit = new TimeEdit(timesControlsGroupBox);
0221         m_showTimeEdit->setFocusPolicy(Qt::ClickFocus);
0222         timesControlsLayout->addWidget(m_showTimeEdit, 0, 1);
0223 
0224         QLabel *hideTimeLabel = new QLabel(timesControlsGroupBox);
0225         hideTimeLabel->setText(i18n("<b>Hide</b>"));
0226         timesControlsLayout->addWidget(hideTimeLabel, 1, 0);
0227 
0228         m_hideTimeEdit = new TimeEdit(timesControlsGroupBox);
0229         m_hideTimeEdit->setFocusPolicy(Qt::ClickFocus);
0230         timesControlsLayout->addWidget(m_hideTimeEdit, 1, 1);
0231 
0232         QLabel *durationTimeLabel = new QLabel(timesControlsGroupBox);
0233         durationTimeLabel->setText(i18n("<b>Duration</b>"));
0234         timesControlsLayout->addWidget(durationTimeLabel, 2, 0);
0235 
0236         m_durationTimeEdit = new TimeEdit(timesControlsGroupBox);
0237         m_durationTimeEdit->setFocusPolicy(Qt::ClickFocus);
0238         timesControlsLayout->addWidget(m_durationTimeEdit, 2, 1);
0239     }
0240     timesControlsGroupBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
0241     mainLayout->addWidget(timesControlsGroupBox, 0, COL_TIME);
0242 
0243     m_boxPrimary = createLineWidgetBox(0);
0244     mainLayout->setColumnStretch(COL_PRIMARY, 1);
0245     mainLayout->addWidget(m_boxPrimary, 0, COL_PRIMARY);
0246 
0247     m_boxTranslation = createLineWidgetBox(1);
0248     mainLayout->addWidget(m_boxTranslation, 0, COL_SECONDARY);
0249 
0250     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
0251 
0252     connect(m_showTimeEdit, &TimeEdit::valueChanged, this, &CurrentLineWidget::onShowTimeEditChanged);
0253     connect(m_hideTimeEdit, &TimeEdit::valueChanged, this, &CurrentLineWidget::onHideTimeEditChanged);
0254     connect(m_durationTimeEdit, &TimeEdit::valueChanged, this, &CurrentLineWidget::onDurationTimeEditChanged);
0255 
0256     setTranslationMode(m_translationMode);
0257 
0258     connect(SCConfig::self(), &KCoreConfigSkeleton::configChanged, this, &CurrentLineWidget::onConfigChanged);
0259 }
0260 
0261 CurrentLineWidget::~CurrentLineWidget()
0262 {
0263 }
0264 
0265 QToolButton *
0266 CurrentLineWidget::createToolButton(const QString &text, const char *icon, bool checkable)
0267 {
0268     QToolButton *btn = new QToolButton(this);
0269     btn->setToolTip(text);
0270     btn->setIcon(QIcon::fromTheme(icon));
0271     btn->setMinimumSize(TOOLBUTTON_SIZE, TOOLBUTTON_SIZE);
0272     btn->setMaximumSize(TOOLBUTTON_SIZE, TOOLBUTTON_SIZE);
0273     btn->setCheckable(checkable);
0274     btn->setAutoRaise(true);
0275     btn->setFocusPolicy(Qt::NoFocus);
0276     return btn;
0277 }
0278 
0279 QWidget *
0280 CurrentLineWidget::createLineWidgetBox(int index)
0281 {
0282     enum {
0283         COL_DURATION, COL_SPACER,
0284         COL_VOICE, COL_CLASS, COL_BOLD, COL_ITALIC, COL_UNDERLINE, COL_STRIKE, COL_COLOR,
0285         COL_TOTAL
0286     };
0287 
0288     QGridLayout *layout = new QGridLayout();
0289     layout->setContentsMargins(2, 3, 1, 0);
0290     layout->setHorizontalSpacing(4);
0291     layout->setVerticalSpacing(2);
0292     layout->setColumnStretch(0, 1);
0293 
0294     QLabel *textLabel = new QLabel(this);
0295     textLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
0296     textLabel->setTextFormat(Qt::RichText);
0297     textLabel->setIndent(3);
0298     textLabel->setWordWrap(true);
0299     QFont f = textLabel->font();
0300     f.setPointSize(f.pointSize() - 1);
0301     textLabel->setFont(f);
0302     layout->addWidget(textLabel, 0, COL_DURATION);
0303     m_textLabels[index] = textLabel;
0304 
0305     SimpleRichTextEdit *textEdit = new SimpleRichTextEdit(this);
0306     textEdit->setDocument(&m_blankDoc);
0307     textEdit->setTabChangesFocus(true);
0308     textEdit->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
0309     layout->addWidget(textEdit, 1, 0, 1, COL_TOTAL);
0310     m_textEdits[index] = textEdit;
0311 
0312     layout->addWidget(new Breadcrumb(textEdit, this), 2, 0, 1, 7);
0313 
0314     QToolButton *btnVoice = createToolButton(i18n("Change Voice Tag"), "actor", false);
0315     connect(btnVoice, &QToolButton::clicked, textEdit, &SimpleRichTextEdit::changeTextVoice);
0316     layout->addWidget(btnVoice, 0, COL_VOICE, Qt::AlignBottom);
0317 
0318     QToolButton *btnClass = createToolButton(i18n("Change Class Tag"), "format-text-code", false);
0319     connect(btnClass, &QToolButton::clicked, textEdit, &SimpleRichTextEdit::changeTextClass);
0320     layout->addWidget(btnClass, 0, COL_CLASS, Qt::AlignBottom);
0321 
0322     QToolButton *btnBold = createToolButton(i18n("Toggle Bold"), "format-text-bold");
0323     connect(btnBold, &QToolButton::clicked, textEdit, &SimpleRichTextEdit::toggleFontBold);
0324     layout->addWidget(btnBold, 0, COL_BOLD, Qt::AlignBottom);
0325 
0326     QToolButton *btnItalic = createToolButton(i18n("Toggle Italic"), "format-text-italic");
0327     connect(btnItalic, &QToolButton::clicked, textEdit, &SimpleRichTextEdit::toggleFontItalic);
0328     layout->addWidget(btnItalic, 0, COL_ITALIC, Qt::AlignBottom);
0329 
0330     QToolButton *btnUnderline = createToolButton(i18n("Toggle Underline"), "format-text-underline");
0331     connect(btnUnderline, &QToolButton::clicked, textEdit, &SimpleRichTextEdit::toggleFontUnderline);
0332     layout->addWidget(btnUnderline, 0, COL_UNDERLINE, Qt::AlignBottom);
0333 
0334     QToolButton *btnStrike = createToolButton(i18n("Toggle Strike Through"), "format-text-strikethrough");
0335     connect(btnStrike, &QToolButton::clicked, textEdit, &SimpleRichTextEdit::toggleFontStrikeOut);
0336     layout->addWidget(btnStrike, 0, COL_STRIKE, Qt::AlignBottom);
0337 
0338     QToolButton *btnColor = createToolButton(i18n("Change Text Color"), "format-text-color", false);
0339     connect(btnColor, &QToolButton::clicked, textEdit, &SimpleRichTextEdit::changeTextColor);
0340     layout->addWidget(btnColor, 0, COL_COLOR, Qt::AlignBottom);
0341 
0342     connect(textEdit, &SimpleRichTextEdit::cursorPositionChanged, this, [=](){
0343         btnBold->setChecked(textEdit->charFormat().fontWeight() == QFont::Bold);
0344         btnItalic->setChecked(textEdit->charFormat().fontItalic());
0345         btnUnderline->setChecked(textEdit->charFormat().fontUnderline());
0346         btnStrike->setChecked(textEdit->charFormat().fontStrikeOut());
0347     });
0348 
0349     QWidget *cont = new QWidget(this);
0350     cont->setLayout(layout);
0351     return cont;
0352 }
0353 
0354 QString
0355 CurrentLineWidget::focusedText() const
0356 {
0357     for(int index = 0; index < 2; ++index) {
0358         if(m_textEdits[index]->hasFocus() && m_textEdits[index]->hasSelection())
0359             return m_textEdits[index]->selectedText();
0360     }
0361     return QString();
0362 }
0363 
0364 void
0365 CurrentLineWidget::loadConfig()
0366 {
0367     KConfigGroup group(KSharedConfig::openConfig()->group("Current Line Settings"));
0368     m_textEdits[0]->setCheckSpellingEnabled(group.readEntry<bool>("PrimaryCheckSpelling", false));
0369     m_textEdits[1]->setCheckSpellingEnabled(group.readEntry<bool>("TranslationCheckSpelling", false));
0370 }
0371 
0372 void
0373 CurrentLineWidget::saveConfig()
0374 {
0375     KConfigGroup group(KSharedConfig::openConfig()->group("Current Line Settings"));
0376     group.writeEntry("PrimaryCheckSpelling", m_textEdits[0]->checkSpellingEnabled());
0377     group.writeEntry("TranslationCheckSpelling", m_textEdits[1]->checkSpellingEnabled());
0378 }
0379 
0380 void
0381 CurrentLineWidget::setSubtitle(Subtitle *subtitle)
0382 {
0383     if(m_subtitle)
0384         disconnect(m_subtitle.constData(), &Subtitle::lineAnchorChanged, this, &CurrentLineWidget::onLineAnchorChanged);
0385 
0386     m_subtitle = subtitle;
0387 
0388     if(subtitle)
0389         connect(m_subtitle.constData(), &Subtitle::lineAnchorChanged, this, &CurrentLineWidget::onLineAnchorChanged);
0390     else
0391         setCurrentLine(nullptr);
0392 }
0393 
0394 void
0395 CurrentLineWidget::updateLabels()
0396 {
0397     if(!m_currentLine)
0398         return;
0399 
0400     m_textLabels[0]->setText(buildTextDescription(true));
0401     m_textLabels[1]->setText(buildTextDescription(false));
0402 }
0403 
0404 void
0405 CurrentLineWidget::setCurrentLine(SubtitleLine *line)
0406 {
0407     if(m_currentLine) {
0408         disconnect(m_currentLine, nullptr, this, nullptr);
0409     }
0410 
0411     m_currentLine = line;
0412 
0413     if(m_currentLine) {
0414         connect(m_currentLine, &SubtitleLine::showTimeChanged, this, &CurrentLineWidget::onLineShowTimeChanged);
0415         connect(m_currentLine, &SubtitleLine::hideTimeChanged, this, &CurrentLineWidget::onLineHideTimeChanged);
0416 
0417         RichDocument *doc = m_currentLine->primaryDoc();
0418         if(m_textEdits[0]->isReadOnly())
0419             m_textEdits[0]->setReadOnly(false);
0420         doc->setDefaultFont(QFont());
0421         m_textEdits[0]->setDocument(doc);
0422         connect(m_currentLine, &SubtitleLine::primaryTextChanged, this, &CurrentLineWidget::updateLabels);
0423 
0424         doc = m_currentLine->secondaryDoc();
0425         if(m_textEdits[1]->isReadOnly())
0426             m_textEdits[1]->setReadOnly(false);
0427         doc->setDefaultFont(QFont());
0428         m_textEdits[1]->setDocument(doc);
0429         connect(m_currentLine, &SubtitleLine::secondaryTextChanged, this, &CurrentLineWidget::updateLabels);
0430 
0431         onLineTimesChanged(m_currentLine->showTime(), m_currentLine->hideTime());
0432 
0433         if(m_subtitle)
0434             onLineAnchorChanged(m_currentLine, m_subtitle->isLineAnchored(m_currentLine));
0435 
0436         setEnabled(true);
0437     } else {
0438         QSignalBlocker s1(m_textEdits[0]), s2(m_textEdits[1]);
0439         m_textLabels[0]->setText(i18n("No current line"));
0440         m_textEdits[0]->setDocument(&m_blankDoc);
0441         m_textEdits[0]->setReadOnly(true);
0442         m_textLabels[1]->setText(i18n("No current line"));
0443         m_textEdits[1]->setDocument(&m_blankDoc);
0444         m_textEdits[1]->setReadOnly(true);
0445         onLineTimesChanged(Time(), Time());
0446 
0447         setEnabled(false);
0448     }
0449 }
0450 
0451 void
0452 CurrentLineWidget::setTranslationMode(bool enabled)
0453 {
0454     m_translationMode = enabled;
0455 
0456     QGridLayout *mainLayout = static_cast<QGridLayout *>(layout());
0457     if(m_translationMode) {
0458         mainLayout->setColumnStretch(COL_SECONDARY, 1);
0459         m_boxTranslation->show();
0460     } else {
0461         mainLayout->setColumnStretch(COL_SECONDARY, 0);
0462         m_boxTranslation->hide();
0463     }
0464 
0465     setCurrentLine(m_currentLine);
0466 }
0467 
0468 void
0469 CurrentLineWidget::onShowTimeEditChanged(int showTime)
0470 {
0471     m_currentLine->setShowTime(showTime);
0472     m_hideTimeEdit->setValue(m_currentLine->hideTime().toMillis());
0473     m_durationTimeEdit->setValue(m_hideTimeEdit->value() - showTime);
0474 }
0475 
0476 void
0477 CurrentLineWidget::onHideTimeEditChanged(int hideTime)
0478 {
0479     m_currentLine->setHideTime(hideTime);
0480     m_durationTimeEdit->setValue(hideTime - m_showTimeEdit->value());
0481 }
0482 
0483 void
0484 CurrentLineWidget::onDurationTimeEditChanged(int durationTime)
0485 {
0486     m_currentLine->setDurationTime(durationTime);
0487     m_hideTimeEdit->setValue(m_showTimeEdit->value() + durationTime);
0488 }
0489 
0490 QString
0491 CurrentLineWidget::buildTextDescription(bool primary)
0492 {
0493     static const QString blkSep = $(" <b>\u2014</b> ");
0494     static const QString colorTagBlank = $("<font>");
0495     static const QString colorTagRed = $("<font color=\"#ff0000\">");
0496     static const QString colorTagEnd = $("</font>");
0497     const QString &text = m_textEdits[primary ? 0 : 1]->toPlainText();
0498     QString res;
0499 
0500     // character count
0501     QStringList lines = text.split(QLatin1Char('\n'));
0502     res += text.length() > SCConfig::maxCharacters() ? colorTagRed : colorTagBlank;
0503     for(int i = 0; i < lines.length(); i++) {
0504         if(i >= SCConfig::maxLines())
0505             res += colorTagRed;
0506         if(i)
0507             res += $(" + ");
0508         res += QString::number(lines.at(i).length());
0509     }
0510     if(lines.length() > SCConfig::maxLines())
0511         res += colorTagEnd;
0512     if(lines.length() > 1)
0513         res += $(" = ") % QString::number(text.length() - lines.length() + 1);
0514     res += colorTagEnd % QLatin1Char(' ') % i18n("chars");
0515 
0516     res += blkSep;
0517 
0518     // characters/duration
0519     const QColor textColor = m_currentLine->durationColor(m_textLabels[0]->palette().color(QPalette::WindowText), primary);
0520     const QString colorDur = $("<font color=\"#%1\">").arg(textColor.rgb(), 6, 16, QLatin1Char(' '));
0521     const double chrDur = m_currentLine->durationTime().toMillis() / text.length();
0522     res += colorDur % QString::number(chrDur, 'f', 1) % colorTagEnd % QLatin1Char(' ') % i18n("ms/char")
0523         % blkSep
0524         % colorDur % QString::number(1000. / chrDur, 'f', 1) % colorTagEnd % QLatin1Char(' ') % i18n("chars/sec");
0525 
0526     return res;
0527 }
0528 
0529 void
0530 CurrentLineWidget::onLineAnchorChanged(const SubtitleLine *line, bool anchored)
0531 {
0532     if(m_subtitle && line == m_currentLine)
0533         m_showTimeEdit->setEnabled(!m_subtitle->hasAnchors() || anchored);
0534 }
0535 
0536 void
0537 CurrentLineWidget::onLineTimesChanged(const Time &showTime, const Time &hideTime)
0538 {
0539     QSignalBlocker s1(m_showTimeEdit), s2(m_hideTimeEdit), s3(m_durationTimeEdit);
0540     const int showMillis = showTime.toMillis();
0541     m_showTimeEdit->setValue(showMillis);
0542     m_hideTimeEdit->setMinimumTime(QTime::fromMSecsSinceStartOfDay(showMillis));
0543     m_hideTimeEdit->setValue(hideTime.toMillis());
0544     m_durationTimeEdit->setValue(m_hideTimeEdit->value() - m_showTimeEdit->value());
0545     updateLabels();
0546 }
0547 
0548 void
0549 CurrentLineWidget::onLineShowTimeChanged(const Time &showTime)
0550 {
0551     QSignalBlocker s1(m_showTimeEdit), s2(m_hideTimeEdit), s3(m_durationTimeEdit);
0552     m_showTimeEdit->setValue(showTime.toMillis());
0553     m_hideTimeEdit->setMinimumTime(QTime::fromMSecsSinceStartOfDay(showTime.toMillis()));
0554     updateLabels();
0555 }
0556 
0557 void
0558 CurrentLineWidget::onLineHideTimeChanged(const Time &hideTime)
0559 {
0560     QSignalBlocker s1(m_showTimeEdit), s2(m_hideTimeEdit), s3(m_durationTimeEdit);
0561     m_hideTimeEdit->setValue(hideTime.toMillis());
0562     m_durationTimeEdit->setValue(m_hideTimeEdit->value() - m_showTimeEdit->value());
0563     updateLabels();
0564 }
0565 
0566 void
0567 CurrentLineWidget::selectPrimaryText(int startIndex, int endIndex)
0568 {
0569     m_textEdits[1]->clearSelection();
0570     m_textEdits[0]->setSelection(startIndex, endIndex);
0571     m_textEdits[0]->setFocus();
0572 }
0573 
0574 void
0575 CurrentLineWidget::selectTranslationText(int startIndex, int endIndex)
0576 {
0577     m_textEdits[0]->clearSelection();
0578     m_textEdits[1]->setSelection(startIndex, endIndex);
0579     m_textEdits[1]->setFocus();
0580 }
0581 
0582 void
0583 CurrentLineWidget::onBreadcrumbClick(QPushButton *btn, SimpleRichTextEdit *textEdit)
0584 {
0585     const int start = btn->property("start").toInt();
0586     const int end = btn->property("end").toInt();
0587     textEdit->setSelection(start, end - 1);
0588 }
0589 
0590 void
0591 CurrentLineWidget::onConfigChanged()
0592 {
0593     m_textEdits[0]->setSpellCheckingLanguage(SCConfig::defaultLanguage());
0594     m_textEdits[1]->setSpellCheckingLanguage(SCConfig::defaultLanguage());
0595 }