bin.h 18.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/*
Copyright (C) 2012  Till Theato <root@ttill.de>
Copyright (C) 2014  Jean-Baptiste Mardelle <jb@kdenlive.org>
This file is part of Kdenlive. See www.kdenlive.org.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
11
by the membership of KDE e.V.), which shall act as a proxy
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
defined in Section 14 of version 3 of the license.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef KDENLIVE_BIN_H
#define KDENLIVE_BIN_H

#include "abstractprojectitem.h"
27
#include "timecode.h"
28

29
30
#include <KMessageWidget>

Nicolas Carion's avatar
Nicolas Carion committed
31
#include <QDir>
32
#include <QDomElement>
33
#include <QFuture>
34
#include <QLineEdit>
Nicolas Carion's avatar
Nicolas Carion committed
35
36
37
#include <QListView>
#include <QMutex>
#include <QPushButton>
Nicolas Carion's avatar
Nicolas Carion committed
38
#include <QTreeView>
Nicolas Carion's avatar
Nicolas Carion committed
39
40
#include <QUrl>
#include <QWidget>
41

Nicolas Carion's avatar
Nicolas Carion committed
42
43
class AbstractProjectItem;
class BinItemDelegate;
44
class BinListItemDelegate;
45
class ClipController;
Nicolas Carion's avatar
Nicolas Carion committed
46
47
48
49
50
51
52
53
class EffectStackModel;
class InvalidDialog;
class KdenliveDoc;
class Monitor;
class ProjectClip;
class ProjectFolder;
class ProjectItemModel;
class ProjectSortProxyModel;
54
class QDockWidget;
Nicolas Carion's avatar
Nicolas Carion committed
55
56
class QMenu;
class QScrollArea;
57
class QTimeLine;
58
class QToolBar;
59
class QToolButton;
60
class QUndoCommand;
Nicolas Carion's avatar
Nicolas Carion committed
61
class QVBoxLayout;
62
class SmallJobLabel;
63

Nicolas Carion's avatar
Nicolas Carion committed
64
namespace Mlt {
65
class Producer;
66
}
67

Nicolas Carion's avatar
Nicolas Carion committed
68
class MyListView : public QListView
69
70
71
{
    Q_OBJECT
public:
Laurent Montel's avatar
Laurent Montel committed
72
    explicit MyListView(QWidget *parent = nullptr);
73
74

protected:
75
    void focusInEvent(QFocusEvent *event) override;
76
    void mouseMoveEvent(QMouseEvent *event) override;
77
78
signals:
    void focusView();
79
    void updateDragMode(ClipType::ProducerType type);
80
    void displayBinFrame(QModelIndex ix, int frame);
81
82
};

Nicolas Carion's avatar
Nicolas Carion committed
83
class MyTreeView : public QTreeView
84
85
{
    Q_OBJECT
86
    Q_PROPERTY(bool editing READ isEditing WRITE setEditing)
87
public:
Laurent Montel's avatar
Laurent Montel committed
88
    explicit MyTreeView(QWidget *parent = nullptr);
89
    void setEditing(bool edit);
Nicolas Carion's avatar
Nicolas Carion committed
90

91
protected:
92
93
94
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void focusInEvent(QFocusEvent *event) override;
95
96

protected slots:
97
98
    void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) override;
    void editorDestroyed(QObject *editor) override;
99
100
101

private:
    QPoint m_startPos;
102
    PlaylistState::ClipState m_dragType;
103
    bool m_editing;
104
    bool performDrag();
Laurent Montel's avatar
Laurent Montel committed
105
    bool isEditing() const;
106
107
108

signals:
    void focusView();
109
    void updateDragMode(PlaylistState::ClipState type);
110
    void displayBinFrame(QModelIndex ix, int frame);
111
112
};

Nicolas Carion's avatar
Nicolas Carion committed
113
class SmallJobLabel : public QPushButton
114
115
116
{
    Q_OBJECT
public:
Laurent Montel's avatar
Laurent Montel committed
117
    explicit SmallJobLabel(QWidget *parent = nullptr);
118
119
    static const QString getStyleSheet(const QPalette &p);
    void setAction(QAction *action);
Nicolas Carion's avatar
Nicolas Carion committed
120

121
private:
Nicolas Carion's avatar
Nicolas Carion committed
122
    enum ItemRole { NameRole = Qt::UserRole, DurationRole, UsageRole };
123

124
    QTimeLine *m_timeLine;
Nicolas Carion's avatar
Nicolas Carion committed
125
    QAction *m_action{nullptr};
Nicolas Carion's avatar
Nicolas Carion committed
126
    QMutex m_locker;
127
128
129
130
131
132
133
134
135

public slots:
    void slotSetJobCount(int jobCount);

private slots:
    void slotTimeLineChanged(qreal value);
    void slotTimeLineFinished();
};

136
137
138
139
class LineEventEater : public QObject
{
    Q_OBJECT
public:
Laurent Montel's avatar
Laurent Montel committed
140
    explicit LineEventEater(QObject *parent = nullptr);
141
142

protected:
143
    bool eventFilter(QObject *obj, QEvent *event) override;
144
145
146

signals:
    void clearSearchLine();
147
    void showClearButton(bool);
148
149
};

150
151
152
153
154
155
156
157
158
159
/**
 * @class Bin
 * @brief The bin widget takes care of both item model and view upon project opening.
 */

class Bin : public QWidget
{
    Q_OBJECT

    /** @brief Defines the view types (icon view, tree view,...)  */
Nicolas Carion's avatar
Nicolas Carion committed
160
    enum BinViewType { BinTreeView, BinIconView };
161
162

public:
Nicolas Carion's avatar
Nicolas Carion committed
163
164
    explicit Bin(std::shared_ptr<ProjectItemModel> model, QWidget *parent = nullptr);
    ~Bin() override;
165

166
    bool isLoading;
167
168
169
170
171

    /** @brief Sets the document for the bin and initialize some stuff  */
    void setDocument(KdenliveDoc *project);

    /** @brief Create a clip item from its xml description  */
Laurent Montel's avatar
Laurent Montel committed
172
    void createClip(const QDomElement &xml);
173
174

    /** @brief Used to notify the Model View that an item was updated */
175
    void emitItemUpdated(std::shared_ptr<AbstractProjectItem> item);
176
177
178
179
180
181
182
183

    /** @brief Set monitor associated with this bin (clipmonitor) */
    void setMonitor(Monitor *monitor);

    /** @brief Returns the clip monitor */
    Monitor *monitor();

    /** @brief Open a producer in the clip monitor */
184
185
    void openProducer(std::shared_ptr<ProjectClip> controller);
    void openProducer(std::shared_ptr<ProjectClip> controller, int in, int out);
186
187

    /** @brief Get a clip from it's id */
188
    std::shared_ptr<ProjectClip> getBinClip(const QString &id);
189

190
191
    /** @brief Returns a list of selected clip ids
     */
192
    std::vector<QString> selectedClipsIds();
193

194
195
    // Returns the selected clips
    QList<std::shared_ptr<ProjectClip>> selectedClips();
196

197
198
    /** @brief Current producer has changed, refresh monitor and timeline*/
    void refreshClip(const QString &id);
199

200
    void setupMenu();
201

202
203
    /** @brief The source file was modified, we will reload it soon, disable item in the meantime */
    void setWaitingStatus(const QString &id);
204
205
206

    const QString getDocumentProperty(const QString &key);

207
    /** @brief Ask MLT to reload this clip's producer  */
208
    void reloadClip(const QString &id, bool reloadAudio = true);
209

210
211
212
    /** @brief refresh monitor (if clip changed)  */
    void reloadMonitorIfActive(const QString &id);

213
    void doMoveClip(const QString &id, const QString &newParentId);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
214
    void doMoveFolder(const QString &id, const QString &newParentId);
215
    void setupGeneratorMenu();
216

217
218
    /** @brief Set focus to the Bin view. */
    void focusBinView() const;
219
220
    /** @brief Get a string list of all clip ids that are inside a folder defined by id. */
    QStringList getBinFolderClipIds(const QString &id) const;
221
    /** @brief Build a rename subclip command. */
222
    void renameSubClipCommand(const QString &id, const QString &newName, const QString &oldName, int in, int out);
223
    /** @brief Rename a clip zone (subclip). */
224
    void renameSubClip(const QString &id, const QString &newName, int in, int out);
225
226
    /** @brief Returns current project's timecode. */
    Timecode projectTimecode() const;
227
228
    /** @brief Trigger timecode format refresh where needed. */
    void updateTimecodeFormat();
229
    /** @brief Edit an effect settings to a bin clip. */
Nicolas Carion's avatar
Nicolas Carion committed
230
    void editMasterEffect(const std::shared_ptr<AbstractProjectItem> &clip);
231
232
    /** @brief An effect setting was changed, update stack if displayed. */
    void updateMasterEffect(ClipController *ctl);
233
    void rebuildMenu();
234
    void refreshIcons();
235
236
237
238

    /** @brief This function change the global enabled state of the bin effects
     */
    void setBinEffectsEnabled(bool enabled);
239

240
    void requestAudioThumbs(const QString &id, long duration);
241
242
    /** @brief Proxy status for the project changed, update. */
    void refreshProxySettings();
243
244
    /** @brief A clip is ready, update its info panel if displayed. */
    void emitRefreshPanel(const QString &id);
245
246
    /** @brief Returns true if there is no clip. */
    bool isEmpty() const;
247
248
    /** @brief Trigger reload of all clips. */
    void reloadAllProducers();
249
250
    /** @brief Get usage stats for project bin. */
    void getBinStats(uint *used, uint *unused, qint64 *usedSize, qint64 *unusedSize);
251
252
    /** @brief Returns the clip properties dockwidget. */
    QDockWidget *clipPropertiesDock();
253
    /** @brief Returns a document's cache dir. ok is set to false if folder does not exist */
254
    QDir getCacheDir(CacheType type, bool *ok) const;
255
    void rebuildProxies();
256
257
    /** @brief Return a list of all clips hashes used in this project */
    QStringList getProxyHashList();
258
259
    /** @brief Get binId of the current selected folder */
    QString getCurrentFolder();
260
    /** @brief Save a clip zone as MLT playlist */
Laurent Montel's avatar
Laurent Montel committed
261
    void saveZone(const QStringList &info, const QDir &dir);
262
263
    /** @brief A bin clip changed (its effects), invalidate preview */
    void invalidateClip(const QString &binId);
264

265
266
    // TODO refac: remove this and call directly the function in ProjectItemModel
    void cleanup();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
267
    void selectAll();
268

269
270
271
private slots:
    void slotAddClip();
    void slotReloadClip();
272
273
274
275
276
    /** @brief Set sorting column */
    void slotSetSorting();
    /** @brief Show/hide date column */
    void slotShowDateColumn(bool show);
    void slotShowDescColumn(bool show);
277
278
    /** @brief Go to parent folder */
    void slotBack();
279
    /** @brief Setup the bin view type (icon view, tree view, ...).
280
     * @param action The action whose data defines the view type or nullptr to keep default view */
281
282
    void slotInitView(QAction *action);

283
    /** @brief Update status for clip jobs  */
Nicolas Carion's avatar
Nicolas Carion committed
284
285
    void slotUpdateJobStatus(const QString &, int, int, const QString &label = QString(), const QString &actionName = QString(),
                             const QString &details = QString());
286
287
288
    void slotSetIconSize(int size);
    void selectProxyModel(const QModelIndex &id);
    void slotSaveHeaders();
Laurent Montel's avatar
Laurent Montel committed
289
    void slotItemDropped(const QStringList &ids, const QModelIndex &parent);
290
    void slotItemDropped(const QList<QUrl> &urls, const QModelIndex &parent);
291
    void slotEffectDropped(const QStringList &effectData, const QModelIndex &parent);
Laurent Montel's avatar
Laurent Montel committed
292
    void slotItemEdited(const QModelIndex &, const QModelIndex &, const QVector<int> &);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
293

294
295
    /** @brief Reset all text and log data from info message widget. */
    void slotResetInfoMessage();
296
    /** @brief Show dialog prompting for removal of invalid clips. */
297
    void slotQueryRemoval(const QString &id, const QString &url, const QString &errorMessage);
298
299
    /** @brief Request display of current clip in monitor. */
    void slotOpenCurrent();
300
    void slotZoomView(bool zoomIn);
301
    /** @brief Widget gained focus, make sure we display effects for master clip. */
302
    void slotGotFocus();
303
304
    /** @brief Rename a Bin Item. */
    void slotRenameItem();
305
    void doRefreshPanel(const QString &id);
306
307
    /** @brief Enable item view and hide message */
    void slotMessageActionTriggered();
308
309
    /** @brief Request editing of title or slideshow clip */
    void slotEditClip();
310
311
312
313
    /** @brief Enable / disable clear button on search line
     *  this is a workaround foq Qt bug 54676
     */
    void showClearButton(bool show);
314
315
316
    /** @brief Display a defined frame in bin clip thumbnail
     */
    void showBinFrame(QModelIndex ix, int frame);
317
318

public slots:
319
    void slotRemoveInvalidClip(const QString &id, bool replace, const QString &errorMessage);
320
321
    /** @brief Reload clip thumbnail - when frame for thumbnail changed */
    void slotRefreshClipThumbnail(const QString &id);
322
    void slotDeleteClip();
Nicolas Carion's avatar
Nicolas Carion committed
323
    void slotItemDoubleClicked(const QModelIndex &ix, const QPoint &pos);
Nicolas Carion's avatar
Nicolas Carion committed
324
    void slotSwitchClipProperties(const std::shared_ptr<ProjectClip> &clip);
325
    void slotSwitchClipProperties();
326
    /** @brief Creates a new folder with optional name, and returns new folder's id */
327
    void slotAddFolder();
328
    void slotCreateProjectClip();
Laurent Montel's avatar
Laurent Montel committed
329
    void slotEditClipCommand(const QString &id, const QMap<QString, QString> &oldProps, const QMap<QString, QString> &newProps);
330
    /** @brief Start a filter job requested by a filter applied in timeline */
Nicolas Carion's avatar
Nicolas Carion committed
331
332
    void slotStartFilterJob(const ItemInfo &info, const QString &id, QMap<QString, QString> &filterParams, QMap<QString, QString> &consumerParams,
                            QMap<QString, QString> &extraParams);
333
334
    /** @brief Open current clip in an external editing application */
    void slotOpenClip();
335
    void slotDuplicateClip();
336
    void slotLocateClip();
337
    /** @brief Add extra data to a clip. */
Laurent Montel's avatar
Laurent Montel committed
338
    void slotAddClipExtraData(const QString &id, const QString &key, const QString &data = QString(), QUndoCommand *groupCommand = nullptr);
Laurent Montel's avatar
Laurent Montel committed
339
    void slotUpdateClipProperties(const QString &id, const QMap<QString, QString> &properties, bool refreshPropertiesPanel);
340
    /** @brief Add effect to active Bin clip (used when double clicking an effect in list). */
341
    void slotAddEffect(QString id, const QStringList &effectData);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
342
    void slotExpandUrl(const ItemInfo &info, const QString &url, QUndoCommand *command);
343
344
    /** @brief Abort all ongoing operations to prepare close. */
    void abortOperations();
Laurent Montel's avatar
Laurent Montel committed
345
    void doDisplayMessage(const QString &text, KMessageWidget::MessageType type, const QList<QAction *> &actions = QList<QAction *>());
346
    void doDisplayMessage(const QString &text, KMessageWidget::MessageType type, const QString &logInfo);
347
348
    /** @brief Reset all clip usage to 0 */
    void resetUsageCount();
349
    /** @brief Select a clip in the Bin from its id. */
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
350
    void selectClipById(const QString &id, int frame = -1, const QPoint &zone = QPoint());
Laurent Montel's avatar
Laurent Montel committed
351
    void slotAddClipToProject(const QUrl &url);
352
    void droppedUrls(const QList<QUrl> &urls, const QString &folderInfo = QString());
353
354
    /** @brief Returns the effectstack of a given clip. */
    std::shared_ptr<EffectStackModel> getClipEffectStack(int itemId);
355
    /** @brief Returns the duration of a given clip. */
356
    size_t getClipDuration(int itemId) const;
357
358
    /** @brief Returns the state of a given clip: AudioOnly, VideoOnly, Disabled (Disabled means it has audio and video capabilities */
    PlaylistState::ClipState getClipState(int itemId) const;
359
360
    /** @brief Adjust project profile to current clip. */
    void adjustProjectProfileToItem();
361

362
protected:
363
364
365
    /* This function is called whenever an item is selected to propagate signals
       (for ex request to show the clip in the monitor)
    */
Nicolas Carion's avatar
Nicolas Carion committed
366
    void setCurrent(const std::shared_ptr<AbstractProjectItem> &item);
367
    void selectClip(const std::shared_ptr<ProjectClip> &clip);
368
369
    void contextMenuEvent(QContextMenuEvent *event) override;
    bool eventFilter(QObject *obj, QEvent *event) override;
370
    QSize sizeHint() const override;
371
372

private:
373
    std::shared_ptr<ProjectItemModel> m_itemModel;
374
375
    QAbstractItemView *m_itemView;
    BinItemDelegate *m_binTreeViewDelegate;
376
377
    BinListItemDelegate *m_binListViewDelegate;
    std::unique_ptr<ProjectSortProxyModel> m_proxyModel;
378
    QToolBar *m_toolbar;
379
    KdenliveDoc *m_doc;
380
    QLineEdit *m_searchLine;
381
382
383
384
    QToolButton *m_addButton;
    QMenu *m_extractAudioAction;
    QMenu *m_transcodeAction;
    QMenu *m_clipsActionsMenu;
385
    QAction *m_inTimelineAction;
386
387
    QAction *m_showDate;
    QAction *m_showDesc;
388
389
390
391
392
393
    /** @brief Default view type (icon, tree, ...) */
    BinViewType m_listType;
    /** @brief Default icon size for the views. */
    QSize m_iconSize;
    /** @brief Keeps the column width info of the tree view. */
    QByteArray m_headerInfo;
394
395
    QVBoxLayout *m_layout;
    QDockWidget *m_propertiesDock;
396
    QScrollArea *m_propertiesPanel;
397
    QSlider *m_slider;
398
    Monitor *m_monitor;
399
    QIcon m_blankThumb;
400
401
    QMenu *m_menu;
    QAction *m_openAction;
402
    QAction *m_editAction;
403
    QAction *m_reloadAction;
404
    QAction *m_duplicateAction;
405
    QAction *m_locateAction;
406
407
    QAction *m_proxyAction;
    QAction *m_deleteAction;
408
    QAction *m_renameAction;
409
410
411
    QMenu *m_jobsMenu;
    QAction *m_cancelJobs;
    QAction *m_discardCurrentClipJobs;
412
    QAction *m_discardPendingJobs;
413
    QAction *m_upAction;
414
    SmallJobLabel *m_infoLabel;
415
    /** @brief The info widget for failed jobs. */
416
    KMessageWidget *m_infoMessage;
417
    QStringList m_errorLog;
418
    InvalidDialog *m_invalidClipDialog;
419
420
    /** @brief Set to true if widget just gained focus (means we have to update effect stack . */
    bool m_gainedFocus;
421
422
423
424
    /** @brief List of Clip Ids that want an audio thumb. */
    QStringList m_audioThumbsList;
    QString m_processingAudioThumb;
    QMutex m_audioThumbMutex;
425
426
427
428
    /** @brief Total number of milliseconds to process for audio thumbnails */
    long m_audioDuration;
    /** @brief Total number of milliseconds already processed for audio thumbnails */
    long m_processedAudio;
429
430
    /** @brief Indicates whether audio thumbnail creation is running. */
    QFuture<void> m_audioThumbsThread;
431
432
    QAction *addAction(const QString &name, const QString &text, const QIcon &icon);
    void setupAddClipAction(QMenu *addClipMenu, ClipType::ProducerType type, const QString &name, const QString &text, const QIcon &icon);
Nicolas Carion's avatar
Nicolas Carion committed
433
    void showClipProperties(const std::shared_ptr<ProjectClip> &clip, bool forceRefresh = false);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
434
435
    /** @brief Get the QModelIndex value for an item in the Bin. */
    QModelIndex getIndexForId(const QString &id, bool folderWanted) const;
436
    std::shared_ptr<ProjectClip> getFirstSelectedClip();
Nicolas Carion's avatar
Nicolas Carion committed
437
438
    void showTitleWidget(const std::shared_ptr<ProjectClip> &clip);
    void showSlideshowWidget(const std::shared_ptr<ProjectClip> &clip);
439
    void processAudioThumbs();
440
    int wheelAccumulatedDelta;
441
442

signals:
443
    void itemUpdated(std::shared_ptr<AbstractProjectItem>);
444
    void producerReady(const QString &id);
445
    /** @brief Save folder info into MLT. */
Laurent Montel's avatar
Laurent Montel committed
446
447
    void storeFolder(const QString &folderId, const QString &parentId, const QString &oldParentId, const QString &folderName);
    void gotFilterJobResults(const QString &, int, int, stringMap, stringMap);
448
449
    /** @brief Trigger timecode format refresh where needed. */
    void refreshTimeCode();
450
    /** @brief Request display of effect stack for a Bin clip. */
451
    void requestShowEffectStack(const QString &clipName, std::shared_ptr<EffectStackModel>, QSize frameSize, bool showKeyframes);
452
    /** @brief Request that the given clip is displayed in the clip monitor */
453
    void requestClipShow(std::shared_ptr<ProjectClip>);
454
    void displayBinMessage(const QString &, KMessageWidget::MessageType);
455
    void requesteInvalidRemoval(const QString &, const QString &, const QString &);
456
457
    /** @brief Analysis data changed, refresh panel. */
    void updateAnalysisData(const QString &);
458
    void openClip(std::shared_ptr<ProjectClip> c, int in = -1, int out = -1);
459
    /** @brief Fill context menu with occurrences of this clip in timeline. */
460
    void findInTimeline(const QString &, QList<int> ids = QList<int>());
461
    void clipNameChanged(const QString &);
462
463
    /** @brief A clip was updated, request panel update. */
    void refreshPanel(const QString &id);
464
    /** @brief Upon selection, activate timeline target tracks. */
465
    void setupTargets(bool hasVideo, QList <int> audioStreams);
466
467
468
};

#endif