From f14b0cef7d3559087c8e9f3de0586d765df0d766 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 16 Feb 2019 22:22:43 -0800 Subject: [PATCH] replaced mediathrobber with mediaiconservice --- dialogs/replaceclipmediadialog.cpp | 2 +- io/loadthread.cpp | 4 +- io/previewgenerator.cpp | 11 +-- io/previewgenerator.h | 11 +-- main.cpp | 3 + olive.pro | 6 +- panels/project.cpp | 112 +++++++---------------------- panels/project.h | 17 ----- project/footage.h | 1 - project/media.cpp | 4 +- project/media.h | 3 - project/projectmodel.cpp | 2 + project/projectmodel.h | 4 ++ project/undo.cpp | 20 +++--- ui/mediaiconservice.cpp | 93 ++++++++++++++++++++++++ ui/mediaiconservice.h | 58 +++++++++++++++ ui/timelinewidget.cpp | 4 +- 17 files changed, 213 insertions(+), 142 deletions(-) create mode 100644 ui/mediaiconservice.cpp create mode 100644 ui/mediaiconservice.h diff --git a/dialogs/replaceclipmediadialog.cpp b/dialogs/replaceclipmediadialog.cpp index 7a4cdc2c2..88d7f898a 100644 --- a/dialogs/replaceclipmediadialog.cpp +++ b/dialogs/replaceclipmediadialog.cpp @@ -67,7 +67,7 @@ ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media layout->addLayout(buttons); - tree->setModel(&project_model); + tree->setModel(&olive::project_model); } void ReplaceClipMediaDialog::replace() { diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 741453853..bb951a159 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -288,7 +288,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { item->set_footage(f); if (folder == 0) { - project_model.appendChild(nullptr, item); + olive::project_model.appendChild(nullptr, item); } else { find_loaded_folder_by_id(folder)->appendChild(item); } @@ -645,7 +645,7 @@ void LoadThread::run() { Media* folder = loaded_folders.at(i); int parent = folder->temp_id2; if (folder->temp_id2 == 0) { - project_model.appendChild(nullptr, folder); + olive::project_model.appendChild(nullptr, folder); } else { find_loaded_folder_by_id(parent)->appendChild(folder); } diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index 36c0e644c..dce3522cf 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -20,6 +20,7 @@ #include "previewgenerator.h" +#include "ui/mediaiconservice.h" #include "project/media.h" #include "project/footage.h" #include "panels/viewer.h" @@ -189,12 +190,12 @@ void PreviewGenerator::finalize_media() { footage->ready = true; if (!cancelled) { - if (footage->video_tracks.size() == 0) { - emit set_icon(ICON_TYPE_AUDIO, replace); + if (footage->video_tracks.size() == 0) { + olive::media_icon_service->SetMediaIcon(media, ICON_TYPE_AUDIO); } else if (contains_still_image) { - emit set_icon(ICON_TYPE_IMAGE, replace); + olive::media_icon_service->SetMediaIcon(media, ICON_TYPE_IMAGE); } else { - emit set_icon(ICON_TYPE_VIDEO, replace); + olive::media_icon_service->SetMediaIcon(media, ICON_TYPE_VIDEO); } /*if (!contains_still_image || media->audio_tracks.size() > 0) { @@ -575,7 +576,7 @@ void PreviewGenerator::run() { if (!cancelled) { if (error) { media->update_tooltip(errorStr); - emit set_icon(ICON_TYPE_ERROR, replace); + olive::media_icon_service->SetMediaIcon(media, ICON_TYPE_ERROR); footage->invalid = true; footage->ready_lock.unlock(); } else { diff --git a/io/previewgenerator.h b/io/previewgenerator.h index 40af8f64d..21bae9be7 100644 --- a/io/previewgenerator.h +++ b/io/previewgenerator.h @@ -25,13 +25,6 @@ #include #include -enum IconType { - ICON_TYPE_VIDEO, - ICON_TYPE_AUDIO, - ICON_TYPE_IMAGE, - ICON_TYPE_ERROR -}; - #include "project/footage.h" #include "project/media.h" @@ -48,9 +41,7 @@ class PreviewGenerator : public QThread public: PreviewGenerator(Media*, FootagePtr, bool); void run(); - void cancel(); -signals: - void set_icon(int, bool); + void cancel(); private: void parse_media(); bool retrieve_preview(const QString &hash); diff --git a/main.cpp b/main.cpp index 2976ef578..a4d93a56d 100644 --- a/main.cpp +++ b/main.cpp @@ -24,6 +24,7 @@ #include "debug.h" #include "oliveglobal.h" +#include "ui/mediaiconservice.h" #include "io/config.h" @@ -109,6 +110,8 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); a.setWindowIcon(QIcon(":/icons/olive64.png")); + olive::media_icon_service = std::unique_ptr(new MediaIconService()); + QCoreApplication::setOrganizationName("olivevideoeditor.org"); QCoreApplication::setOrganizationDomain("olivevideoeditor.org"); QCoreApplication::setApplicationName("Olive"); diff --git a/olive.pro b/olive.pro index dc68ad4ef..bee391b17 100644 --- a/olive.pro +++ b/olive.pro @@ -149,7 +149,8 @@ SOURCES += \ ui/menuhelper.cpp \ oliveglobal.cpp \ ui/focusfilter.cpp \ - project/comboaction.cpp + project/comboaction.cpp \ + ui/mediaiconservice.cpp HEADERS += \ mainwindow.h \ @@ -256,7 +257,8 @@ HEADERS += \ oliveglobal.h \ project/projectelements.h \ ui/focusfilter.h \ - project/comboaction.h + project/comboaction.h \ + ui/mediaiconservice.h FORMS += diff --git a/panels/project.cpp b/panels/project.cpp index c95a0f5ed..37c99194f 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -38,6 +38,7 @@ #include "ui/sourcetable.h" #include "ui/sourceiconview.h" #include "ui/menuhelper.h" +#include "ui/mediaiconservice.h" #include "project/sourcescommon.h" #include "project/projectfilter.h" #include "debug.h" @@ -63,9 +64,7 @@ extern "C" { #include } -#define MAXIMUM_RECENT_PROJECTS 10 - -ProjectModel project_model; +#define MAXIMUM_RECENT_PROJECTS 10 // FIXME: should be configurable QString autorecovery_filename; QStringList recent_projects; @@ -86,7 +85,7 @@ Project::Project(QWidget *parent) : sources_common = new SourcesCommon(this); sorter = new ProjectFilter(this); - sorter->setSourceModel(&project_model); + sorter->setSourceModel(&olive::project_model); // optional toolbar toolbar_widget = new QWidget(); @@ -223,7 +222,7 @@ Project::Project(QWidget *parent) : verticalLayout->addWidget(icon_view_container); connect(directory_up, SIGNAL(clicked(bool)), this, SLOT(go_up_dir())); - connect(icon_view, SIGNAL(changed_root()), this, SLOT(set_up_dir_enabled())); + connect(icon_view, SIGNAL(changed_root()), this, SLOT(set_up_dir_enabled())); setWindowTitle(tr("Project")); @@ -247,8 +246,8 @@ QString Project::get_next_sequence_name(QString start) { name += "0"; } name += QString::number(n); - for (int i=0;iget_name(), name, Qt::CaseInsensitive) == 0) { + for (int i=0;iget_name(), name, Qt::CaseInsensitive) == 0) { found = true; n++; break; @@ -426,7 +425,7 @@ void Project::new_folder() { Media* m = create_folder_internal(nullptr); olive::UndoStack.push(new AddMediaCommand(m, get_selected_folder())); - QModelIndex index = project_model.create_index(m->row(), 0, m); + QModelIndex index = olive::project_model.create_index(m->row(), 0, m); switch (olive::CurrentConfig.project_view_type) { case PROJECT_VIEW_TREE: tree_view->edit(sorter->mapFromSource(index)); @@ -445,7 +444,7 @@ void Project::new_sequence() { Media* Project::create_sequence_internal(ComboAction *ca, SequencePtr s, bool open, Media* parent) { if (parent == nullptr) { - parent = project_model.get_root(); + parent = olive::project_model.get_root(); } Media* item(new Media(parent)); @@ -455,8 +454,8 @@ Media* Project::create_sequence_internal(ComboAction *ca, SequencePtr s, bool op ca->append(new NewSequenceCommand(item, parent)); if (open) ca->append(new ChangeSequenceAction(s)); } else { - if (parent == project_model.get_root()) { - project_model.appendChild(parent, item); + if (parent == olive::project_model.get_root()) { + olive::project_model.appendChild(parent, item); } else { parent->appendChild(item); } @@ -534,8 +533,8 @@ void Project::delete_selected_media() { QVector parents; QList sequence_items; QList all_top_level_items; - for (int i=0;i 0) { @@ -665,15 +664,11 @@ void Project::delete_selected_media() { } void Project::start_preview_generator(Media* item, bool replacing) { - // set up throbber animation - MediaThrobber* throbber = new MediaThrobber(item); - throbber->moveToThread(QApplication::instance()->thread()); - item->throbber = throbber; - QMetaObject::invokeMethod(throbber, "start", Qt::QueuedConnection); + // set up throbber animation + olive::media_icon_service->SetMediaIcon(item, ICON_TYPE_LOADING); PreviewGenerator* pg = new PreviewGenerator(item, item->to_footage(), replacing); - item->to_footage()->preview_gen = pg; - connect(pg, SIGNAL(set_icon(int, bool)), throbber, SLOT(stop(int, bool))); + item->to_footage()->preview_gen = pg; pg->start(QThread::LowPriority); } @@ -710,7 +705,7 @@ void Project::process_file_list(QStringList& files, bool recursive, Media* repla if (create_undo_action) { ca->append(new AddMediaCommand(folder, parent)); } else { - project_model.appendChild(parent, folder); + olive::project_model.appendChild(parent, folder); } imported = true; @@ -853,9 +848,9 @@ Media* Project::get_selected_folder() { } bool Project::reveal_media(Media *media, QModelIndex parent) { - for (int i=0;iget_type() == MEDIA_TYPE_FOLDER) { @@ -963,7 +958,7 @@ void Project::clear() { } // delete everything else - project_model.clear(); + olive::project_model.clear(); // update tree view (sometimes this doesn't seem to update reliably) tree_view->update(); @@ -992,9 +987,9 @@ void save_marker(QXmlStreamWriter& stream, const Marker& m) { } void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex& parent) { - for (int i=0;iget_type()) { if (m->get_type() == MEDIA_TYPE_FOLDER) { @@ -1009,7 +1004,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, if (!item.parent().isValid()) { stream.writeAttribute("parent", "0"); } else { - stream.writeAttribute("parent", QString::number(project_model.getItem(item.parent())->temp_id)); + stream.writeAttribute("parent", QString::number(olive::project_model.getItem(item.parent())->temp_id)); } stream.writeEndElement(); } @@ -1308,8 +1303,8 @@ void Project::add_recent_project(QString url) { } void Project::list_all_sequences_worker(QVector* list, Media* parent) { - for (int i=0;iget_type()) { case MEDIA_TYPE_SEQUENCE: list->append(item); @@ -1333,58 +1328,3 @@ QModelIndexList Project::get_current_selected() { } return icon_view->selectionModel()->selectedIndexes(); } - -#define THROBBER_LIMIT 20 -#define THROBBER_SIZE 50 - -MediaThrobber::MediaThrobber(Media *i) : pixmap(":/icons/throbber.png"), animation(0), item(i), animator(nullptr) {} - -void MediaThrobber::start() { - // set up throbber - animation_update(); - animator = new QTimer(this); - animator->setInterval(20); - connect(animator, SIGNAL(timeout()), this, SLOT(animation_update())); - animator->start(); -} - -void MediaThrobber::animation_update() { - if (animation == THROBBER_LIMIT) { - animation = 0; - } - project_model.set_icon(item, QIcon(pixmap.copy(THROBBER_SIZE*animation, 0, THROBBER_SIZE, THROBBER_SIZE))); - animation++; -} - -void MediaThrobber::stop(int icon_type, bool replace) { - if (animator != nullptr) { - animator->stop(); - delete animator; - } - - switch (icon_type) { - case ICON_TYPE_VIDEO: project_model.set_icon(item, QIcon(":/icons/videosource.png")); break; - case ICON_TYPE_AUDIO: project_model.set_icon(item, QIcon(":/icons/audiosource.png")); break; - case ICON_TYPE_IMAGE: project_model.set_icon(item, QIcon(":/icons/imagesource.png")); break; - case ICON_TYPE_ERROR: project_model.set_icon(item, QIcon(":/icons/error.png")); break; - } - - // refresh all clips - QVector sequences = panel_project->list_all_project_sequences(); - for (int i=0;ito_sequence(); - for (int j=0;jclips.size();j++) { - const ClipPtr& c = s->clips.at(j); - if (c != nullptr) { - c->refresh(); - } - } - } - - // redraw clips - update_ui(replace); - - panel_project->tree_view->viewport()->update(); - item->throbber = nullptr; - deleteLater(); -} diff --git a/panels/project.h b/panels/project.h index 5a073f455..52113f290 100644 --- a/panels/project.h +++ b/panels/project.h @@ -44,7 +44,6 @@ extern QString autorecovery_filename; extern QStringList recent_projects; -extern ProjectModel project_model; SequencePtr create_sequence_from_media(QVector &media_list); @@ -122,20 +121,4 @@ private slots: void make_new_menu(); }; -class MediaThrobber : public QObject { - Q_OBJECT -public: - MediaThrobber(Media*); -public slots: - void start(); - void stop(int, bool replace); -private slots: - void animation_update(); -private: - QPixmap pixmap; - int animation; - Media* item; - QTimer* animator; -}; - #endif // PROJECT_H diff --git a/project/footage.h b/project/footage.h index 9c99c2a87..979a3af98 100644 --- a/project/footage.h +++ b/project/footage.h @@ -40,7 +40,6 @@ enum VideoInterlacingMode { class Sequence; class Clip; class PreviewGenerator; -class MediaThrobber; struct FootageStream { int file_index; diff --git a/project/media.cpp b/project/media.cpp index 118d9c960..1094b3721 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -61,8 +61,7 @@ QString get_channel_layout_name(int channels, uint64_t layout) { } Media::Media(Media* iparent) : - parent(iparent), - throbber(nullptr), + parent(iparent), root(false), type(-1) {} @@ -71,7 +70,6 @@ Media::~Media() { for (int i=0;i; using VoidPtr = std::shared_ptr; -class MediaThrobber; - class Media { public: @@ -58,7 +56,6 @@ public: int get_type(); const QString& get_name(); void set_name(const QString& n); - MediaThrobber* throbber; double get_frame_rate(int stream = -1); int get_sampling_rate(int stream = -1); diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index 177eaa0fc..35fbb9633 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -26,6 +26,8 @@ #include "project/media.h" #include "debug.h" +ProjectModel olive::project_model; + ProjectModel::ProjectModel(QObject *parent) : QAbstractItemModel(parent), root_item(nullptr) { make_root(); } diff --git a/project/projectmodel.h b/project/projectmodel.h index a875dfb51..3135f1e8b 100644 --- a/project/projectmodel.h +++ b/project/projectmodel.h @@ -60,4 +60,8 @@ private: Media* root_item; }; +namespace olive { + extern ProjectModel project_model; +} + #endif // PROJECTMODEL_H diff --git a/project/undo.cpp b/project/undo.cpp index 17dfe6474..27a5b1344 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -357,7 +357,7 @@ NewSequenceCommand::NewSequenceCommand(Media *s, Media* iparent) { parent = iparent; done = false; - if (parent == nullptr) parent = project_model.get_root(); + if (parent == nullptr) parent = olive::project_model.get_root(); } NewSequenceCommand::~NewSequenceCommand() { @@ -365,13 +365,13 @@ NewSequenceCommand::~NewSequenceCommand() { } void NewSequenceCommand::doUndo() { - project_model.removeChild(parent, seq); + olive::project_model.removeChild(parent, seq); done = false; } void NewSequenceCommand::doRedo() { - project_model.appendChild(parent, seq); + olive::project_model.appendChild(parent, seq); done = true; } @@ -389,13 +389,13 @@ AddMediaCommand::~AddMediaCommand() { } void AddMediaCommand::doUndo() { - project_model.removeChild(parent, item); + olive::project_model.removeChild(parent, item); done = false; } void AddMediaCommand::doRedo() { - project_model.appendChild(parent, item); + olive::project_model.appendChild(parent, item); done = true; } @@ -412,14 +412,14 @@ DeleteMediaCommand::~DeleteMediaCommand() { } void DeleteMediaCommand::doUndo() { - project_model.appendChild(parent, item); + olive::project_model.appendChild(parent, item); done = false; } void DeleteMediaCommand::doRedo() { - project_model.removeChild(parent, item); + olive::project_model.removeChild(parent, item); done = true; } @@ -641,18 +641,18 @@ MediaMove::MediaMove() {} void MediaMove::doUndo() { for (int i=0;iparentItem(); froms[i] = parent; - project_model.moveChild(items.at(i), to); + olive::project_model.moveChild(items.at(i), to); } } diff --git a/ui/mediaiconservice.cpp b/ui/mediaiconservice.cpp new file mode 100644 index 000000000..6a2578d17 --- /dev/null +++ b/ui/mediaiconservice.cpp @@ -0,0 +1,93 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + 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 3 of the License, or + (at your option) any later version. + + 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 . + +***/ + +#include "mediaiconservice.h" + +const int kThrobberLimit = 20; +const int kThrobberSize = 50; + +#include "project/projectmodel.h" + +std::unique_ptr olive::media_icon_service; + +MediaIconService::MediaIconService() { + // set up animation timer + throbber_animator_.setInterval(20); + connect(&throbber_animator_, SIGNAL(timeout()), this, SLOT(AnimationUpdate())); + + // set up pixmap + throbber_pixmap_ = QPixmap(":/icons/throbber.png"); +} + +void MediaIconService::SetMediaIcon(Media *media, int icon_type) { + // if this icon is already part of the throbber animation loop, remove it + if (throbber_items_.contains(media)) { + throbber_items_.removeAll(media); + + // if we aren't animating anything, no need to run the timer for now + if (throbber_items_.empty()) { + // ensure timer function is called in its own thread + QMetaObject::invokeMethod(&throbber_animator_, "stop", Qt::QueuedConnection); + } + } + + switch (icon_type) { + case ICON_TYPE_VIDEO: + olive::project_model.set_icon(media, QIcon(":/icons/videosource.png")); + break; + case ICON_TYPE_AUDIO: + olive::project_model.set_icon(media, QIcon(":/icons/audiosource.png")); + break; + case ICON_TYPE_IMAGE: + olive::project_model.set_icon(media, QIcon(":/icons/imagesource.png")); + break; + case ICON_TYPE_LOADING: + throbber_items_.append(media); + + // if the animation timer isn't running, start it + if (!throbber_animator_.isActive()) { + // set starting frame to 0 + throbber_animation_frame_ = 0; + + // ensure timer function is called in its own thread + QMetaObject::invokeMethod(&throbber_animator_, "start", Qt::QueuedConnection); + } + break; + case ICON_TYPE_ERROR: + olive::project_model.set_icon(media, QIcon(":/icons/error.png")); + break; + } + + emit IconChanged(); +} + +void MediaIconService::AnimationUpdate() { + if (throbber_animation_frame_ == kThrobberLimit) { + throbber_animation_frame_ = 0; + } + + QIcon throbber_ico = QIcon(throbber_pixmap_.copy(kThrobberSize*throbber_animation_frame_, 0, kThrobberSize, kThrobberSize)); + + for (int i=0;i. + +***/ + +#ifndef MEDIAICONSERVICE_H +#define MEDIAICONSERVICE_H + +#include +#include + +#include "project/media.h" + +enum IconType { + ICON_TYPE_VIDEO, + ICON_TYPE_AUDIO, + ICON_TYPE_IMAGE, + ICON_TYPE_LOADING, + ICON_TYPE_ERROR +}; + +class MediaIconService : public QObject { + Q_OBJECT +public: + MediaIconService(); +public slots: + void SetMediaIcon(Media* media, int icon_type); +signals: + void IconChanged(); +private slots: + void AnimationUpdate(); +private: + int throbber_animation_frame_; + QVector throbber_items_; + QTimer throbber_animator_; + QPixmap throbber_pixmap_; +}; + +namespace olive { + extern std::unique_ptr media_icon_service; +} + +#endif // MEDIAICONSERVICE_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index d18c45ecf..1d8afcbac 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -244,8 +244,8 @@ void TimelineWidget::rename_clip() { void TimelineWidget::open_sequence_properties() { QList sequence_items; QList all_top_level_items; - for (int i=0;iget_all_media_from_table(all_top_level_items, sequence_items, MEDIA_TYPE_SEQUENCE); // find all sequences in project for (int i=0;i