timeline: handle users deleting tentative subtitle track
Fixes potential crash if users try to do this
This commit is contained in:
@@ -66,7 +66,8 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
|
|||||||
rubberband_(QRubberBand::Rectangle, this),
|
rubberband_(QRubberBand::Rectangle, this),
|
||||||
active_tool_(nullptr),
|
active_tool_(nullptr),
|
||||||
use_audio_time_units_(false),
|
use_audio_time_units_(false),
|
||||||
subtitle_show_command_(nullptr)
|
subtitle_show_command_(nullptr),
|
||||||
|
subtitle_tentative_track_(nullptr)
|
||||||
{
|
{
|
||||||
QVBoxLayout* vert_layout = new QVBoxLayout(this);
|
QVBoxLayout* vert_layout = new QVBoxLayout(this);
|
||||||
vert_layout->setSpacing(0);
|
vert_layout->setSpacing(0);
|
||||||
@@ -91,13 +92,13 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
|
|||||||
vert_layout->addWidget(view_splitter_);
|
vert_layout->addWidget(view_splitter_);
|
||||||
|
|
||||||
// Video view
|
// Video view
|
||||||
views_.append(new TimelineAndTrackView(Qt::AlignBottom));
|
views_.append(AddTimelineAndTrackView(Qt::AlignBottom));
|
||||||
|
|
||||||
// Audio view
|
// Audio view
|
||||||
views_.append(new TimelineAndTrackView(Qt::AlignTop));
|
views_.append(AddTimelineAndTrackView(Qt::AlignTop));
|
||||||
|
|
||||||
// Subtitle view
|
// Subtitle view
|
||||||
views_.append(new TimelineAndTrackView(Qt::AlignTop));
|
views_.append(AddTimelineAndTrackView(Qt::AlignTop));
|
||||||
|
|
||||||
// Create tools
|
// Create tools
|
||||||
tools_.resize(olive::Tool::kCount);
|
tools_.resize(olive::Tool::kCount);
|
||||||
@@ -780,6 +781,44 @@ void TimelineWidget::DisableRecordingOverlay()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimelineWidget::AddTentativeSubtitleTrack()
|
||||||
|
{
|
||||||
|
if (!subtitle_show_command_) {
|
||||||
|
// Determine if we need to do anything
|
||||||
|
QList<int> sz = view_splitter_->sizes();
|
||||||
|
bool should_adjust_splitter = (sz[Track::kSubtitle] == 0);
|
||||||
|
bool should_add_sub_track = (sequence() && sequence()->track_list(Track::kSubtitle)->GetTrackCount() == 0);
|
||||||
|
|
||||||
|
if (should_adjust_splitter || should_add_sub_track) {
|
||||||
|
// Create command
|
||||||
|
subtitle_show_command_ = new MultiUndoCommand();
|
||||||
|
|
||||||
|
if (should_adjust_splitter) {
|
||||||
|
sz[Track::kSubtitle] = height() / Track::kCount;
|
||||||
|
subtitle_show_command_->add_child(new SetSplitterSizesCommand(view_splitter_, sz));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_add_sub_track) {
|
||||||
|
TimelineAddTrackCommand *track_add_cmd = new TimelineAddTrackCommand(sequence()->track_list(Track::kSubtitle));
|
||||||
|
subtitle_tentative_track_ = track_add_cmd->track();
|
||||||
|
subtitle_show_command_->add_child(track_add_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
subtitle_show_command_->redo_now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimelineWidget::ClearTentativeSubtitleTrack()
|
||||||
|
{
|
||||||
|
if (subtitle_show_command_) {
|
||||||
|
subtitle_show_command_->undo_now();
|
||||||
|
delete subtitle_show_command_;
|
||||||
|
subtitle_show_command_ = nullptr;
|
||||||
|
subtitle_tentative_track_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational &insert_length, MultiUndoCommand *command)
|
void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational &insert_length, MultiUndoCommand *command)
|
||||||
{
|
{
|
||||||
for (int i=0;i<Track::kCount;i++) {
|
for (int i=0;i<Track::kCount;i++) {
|
||||||
@@ -1116,32 +1155,9 @@ void TimelineWidget::AddableObjectChanged()
|
|||||||
{
|
{
|
||||||
// Special cast for subtitle adding - ensure section is visible
|
// Special cast for subtitle adding - ensure section is visible
|
||||||
if (Core::instance()->tool() == Tool::kAdd && Core::instance()->GetSelectedAddableObject() == Tool::kAddableSubtitle) {
|
if (Core::instance()->tool() == Tool::kAdd && Core::instance()->GetSelectedAddableObject() == Tool::kAddableSubtitle) {
|
||||||
if (!subtitle_show_command_) {
|
AddTentativeSubtitleTrack();
|
||||||
// Determine if we need to do anything
|
} else {
|
||||||
QList<int> sz = view_splitter_->sizes();
|
ClearTentativeSubtitleTrack();
|
||||||
bool should_adjust_splitter = (sz[Track::kSubtitle] == 0);
|
|
||||||
bool should_add_sub_track = (sequence() && sequence()->track_list(Track::kSubtitle)->GetTrackCount() == 0);
|
|
||||||
|
|
||||||
if (should_adjust_splitter || should_add_sub_track) {
|
|
||||||
// Create command
|
|
||||||
subtitle_show_command_ = new MultiUndoCommand();
|
|
||||||
|
|
||||||
if (should_adjust_splitter) {
|
|
||||||
sz[Track::kSubtitle] = height() / Track::kCount;
|
|
||||||
subtitle_show_command_->add_child(new SetSplitterSizesCommand(view_splitter_, sz));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (should_add_sub_track) {
|
|
||||||
subtitle_show_command_->add_child(new TimelineAddTrackCommand(sequence()->track_list(Track::kSubtitle)));
|
|
||||||
}
|
|
||||||
|
|
||||||
subtitle_show_command_->redo_now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (subtitle_show_command_) {
|
|
||||||
subtitle_show_command_->undo_now();
|
|
||||||
delete subtitle_show_command_;
|
|
||||||
subtitle_show_command_ = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1210,6 +1226,16 @@ void TimelineWidget::RenameSelectedBlocks()
|
|||||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimelineWidget::TrackAboutToBeDeleted(Track *track)
|
||||||
|
{
|
||||||
|
if (track == subtitle_tentative_track_) {
|
||||||
|
// User is deleting the tentative subtitle track. Technically they shouldn't do this, but they
|
||||||
|
// might if they misinterpret it as permanent. If so, we handle it cleanly by pushing our
|
||||||
|
// command as if the action really were permanent.
|
||||||
|
Core::instance()->undo_stack()->push(TakeSubtitleSectionCommand());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost)
|
void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost)
|
||||||
{
|
{
|
||||||
ghost_items_.append(ghost);
|
ghost_items_.append(ghost);
|
||||||
@@ -1641,6 +1667,13 @@ bool TimelineWidget::PasteInternal(bool insert)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimelineAndTrackView *TimelineWidget::AddTimelineAndTrackView(Qt::Alignment alignment)
|
||||||
|
{
|
||||||
|
TimelineAndTrackView *v = new TimelineAndTrackView(alignment);
|
||||||
|
connect(v->track_view(), &TrackView::AboutToDeleteTrack, this, &TimelineWidget::TrackAboutToBeDeleted);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray TimelineWidget::SaveSplitterState() const
|
QByteArray TimelineWidget::SaveSplitterState() const
|
||||||
{
|
{
|
||||||
return view_splitter_->saveState();
|
return view_splitter_->saveState();
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ public:
|
|||||||
|
|
||||||
void DisableRecordingOverlay();
|
void DisableRecordingOverlay();
|
||||||
|
|
||||||
|
void AddTentativeSubtitleTrack();
|
||||||
|
|
||||||
|
void ClearTentativeSubtitleTrack();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Timelines should always be connected to sequences
|
* @brief Timelines should always be connected to sequences
|
||||||
*/
|
*/
|
||||||
@@ -230,6 +234,7 @@ public:
|
|||||||
|
|
||||||
// Set to null
|
// Set to null
|
||||||
subtitle_show_command_ = nullptr;
|
subtitle_show_command_ = nullptr;
|
||||||
|
subtitle_tentative_track_ = nullptr;
|
||||||
|
|
||||||
// Return command
|
// Return command
|
||||||
return c;
|
return c;
|
||||||
@@ -298,6 +303,8 @@ private:
|
|||||||
|
|
||||||
bool PasteInternal(bool insert);
|
bool PasteInternal(bool insert);
|
||||||
|
|
||||||
|
TimelineAndTrackView *AddTimelineAndTrackView(Qt::Alignment alignment);
|
||||||
|
|
||||||
QPoint drag_origin_;
|
QPoint drag_origin_;
|
||||||
|
|
||||||
QRubberBand rubberband_;
|
QRubberBand rubberband_;
|
||||||
@@ -331,6 +338,7 @@ private:
|
|||||||
QSplitter* view_splitter_;
|
QSplitter* view_splitter_;
|
||||||
|
|
||||||
MultiUndoCommand *subtitle_show_command_;
|
MultiUndoCommand *subtitle_show_command_;
|
||||||
|
Track *subtitle_tentative_track_;
|
||||||
|
|
||||||
QTimer *signal_block_change_timer_;
|
QTimer *signal_block_change_timer_;
|
||||||
|
|
||||||
@@ -420,6 +428,8 @@ private slots:
|
|||||||
|
|
||||||
void RenameSelectedBlocks();
|
void RenameSelectedBlocks();
|
||||||
|
|
||||||
|
void TrackAboutToBeDeleted(Track *track);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,9 +121,13 @@ void TrackView::TrackHeightChanged(int index, int height)
|
|||||||
|
|
||||||
void TrackView::InsertTrack(Track *track)
|
void TrackView::InsertTrack(Track *track)
|
||||||
{
|
{
|
||||||
|
TrackViewItem *tvi = new TrackViewItem(track);
|
||||||
|
|
||||||
|
connect(tvi, &TrackViewItem::AboutToDeleteTrack, this, &TrackView::AboutToDeleteTrack);
|
||||||
|
|
||||||
splitter_->Insert(track->Index(),
|
splitter_->Insert(track->Index(),
|
||||||
track->GetTrackHeightInPixels(),
|
track->GetTrackHeightInPixels(),
|
||||||
new TrackViewItem(track));
|
tvi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackView::RemoveTrack(Track *track)
|
void TrackView::RemoveTrack(Track *track)
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ public:
|
|||||||
void ConnectTrackList(TrackList* list);
|
void ConnectTrackList(TrackList* list);
|
||||||
void DisconnectTrackList();
|
void DisconnectTrackList();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void AboutToDeleteTrack(Track *track);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void resizeEvent(QResizeEvent *e) override;
|
virtual void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ void TrackViewItem::ShowContextMenu(const QPoint &p)
|
|||||||
|
|
||||||
void TrackViewItem::DeleteTrack()
|
void TrackViewItem::DeleteTrack()
|
||||||
{
|
{
|
||||||
|
emit AboutToDeleteTrack(track_);
|
||||||
Core::instance()->undo_stack()->push(new TimelineRemoveTrackCommand(track_));
|
Core::instance()->undo_stack()->push(new TimelineRemoveTrackCommand(track_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ public:
|
|||||||
TrackViewItem(Track* track,
|
TrackViewItem(Track* track,
|
||||||
QWidget* parent = nullptr);
|
QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void AboutToDeleteTrack(Track *track);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPushButton* CreateMSLButton(const QColor &checked_color) const;
|
QPushButton* CreateMSLButton(const QColor &checked_color) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user