File indexing completed on 2024-12-22 04:40:00

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 "useraction.h"
0009 #include "application.h"
0010 #include "core/subtitle.h"
0011 #include "videoplayer/videoplayer.h"
0012 #include "gui/treeview/lineswidget.h"
0013 #include "gui/currentlinewidget.h"
0014 
0015 #include <QApplication>
0016 
0017 using namespace SubtitleComposer;
0018 
0019 UserAction::UserAction(QAction *action, int enableFlags) :
0020     m_action(action),
0021     m_enableFlags(enableFlags),
0022     m_actionEnabled(action->isEnabled()),
0023     m_contextEnabled(false),
0024     m_ignoreActionEnabledSignal(false)
0025 {
0026     updateEnabledState();
0027 
0028     connect(action, &QAction::changed, this, &UserAction::onActionChanged);
0029 }
0030 
0031 void
0032 UserAction::onActionChanged()
0033 {
0034     if(!m_ignoreActionEnabledSignal) {
0035         if(m_action->isEnabled() != isEnabled()) {
0036             // qDebug() << "enabled state externally changed for" << m_action->objectName();
0037 
0038             m_actionEnabled = m_action->isEnabled();
0039             updateEnabledState();
0040         }
0041     }
0042 }
0043 
0044 int
0045 UserAction::enableFlags()
0046 {
0047     return m_enableFlags;
0048 }
0049 
0050 QAction *
0051 UserAction::action()
0052 {
0053     return m_action;
0054 }
0055 
0056 bool
0057 UserAction::isEnabled()
0058 {
0059     return m_actionEnabled && m_contextEnabled;
0060 }
0061 
0062 void
0063 UserAction::setActionEnabled(bool enabled)
0064 {
0065     if(m_actionEnabled != enabled) {
0066         m_actionEnabled = enabled;
0067         updateEnabledState();
0068     }
0069 }
0070 
0071 void
0072 UserAction::setContextFlags(int contextFlags)
0073 {
0074     bool contextEnabled = (contextFlags & m_enableFlags) == m_enableFlags;
0075     if(m_contextEnabled != contextEnabled) {
0076         m_contextEnabled = contextEnabled;
0077         updateEnabledState();
0078     }
0079 }
0080 
0081 void
0082 UserAction::updateEnabledState()
0083 {
0084     bool enabled = m_actionEnabled && m_contextEnabled;
0085 
0086     if(m_action->isEnabled() != enabled) {
0087         m_ignoreActionEnabledSignal = true;
0088 
0089         m_action->setEnabled(enabled);
0090 
0091 //      QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
0092 
0093 //      qDebug() << "setting action" << m_action->text() << (m_action->isEnabled() ? "ENABLED" : "DISABLED");
0094 
0095         m_ignoreActionEnabledSignal = false;
0096     }
0097 }
0098 
0099 /// USER ACTION MANAGER
0100 
0101 UserActionManager::UserActionManager()
0102     : m_actionSpecs(),
0103       m_subtitle(nullptr),
0104       m_linesWidget(nullptr),
0105       m_translationMode(false),
0106       m_contextFlags(UserAction::SubClosed | UserAction::SubTrClosed | UserAction::VideoClosed | UserAction::FullScreenOff | UserAction::AnchorsNone)
0107 {
0108     VideoPlayer *videoPlayer = VideoPlayer::instance();
0109     connect(videoPlayer, &VideoPlayer::fileOpened, this, &UserActionManager::onPlayerStateChanged);
0110     connect(videoPlayer, &VideoPlayer::fileClosed, this, &UserActionManager::onPlayerStateChanged);
0111     connect(videoPlayer, &VideoPlayer::playing, this, &UserActionManager::onPlayerStateChanged);
0112     connect(videoPlayer, &VideoPlayer::paused, this, &UserActionManager::onPlayerStateChanged);
0113     connect(videoPlayer, &VideoPlayer::stopped, this, &UserActionManager::onPlayerStateChanged);
0114     onPlayerStateChanged();
0115 }
0116 
0117 UserActionManager *
0118 UserActionManager::instance()
0119 {
0120     static UserActionManager *actionManager = nullptr;
0121     if(!actionManager) {
0122         actionManager = new UserActionManager();
0123         actionManager->setParent(QApplication::instance());
0124     }
0125     return actionManager;
0126 }
0127 
0128 void
0129 UserActionManager::addAction(QAction *action, int enableFlags)
0130 {
0131     UserAction *a = new UserAction(action, enableFlags);
0132     addAction(a);
0133     a->setParent(this); // UserActionManager will delete *a
0134 }
0135 
0136 void
0137 UserActionManager::addAction(UserAction *actionSpec)
0138 {
0139     m_actionSpecs.append(actionSpec);
0140 
0141     actionSpec->setContextFlags(m_contextFlags);
0142 }
0143 
0144 void
0145 UserActionManager::setSubtitle(const Subtitle *subtitle)
0146 {
0147     if(m_subtitle) {
0148         disconnect(m_subtitle.constData(), &Subtitle::linesRemoved, this, &UserActionManager::onSubtitleLinesChanged);
0149         disconnect(m_subtitle.constData(), &Subtitle::linesInserted, this, &UserActionManager::onSubtitleLinesChanged);
0150 
0151         disconnect(m_subtitle.constData(), &Subtitle::primaryDirtyStateChanged, this, &UserActionManager::onPrimaryDirtyStateChanged);
0152         disconnect(m_subtitle.constData(), &Subtitle::secondaryDirtyStateChanged, this, &UserActionManager::onSecondaryDirtyStateChanged);
0153 
0154         disconnect(m_subtitle.constData(), &Subtitle::lineAnchorChanged, this, &UserActionManager::onSubtitleAnchorsChanged);
0155     }
0156 
0157     m_subtitle = subtitle;
0158 
0159     int newContextFlags = m_contextFlags & ~UserAction::SubtitleMask;
0160 
0161     if(m_subtitle) {
0162         connect(m_subtitle.constData(), &Subtitle::linesRemoved, this, &UserActionManager::onSubtitleLinesChanged);
0163         connect(m_subtitle.constData(), &Subtitle::linesInserted, this, &UserActionManager::onSubtitleLinesChanged);
0164 
0165         connect(m_subtitle.constData(), &Subtitle::primaryDirtyStateChanged, this, &UserActionManager::onPrimaryDirtyStateChanged);
0166         connect(m_subtitle.constData(), &Subtitle::secondaryDirtyStateChanged, this, &UserActionManager::onSecondaryDirtyStateChanged);
0167 
0168         connect(m_subtitle.constData(), &Subtitle::lineAnchorChanged, this, &UserActionManager::onSubtitleAnchorsChanged);
0169 
0170         newContextFlags |= UserAction::SubOpened;
0171 
0172         if(m_subtitle->isPrimaryDirty())
0173             newContextFlags |= UserAction::SubPDirty;
0174         else
0175             newContextFlags |= UserAction::SubPClean;
0176 
0177         if(m_translationMode) {
0178             newContextFlags |= UserAction::SubTrOpened;
0179 
0180             if(m_subtitle->isSecondaryDirty())
0181                 newContextFlags |= UserAction::SubSDirty;
0182             else
0183                 newContextFlags |= UserAction::SubSClean;
0184         } else {
0185             newContextFlags |= (UserAction::SubTrClosed | UserAction::SubSClean);
0186         }
0187 
0188         if(m_subtitle->linesCount() > 0)
0189             newContextFlags |= UserAction::SubHasLine;
0190         if(m_subtitle->linesCount() > 1)
0191             newContextFlags |= UserAction::SubHasLines;
0192 
0193         if(!m_subtitle->hasAnchors()) {
0194             newContextFlags |= UserAction::AnchorsNone;
0195             newContextFlags |= UserAction::EditableShowTime;
0196         } else {
0197             newContextFlags |= UserAction::AnchorsSome;
0198             const SubtitleLine *selected = m_subtitle->line(m_linesWidget->firstSelectedIndex());
0199             if(m_subtitle->isLineAnchored(selected))
0200                 newContextFlags |= UserAction::EditableShowTime;
0201         }
0202     } else {
0203         newContextFlags |= (UserAction::SubClosed | UserAction::SubPClean | UserAction::SubTrClosed | UserAction::SubSClean);
0204     }
0205 
0206     updateActionsContext(newContextFlags);
0207 }
0208 
0209 void
0210 UserActionManager::onSubtitleLinesChanged()
0211 {
0212     int newContextFlags = m_contextFlags & ~(UserAction::SubHasLine | UserAction::SubHasLines);
0213 
0214     if(m_subtitle->linesCount() > 0)
0215         newContextFlags |= UserAction::SubHasLine;
0216     if(m_subtitle->linesCount() > 1)
0217         newContextFlags |= UserAction::SubHasLines;
0218 
0219     updateActionsContext(newContextFlags);
0220 }
0221 
0222 void
0223 UserActionManager::onPrimaryDirtyStateChanged(bool dirty)
0224 {
0225     int newContextFlags = m_contextFlags & ~(UserAction::SubPDirty | UserAction::SubPClean);
0226 
0227     if(dirty)
0228         newContextFlags |= UserAction::SubPDirty;
0229     else
0230         newContextFlags |= UserAction::SubPClean;
0231 
0232     updateActionsContext(newContextFlags);
0233 }
0234 
0235 void
0236 UserActionManager::onSecondaryDirtyStateChanged(bool dirty)
0237 {
0238     int newContextFlags = m_contextFlags & ~(UserAction::SubSDirty | UserAction::SubSClean);
0239 
0240     if(m_translationMode) {
0241         if(dirty)
0242             newContextFlags |= UserAction::SubSDirty;
0243         else
0244             newContextFlags |= UserAction::SubSClean;
0245     } else {
0246         newContextFlags |= UserAction::SubSClean;
0247     }
0248 
0249     updateActionsContext(newContextFlags);
0250 }
0251 
0252 void
0253 UserActionManager::setLinesWidget(LinesWidget *linesWidget)
0254 {
0255     if(m_linesWidget)
0256         disconnect(m_linesWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &UserActionManager::onLinesWidgetSelectionChanged);
0257 
0258     m_linesWidget = linesWidget;
0259 
0260     if(m_linesWidget) {
0261         connect(m_linesWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &UserActionManager::onLinesWidgetSelectionChanged);
0262         onLinesWidgetSelectionChanged();
0263     }
0264 }
0265 
0266 void
0267 UserActionManager::onLinesWidgetSelectionChanged()
0268 {
0269     int newContextFlags = m_contextFlags & ~(UserAction::SelectionMask | UserAction::EditableShowTime);
0270 
0271     int selectedIndex = m_linesWidget->firstSelectedIndex();
0272 
0273     if(selectedIndex >= 0)
0274         newContextFlags |= UserAction::HasSelection;
0275 
0276     if(m_subtitle) {
0277         if(!m_subtitle->hasAnchors()) {
0278             newContextFlags |= UserAction::EditableShowTime;
0279         } else {
0280             const SubtitleLine *line = m_subtitle->line(selectedIndex);
0281             if(m_subtitle->isLineAnchored(line))
0282                 newContextFlags |= UserAction::EditableShowTime;
0283         }
0284     }
0285 
0286     updateActionsContext(newContextFlags);
0287 }
0288 
0289 void
0290 UserActionManager::onPlayerStateChanged()
0291 {
0292     int newContextFlags = m_contextFlags & ~UserAction::VideoMask;
0293 
0294     const int state = VideoPlayer::instance()->state();
0295     if(state > VideoPlayer::Opening) {
0296         newContextFlags |= UserAction::VideoOpened;
0297         if(state < VideoPlayer::Playing)
0298             newContextFlags |= UserAction::VideoStopped;
0299         else
0300             newContextFlags |= UserAction::VideoPlaying;
0301     } else {
0302         newContextFlags |= UserAction::VideoClosed;
0303     }
0304 
0305     updateActionsContext(newContextFlags);
0306 }
0307 
0308 void
0309 UserActionManager::onSubtitleAnchorsChanged()
0310 {
0311     int newContextFlags = m_contextFlags & ~UserAction::AnchorsMask;
0312 
0313     if(!m_subtitle->hasAnchors()) {
0314         newContextFlags |= UserAction::AnchorsNone;
0315         newContextFlags |= UserAction::EditableShowTime;
0316     } else {
0317         newContextFlags |= UserAction::AnchorsSome;
0318         const SubtitleLine *selected = m_subtitle->line(m_linesWidget->firstSelectedIndex());
0319         if(m_subtitle->isLineAnchored(selected))
0320             newContextFlags |= UserAction::EditableShowTime;
0321     }
0322 
0323     updateActionsContext(newContextFlags);
0324 }
0325 
0326 void
0327 UserActionManager::setTranslationMode(bool translationMode)
0328 {
0329     m_translationMode = translationMode;
0330 
0331     int newContextFlags = m_contextFlags & ~(UserAction::SubTrClosed | UserAction::SubTrOpened | UserAction::SubSDirty | UserAction::SubSClean);
0332 
0333     if(m_subtitle && m_translationMode) {
0334         newContextFlags |= UserAction::SubTrOpened;
0335 
0336         if(m_subtitle->isSecondaryDirty())
0337             newContextFlags |= UserAction::SubSDirty;
0338         else
0339             newContextFlags |= UserAction::SubSClean;
0340     } else {
0341         newContextFlags |= (UserAction::SubTrClosed | UserAction::SubSClean);
0342     }
0343 
0344     updateActionsContext(newContextFlags);
0345 }
0346 
0347 void
0348 UserActionManager::setFullScreenMode(bool fullScreenMode)
0349 {
0350     int newContextFlags = m_contextFlags & ~UserAction::FullScreenMask;
0351 
0352     if(fullScreenMode)
0353         newContextFlags |= UserAction::FullScreenOn;
0354     else
0355         newContextFlags |= UserAction::FullScreenOff;
0356 
0357     updateActionsContext(newContextFlags);
0358 }
0359 
0360 void
0361 UserActionManager::updateActionsContext(int contextFlags)
0362 {
0363 //  if ( (m_contextFlags & UserAction::SubHasLine) != (contextFlags & UserAction::SubHasLine)  )
0364 //      qDebug() << "has line:" << ((contextFlags & UserAction::SubHasLine) != 0);
0365 //  if ( (m_contextFlags & UserAction::SubHasLines) != (contextFlags & UserAction::SubHasLines)  )
0366 //      qDebug() << "has lines:" << ((contextFlags & UserAction::SubHasLines) != 0);
0367 //  if ( (m_contextFlags & UserAction::HasSelection) != (contextFlags & UserAction::HasSelection)  )
0368 //      qDebug() << "has selection:" << ((contextFlags & UserAction::HasSelection) != 0);
0369 
0370     if(m_contextFlags != contextFlags) {
0371         m_contextFlags = contextFlags;
0372         for(QList<UserAction *>::ConstIterator it = m_actionSpecs.constBegin(), end = m_actionSpecs.constEnd(); it != end; ++it)
0373             (*it)->setContextFlags(m_contextFlags);
0374     }
0375 }
0376 
0377