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