Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Kdenlive
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
252
Issues
252
List
Boards
Labels
Service Desk
Milestones
Merge Requests
16
Merge Requests
16
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Multimedia
Kdenlive
Commits
0ca212ca
Commit
0ca212ca
authored
Jun 07, 2019
by
Jean-Baptiste Mardelle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Major speedup in clip selection that caused several seconds lag on large projects
parent
fcbb7b7f
Pipeline
#4112
passed with stage
in 28 minutes and 16 seconds
Changes
13
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
155 additions
and
65 deletions
+155
-65
src/timeline2/model/clipmodel.cpp
src/timeline2/model/clipmodel.cpp
+18
-1
src/timeline2/model/clipmodel.hpp
src/timeline2/model/clipmodel.hpp
+4
-0
src/timeline2/model/compositionmodel.cpp
src/timeline2/model/compositionmodel.cpp
+16
-0
src/timeline2/model/compositionmodel.hpp
src/timeline2/model/compositionmodel.hpp
+1
-0
src/timeline2/model/groupsmodel.cpp
src/timeline2/model/groupsmodel.cpp
+6
-1
src/timeline2/model/moveableItem.hpp
src/timeline2/model/moveableItem.hpp
+5
-0
src/timeline2/model/moveableItem.ipp
src/timeline2/model/moveableItem.ipp
+0
-1
src/timeline2/model/timelinefunctions.cpp
src/timeline2/model/timelinefunctions.cpp
+2
-2
src/timeline2/model/timelineitemmodel.cpp
src/timeline2/model/timelineitemmodel.cpp
+5
-0
src/timeline2/model/timelinemodel.cpp
src/timeline2/model/timelinemodel.cpp
+91
-58
src/timeline2/model/timelinemodel.hpp
src/timeline2/model/timelinemodel.hpp
+4
-0
src/timeline2/view/qml/Track.qml
src/timeline2/view/qml/Track.qml
+1
-1
src/timeline2/view/timelinecontroller.cpp
src/timeline2/view/timelinecontroller.cpp
+2
-1
No files found.
src/timeline2/model/clipmodel.cpp
View file @
0ca212ca
...
...
@@ -548,8 +548,9 @@ void ClipModel::setCurrentTrackId(int tid, bool finalMove)
}
}
if
(
finalMove
&&
tid
!=
-
1
)
{
if
(
finalMove
&&
tid
!=
-
1
&&
m_lastTrackId
!=
m_currentTrackId
)
{
refreshProducerFromBin
(
m_currentState
);
m_lastTrackId
=
m_currentTrackId
;
}
}
...
...
@@ -733,6 +734,9 @@ void ClipModel::setOffset(int offset)
void
ClipModel
::
setGrab
(
bool
grab
)
{
QWriteLocker
locker
(
&
m_lock
);
if
(
grab
==
m_grabbed
)
{
return
;
}
m_grabbed
=
grab
;
if
(
auto
ptr
=
m_parent
.
lock
())
{
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
m_id
);
...
...
@@ -740,6 +744,19 @@ void ClipModel::setGrab(bool grab)
}
}
void
ClipModel
::
setSelected
(
bool
sel
)
{
QWriteLocker
locker
(
&
m_lock
);
if
(
sel
==
selected
)
{
return
;
}
selected
=
sel
;
if
(
auto
ptr
=
m_parent
.
lock
())
{
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
m_id
);
ptr
->
dataChanged
(
ix
,
ix
,
{
TimelineModel
::
SelectedRole
});
}
}
void
ClipModel
::
clearOffset
()
{
if
(
m_positionOffset
!=
0
)
{
...
...
src/timeline2/model/clipmodel.hpp
View file @
0ca212ca
...
...
@@ -100,6 +100,7 @@ public:
int
getFakePosition
()
const
;
void
setFakePosition
(
int
fid
);
void
setGrab
(
bool
grab
)
override
;
void
setSelected
(
bool
sel
)
override
;
/* @brief Returns an XML representation of the clip with its effects */
QDomElement
toXml
(
QDomDocument
&
document
);
...
...
@@ -233,6 +234,9 @@ protected:
int
m_positionOffset
;
int
m_subPlaylistIndex
;
// Tracks have two sub playlists to enable same track transitions, we store in which one this clip is.
// Remember last set track, so that we don't unnecessarily refresh the producer when deleting and re-adding a clip on same track
int
m_lastTrackId
=
-
1
;
};
#endif
src/timeline2/model/compositionmodel.cpp
View file @
0ca212ca
...
...
@@ -253,6 +253,9 @@ void CompositionModel::setInOut(int in, int out)
void
CompositionModel
::
setGrab
(
bool
grab
)
{
QWriteLocker
locker
(
&
m_lock
);
if
(
grab
==
m_grabbed
)
{
return
;
}
m_grabbed
=
grab
;
if
(
auto
ptr
=
m_parent
.
lock
())
{
QModelIndex
ix
=
ptr
->
makeCompositionIndexFromID
(
m_id
);
...
...
@@ -260,6 +263,19 @@ void CompositionModel::setGrab(bool grab)
}
}
void
CompositionModel
::
setSelected
(
bool
sel
)
{
QWriteLocker
locker
(
&
m_lock
);
if
(
sel
==
selected
)
{
return
;
}
selected
=
sel
;
if
(
auto
ptr
=
m_parent
.
lock
())
{
QModelIndex
ix
=
ptr
->
makeCompositionIndexFromID
(
m_id
);
ptr
->
dataChanged
(
ix
,
ix
,
{
TimelineModel
::
SelectedRole
});
}
}
void
CompositionModel
::
setCurrentTrackId
(
int
tid
,
bool
finalMove
)
{
Q_UNUSED
(
finalMove
);
...
...
src/timeline2/model/compositionmodel.hpp
View file @
0ca212ca
...
...
@@ -96,6 +96,7 @@ public:
/* @brief Returns an XML representation of the clip with its effects */
QDomElement
toXml
(
QDomDocument
&
document
);
void
setGrab
(
bool
grab
)
override
;
void
setSelected
(
bool
sel
)
override
;
protected:
Mlt
::
Transition
*
service
()
const
override
;
...
...
src/timeline2/model/groupsmodel.cpp
View file @
0ca212ca
...
...
@@ -85,7 +85,12 @@ Fun GroupsModel::groupItems_lambda(int gid, const std::unordered_set<int> &ids,
auto
ptr
=
m_parent
.
lock
();
if
(
!
ptr
)
Q_ASSERT
(
false
);
for
(
int
id
:
roots
)
{
setGroup
(
getRootId
(
id
),
gid
,
type
!=
GroupType
::
Selection
);
if
(
type
!=
GroupType
::
Selection
)
{
setGroup
(
getRootId
(
id
),
gid
,
true
);
}
else
{
setGroup
(
getRootId
(
id
),
gid
,
false
);
ptr
->
setSelected
(
id
,
true
);
}
}
}
return
true
;
...
...
src/timeline2/model/moveableItem.hpp
View file @
0ca212ca
...
...
@@ -81,6 +81,11 @@ public:
/* Set if the item is in grab state */
bool
isGrabbed
()
const
;
/* True if item is selected in timeline */
bool
selected
{
false
};
/* Set selected status */
virtual
void
setSelected
(
bool
sel
)
=
0
;
protected:
/* @brief Returns a pointer to the service. It may be used but do NOT store it*/
...
...
src/timeline2/model/moveableItem.ipp
View file @
0ca212ca
...
...
@@ -99,4 +99,3 @@ template <typename Service> bool MoveableItem<Service>::isGrabbed() const
READ_LOCK();
return m_grabbed;
}
src/timeline2/model/timelinefunctions.cpp
View file @
0ca212ca
...
...
@@ -246,7 +246,8 @@ bool TimelineFunctions::requestSpacerEndOperation(const std::shared_ptr<Timeline
// Start undoable command
std
::
function
<
bool
(
void
)
>
undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo
=
[]()
{
return
true
;
};
int
res
=
timeline
->
requestClipsGroup
(
clips
,
undo
,
redo
,
GroupType
::
Selection
);
//int res = timeline->requestClipsGroup(clips, undo, redo, GroupType::Selection);
int
res
=
timeline
->
m_groups
->
getRootId
(
itemId
);
bool
final
=
false
;
if
(
res
>
-
1
||
clips
.
size
()
==
1
)
{
if
(
clips
.
size
()
>
1
)
{
...
...
@@ -392,7 +393,6 @@ bool TimelineFunctions::removeSpace(const std::shared_ptr<TimelineItemModel> &ti
}
++
it
;
}
bool
result
=
false
;
if
(
!
clips
.
empty
())
{
int
clipId
=
*
clips
.
begin
();
...
...
src/timeline2/model/timelineitemmodel.cpp
View file @
0ca212ca
...
...
@@ -231,6 +231,7 @@ QHash<int, QByteArray> TimelineItemModel::roleNames() const
roles
[
EffectNamesRole
]
=
"effectNames"
;
roles
[
EffectsEnabledRole
]
=
"isStackEnabled"
;
roles
[
GrabbedRole
]
=
"isGrabbed"
;
roles
[
SelectedRole
]
=
"selected"
;
return
roles
;
}
...
...
@@ -339,6 +340,8 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
return
clip
->
getSpeed
();
case
GrabbedRole
:
return
clip
->
isGrabbed
();
case
SelectedRole
:
return
clip
->
selected
;
default:
break
;
}
...
...
@@ -428,6 +431,8 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
}
case
GrabbedRole
:
return
compo
->
isGrabbed
();
case
SelectedRole
:
return
compo
->
selected
;
default:
break
;
}
...
...
src/timeline2/model/timelinemodel.cpp
View file @
0ca212ca
...
...
@@ -1378,6 +1378,9 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
// Check if there is a track move
bool
updatePositionOnly
=
false
;
// Second step, reinsert clips at correct positions
int
audio_delta
,
video_delta
;
audio_delta
=
video_delta
=
delta_track
;
if
(
delta_track
==
0
&&
updateView
)
{
updateView
=
false
;
allowViewRefresh
=
false
;
...
...
@@ -1400,69 +1403,88 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
};
}
// First, remove clips
std
::
unordered_map
<
int
,
int
>
old_track_ids
,
old_position
,
old_forced_track
;
for
(
int
item
:
sorted_clips
)
{
int
old_trackId
=
getItemTrackId
(
item
);
old_track_ids
[
item
]
=
old_trackId
;
if
(
old_trackId
!=
-
1
)
{
bool
updateThisView
=
allowViewRefresh
;
if
(
isClip
(
item
))
{
ok
=
ok
&&
getTrackById
(
old_trackId
)
->
requestClipDeletion
(
item
,
updateThisView
,
finalMove
,
local_undo
,
local_redo
,
true
);
old_position
[
item
]
=
m_allClips
[
item
]
->
getPosition
();
}
else
{
// ok = ok && getTrackById(old_trackId)->requestCompositionDeletion(item, updateThisView, finalMove, local_undo, local_redo);
old_position
[
item
]
=
m_allCompositions
[
item
]
->
getPosition
();
old_forced_track
[
item
]
=
m_allCompositions
[
item
]
->
getForcedTrack
();
}
if
(
!
ok
)
{
bool
undone
=
local_undo
();
Q_ASSERT
(
undone
);
return
false
;
// First, remove clips
if
(
delta_track
!=
0
)
{
// We delete our clips only if changing track
for
(
int
item
:
sorted_clips
)
{
int
old_trackId
=
getItemTrackId
(
item
);
old_track_ids
[
item
]
=
old_trackId
;
if
(
old_trackId
!=
-
1
)
{
bool
updateThisView
=
allowViewRefresh
;
if
(
isClip
(
item
))
{
ok
=
ok
&&
getTrackById
(
old_trackId
)
->
requestClipDeletion
(
item
,
updateThisView
,
finalMove
,
local_undo
,
local_redo
,
true
);
old_position
[
item
]
=
m_allClips
[
item
]
->
getPosition
();
}
else
{
// ok = ok && getTrackById(old_trackId)->requestCompositionDeletion(item, updateThisView, finalMove, local_undo, local_redo);
old_position
[
item
]
=
m_allCompositions
[
item
]
->
getPosition
();
old_forced_track
[
item
]
=
m_allCompositions
[
item
]
->
getForcedTrack
();
}
if
(
!
ok
)
{
bool
undone
=
local_undo
();
Q_ASSERT
(
undone
);
return
false
;
}
}
}
}
// Second step, reinsert clips at correct positions
int
audio_delta
,
video_delta
;
audio_delta
=
video_delta
=
delta_track
;
if
(
getTrackById
(
old_track_ids
[
itemId
])
->
isAudioTrack
())
{
// Master clip is audio, so reverse delta for video clips
video_delta
=
-
delta_track
;
}
else
{
audio_delta
=
-
delta_track
;
if
(
getTrackById
(
old_track_ids
[
itemId
])
->
isAudioTrack
())
{
// Master clip is audio, so reverse delta for video clips
video_delta
=
-
delta_track
;
}
else
{
audio_delta
=
-
delta_track
;
}
}
// We need to insert depending on the move direction to avoid confusing the view
// std::reverse(std::begin(sorted_clips), std::end(sorted_clips));
for
(
int
item
:
sorted_clips
)
{
int
current_track_id
=
old_track_ids
[
item
];
int
current_track_position
=
getTrackPosition
(
current_track_id
);
int
d
=
getTrackById
(
current_track_id
)
->
isAudioTrack
()
?
audio_delta
:
video_delta
;
int
target_track_position
=
current_track_position
+
d
;
bool
updateThisView
=
allowViewRefresh
;
if
(
target_track_position
>=
0
&&
target_track_position
<
getTracksCount
())
{
auto
it
=
m_allTracks
.
cbegin
();
std
::
advance
(
it
,
target_track_position
);
int
target_track
=
(
*
it
)
->
getId
();
int
target_position
=
old_position
[
item
]
+
delta_pos
;
bool
updateThisView
=
allowViewRefresh
;
if
(
delta_track
==
0
)
{
// Special case, we are moving on same track, avoid too many calculations
for
(
int
item
:
sorted_clips
)
{
int
current_track_id
=
getItemTrackId
(
item
);
int
target_position
=
getItemPosition
(
item
)
+
delta_pos
;
if
(
isClip
(
item
))
{
ok
=
ok
&&
requestClipMove
(
item
,
target_track
,
target_position
,
updateThisView
,
finalMove
,
finalMove
,
local_undo
,
local_redo
,
true
);
ok
=
ok
&&
requestClipMove
(
item
,
current_track_id
,
target_position
,
updateThisView
,
finalMove
,
finalMove
,
local_undo
,
local_redo
,
true
);
}
else
{
ok
=
ok
&&
requestCompositionMove
(
item
,
target_track
,
old_forced_track
[
item
]
,
target_position
,
updateThisView
,
finalMove
,
local_undo
,
local_redo
);
requestCompositionMove
(
item
,
current_track_id
,
m_allCompositions
[
item
]
->
getForcedTrack
()
,
target_position
,
updateThisView
,
finalMove
,
local_undo
,
local_redo
);
}
}
else
{
qDebug
()
<<
"// ABORTING; MOVE TRIED ON TRACK: "
<<
target_track_position
<<
"..
\n
..
\n
.."
;
ok
=
false
;
}
if
(
!
ok
)
{
bool
undone
=
local_undo
();
Q_ASSERT
(
undone
);
return
false
;
}
}
else
{
// Track changed
for
(
int
item
:
sorted_clips
)
{
int
current_track_id
=
old_track_ids
[
item
];
int
current_track_position
=
getTrackPosition
(
current_track_id
);
int
d
=
getTrackById
(
current_track_id
)
->
isAudioTrack
()
?
audio_delta
:
video_delta
;
int
target_track_position
=
current_track_position
+
d
;
if
(
target_track_position
>=
0
&&
target_track_position
<
getTracksCount
())
{
auto
it
=
m_allTracks
.
cbegin
();
std
::
advance
(
it
,
target_track_position
);
int
target_track
=
(
*
it
)
->
getId
();
int
target_position
=
old_position
[
item
]
+
delta_pos
;
if
(
isClip
(
item
))
{
ok
=
ok
&&
requestClipMove
(
item
,
target_track
,
target_position
,
updateThisView
,
finalMove
,
finalMove
,
local_undo
,
local_redo
,
true
);
}
else
{
ok
=
ok
&&
requestCompositionMove
(
item
,
target_track
,
old_forced_track
[
item
],
target_position
,
updateThisView
,
finalMove
,
local_undo
,
local_redo
);
}
}
else
{
qDebug
()
<<
"// ABORTING; MOVE TRIED ON TRACK: "
<<
target_track_position
<<
"..
\n
..
\n
.."
;
ok
=
false
;
}
if
(
!
ok
)
{
bool
undone
=
local_undo
();
Q_ASSERT
(
undone
);
return
false
;
}
}
}
if
(
updatePositionOnly
)
{
update_model
();
...
...
@@ -3133,13 +3155,11 @@ bool TimelineModel::requestClearSelection(bool onDeletion)
}
}
else
if
(
isClip
(
id
))
{
m_allClips
[
id
]
->
clearOffset
();
if
(
m_allClips
[
id
]
->
isGrabbed
())
{
m_allClips
[
id
]
->
setGrab
(
false
);
}
m_allClips
[
id
]
->
setGrab
(
false
);
m_allClips
[
id
]
->
setSelected
(
false
);
}
else
if
(
isComposition
(
id
))
{
if
(
m_allCompositions
[
id
]
->
isGrabbed
())
{
m_allCompositions
[
id
]
->
setGrab
(
false
);
}
m_allCompositions
[
id
]
->
setGrab
(
false
);
m_allCompositions
[
id
]
->
setSelected
(
false
);
}
if
(
m_groups
->
getType
(
m_currentSelection
)
==
GroupType
::
Selection
)
{
m_groups
->
destructGroupItem
(
m_currentSelection
);
...
...
@@ -3147,13 +3167,11 @@ bool TimelineModel::requestClearSelection(bool onDeletion)
}
}
else
{
if
(
isClip
(
m_currentSelection
))
{
if
(
m_allClips
[
m_currentSelection
]
->
isGrabbed
())
{
m_allClips
[
m_currentSelection
]
->
setGrab
(
false
);
}
m_allClips
[
m_currentSelection
]
->
setGrab
(
false
);
m_allClips
[
m_currentSelection
]
->
setSelected
(
false
);
}
else
if
(
isComposition
(
m_currentSelection
))
{
if
(
m_allCompositions
[
m_currentSelection
]
->
isGrabbed
())
{
m_allCompositions
[
m_currentSelection
]
->
setGrab
(
false
);
}
m_allCompositions
[
m_currentSelection
]
->
setGrab
(
false
);
m_allCompositions
[
m_currentSelection
]
->
setSelected
(
false
);
}
Q_ASSERT
(
onDeletion
||
isClip
(
m_currentSelection
)
||
isComposition
(
m_currentSelection
));
}
...
...
@@ -3234,6 +3252,7 @@ bool TimelineModel::requestSetSelection(const std::unordered_set<int> &ids)
m_currentSelection
=
-
1
;
}
else
if
(
roots
.
size
()
==
1
)
{
m_currentSelection
=
*
(
roots
.
begin
());
setSelected
(
m_currentSelection
,
true
);
}
else
{
Fun
undo
=
[]()
{
return
true
;
};
Fun
redo
=
[]()
{
return
true
;
};
...
...
@@ -3272,6 +3291,20 @@ bool TimelineModel::requestSetSelection(const std::unordered_set<int> &ids)
return
result
;
}
void
TimelineModel
::
setSelected
(
int
itemId
,
bool
sel
)
{
if
(
isClip
(
itemId
))
{
m_allClips
[
itemId
]
->
setSelected
(
sel
);
}
else
if
(
isComposition
(
itemId
))
{
m_allCompositions
[
itemId
]
->
setSelected
(
sel
);
}
else
if
(
isGroup
(
itemId
))
{
auto
leaves
=
m_groups
->
getLeaves
(
itemId
);
for
(
auto
&
id
:
leaves
)
{
setSelected
(
id
,
true
);
}
}
}
bool
TimelineModel
::
requestSetSelection
(
const
std
::
unordered_set
<
int
>
&
ids
,
Fun
&
undo
,
Fun
&
redo
)
{
QWriteLocker
locker
(
&
m_lock
);
...
...
src/timeline2/model/timelinemodel.hpp
View file @
0ca212ca
...
...
@@ -155,6 +155,7 @@ public:
EffectNamesRole
,
// track and clip only
EffectsEnabledRole
,
// track and clip only
GrabbedRole
,
/// clip+composition only
SelectedRole
,
/// clip+composition only
TrackActiveRole
,
/// track only
AudioRecordRole
/// track only
};
...
...
@@ -404,6 +405,9 @@ protected:
@param state: The desired clip state (original, audio/video only).
*/
bool
requestClipCreation
(
const
QString
&
binClipId
,
int
&
id
,
PlaylistState
::
ClipState
state
,
double
speed
,
Fun
&
undo
,
Fun
&
redo
);
/* @brief Switch item selection status */
void
setSelected
(
int
itemId
,
bool
sel
);
public:
/* @brief Deletes the given clip or composition from the timeline.
...
...
src/timeline2/view/qml/Track.qml
View file @
0ca212ca
...
...
@@ -77,7 +77,7 @@ Column{
Binding
{
target
:
loader
.
item
property
:
"
selected
"
value
:
loader
.
item
?
root
.
timelineSelection
.
indexOf
(
loader
.
item
.
clipId
)
!==
-
1
:
false
value
:
model
.
selected
when
:
loader
.
status
==
Loader
.
Ready
&&
model
.
clipType
!=
ProducerType
.
Track
}
Binding
{
...
...
src/timeline2/view/timelinecontroller.cpp
View file @
0ca212ca
...
...
@@ -244,8 +244,9 @@ void TimelineController::selectCurrentItem(ObjectType type, bool select, bool ad
QList
<
int
>
TimelineController
::
selection
()
const
{
if
(
!
m_root
)
return
QList
<
int
>
();
std
::
unordered_set
<
int
>
sel
=
m_model
->
getCurrentSelection
();
QList
<
int
>
items
;
for
(
int
id
:
m_model
->
getCurrentSelection
()
)
{
for
(
int
id
:
sel
)
{
items
<<
id
;
}
return
items
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment