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),
|
||||
active_tool_(nullptr),
|
||||
use_audio_time_units_(false),
|
||||
subtitle_show_command_(nullptr)
|
||||
subtitle_show_command_(nullptr),
|
||||
subtitle_tentative_track_(nullptr)
|
||||
{
|
||||
QVBoxLayout* vert_layout = new QVBoxLayout(this);
|
||||
vert_layout->setSpacing(0);
|
||||
@@ -91,13 +92,13 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
|
||||
vert_layout->addWidget(view_splitter_);
|
||||
|
||||
// Video view
|
||||
views_.append(new TimelineAndTrackView(Qt::AlignBottom));
|
||||
views_.append(AddTimelineAndTrackView(Qt::AlignBottom));
|
||||
|
||||
// Audio view
|
||||
views_.append(new TimelineAndTrackView(Qt::AlignTop));
|
||||
views_.append(AddTimelineAndTrackView(Qt::AlignTop));
|
||||
|
||||
// Subtitle view
|
||||
views_.append(new TimelineAndTrackView(Qt::AlignTop));
|
||||
views_.append(AddTimelineAndTrackView(Qt::AlignTop));
|
||||
|
||||
// Create tools
|
||||
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)
|
||||
{
|
||||
for (int i=0;i<Track::kCount;i++) {
|
||||
@@ -1116,32 +1155,9 @@ void TimelineWidget::AddableObjectChanged()
|
||||
{
|
||||
// Special cast for subtitle adding - ensure section is visible
|
||||
if (Core::instance()->tool() == Tool::kAdd && Core::instance()->GetSelectedAddableObject() == Tool::kAddableSubtitle) {
|
||||
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) {
|
||||
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;
|
||||
AddTentativeSubtitleTrack();
|
||||
} else {
|
||||
ClearTentativeSubtitleTrack();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1210,6 +1226,16 @@ void TimelineWidget::RenameSelectedBlocks()
|
||||
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)
|
||||
{
|
||||
ghost_items_.append(ghost);
|
||||
@@ -1641,6 +1667,13 @@ bool TimelineWidget::PasteInternal(bool insert)
|
||||
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
|
||||
{
|
||||
return view_splitter_->saveState();
|
||||
|
||||
@@ -107,6 +107,10 @@ public:
|
||||
|
||||
void DisableRecordingOverlay();
|
||||
|
||||
void AddTentativeSubtitleTrack();
|
||||
|
||||
void ClearTentativeSubtitleTrack();
|
||||
|
||||
/**
|
||||
* @brief Timelines should always be connected to sequences
|
||||
*/
|
||||
@@ -230,6 +234,7 @@ public:
|
||||
|
||||
// Set to null
|
||||
subtitle_show_command_ = nullptr;
|
||||
subtitle_tentative_track_ = nullptr;
|
||||
|
||||
// Return command
|
||||
return c;
|
||||
@@ -298,6 +303,8 @@ private:
|
||||
|
||||
bool PasteInternal(bool insert);
|
||||
|
||||
TimelineAndTrackView *AddTimelineAndTrackView(Qt::Alignment alignment);
|
||||
|
||||
QPoint drag_origin_;
|
||||
|
||||
QRubberBand rubberband_;
|
||||
@@ -331,6 +338,7 @@ private:
|
||||
QSplitter* view_splitter_;
|
||||
|
||||
MultiUndoCommand *subtitle_show_command_;
|
||||
Track *subtitle_tentative_track_;
|
||||
|
||||
QTimer *signal_block_change_timer_;
|
||||
|
||||
@@ -420,6 +428,8 @@ private slots:
|
||||
|
||||
void RenameSelectedBlocks();
|
||||
|
||||
void TrackAboutToBeDeleted(Track *track);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -121,9 +121,13 @@ void TrackView::TrackHeightChanged(int index, int height)
|
||||
|
||||
void TrackView::InsertTrack(Track *track)
|
||||
{
|
||||
TrackViewItem *tvi = new TrackViewItem(track);
|
||||
|
||||
connect(tvi, &TrackViewItem::AboutToDeleteTrack, this, &TrackView::AboutToDeleteTrack);
|
||||
|
||||
splitter_->Insert(track->Index(),
|
||||
track->GetTrackHeightInPixels(),
|
||||
new TrackViewItem(track));
|
||||
tvi);
|
||||
}
|
||||
|
||||
void TrackView::RemoveTrack(Track *track)
|
||||
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
void ConnectTrackList(TrackList* list);
|
||||
void DisconnectTrackList();
|
||||
|
||||
signals:
|
||||
void AboutToDeleteTrack(Track *track);
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ void TrackViewItem::ShowContextMenu(const QPoint &p)
|
||||
|
||||
void TrackViewItem::DeleteTrack()
|
||||
{
|
||||
emit AboutToDeleteTrack(track_);
|
||||
Core::instance()->undo_stack()->push(new TimelineRemoveTrackCommand(track_));
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@ public:
|
||||
TrackViewItem(Track* track,
|
||||
QWidget* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void AboutToDeleteTrack(Track *track);
|
||||
|
||||
private:
|
||||
QPushButton* CreateMSLButton(const QColor &checked_color) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user