aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Mardelle <[email protected]>2015-01-11 21:34:56 +0100
committerJean-Baptiste Mardelle <[email protected]>2015-01-11 21:34:56 +0100
commit366b021b37adc25ad70af9e2958ad40d59084117 (patch)
treee1484100a3c406d2df9153a368c3282a53ac66df
parentc47906702ca1467c18f05d5d1d3483d4bfaa63c0 (diff)
Bring back job info menu to cancel running jobs
-rw-r--r--src/bin/bin.cpp144
-rw-r--r--src/bin/bin.h35
-rw-r--r--src/project/jobs/jobmanager.cpp48
-rw-r--r--src/project/jobs/jobmanager.h16
4 files changed, 238 insertions, 5 deletions
diff --git a/src/bin/bin.cpp b/src/bin/bin.cpp
index cbe01ea..06bc0b2 100644
--- a/src/bin/bin.cpp
+++ b/src/bin/bin.cpp
@@ -42,14 +42,108 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KToolBar>
+#include <KColorScheme>
#include <QVBoxLayout>
+#include <QTimeLine>
#include <QSlider>
#include <QMenu>
#include <QDebug>
#include <QUndoCommand>
#include <KSplitterCollapserButton>
+
+SmallJobLabel::SmallJobLabel(QWidget *parent) : QPushButton(parent)
+{
+ setFixedWidth(0);
+ setFlat(true);
+ m_timeLine = new QTimeLine(500, this);
+ QObject::connect(m_timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(slotTimeLineChanged(qreal)));
+ QObject::connect(m_timeLine, SIGNAL(finished()), this, SLOT(slotTimeLineFinished()));
+ hide();
+}
+
+const QString SmallJobLabel::getStyleSheet(const QPalette &p)
+{
+ KColorScheme scheme(p.currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
+ QColor bg = scheme.background(KColorScheme::LinkBackground).color();
+ QColor fg = scheme.foreground(KColorScheme::LinkText).color();
+ QString style = QString("QPushButton {margin:3px;padding:2px;background-color: rgb(%1, %2, %3);border-radius: 4px;border: none;color: rgb(%4, %5, %6)}").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(fg.red()).arg(fg.green()).arg(fg.blue());
+
+ bg = scheme.background(KColorScheme::ActiveBackground).color();
+ fg = scheme.foreground(KColorScheme::ActiveText).color();
+ style.append(QString("\nQPushButton:hover {margin:3px;padding:2px;background-color: rgb(%1, %2, %3);border-radius: 4px;border: none;color: rgb(%4, %5, %6)}").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(fg.red()).arg(fg.green()).arg(fg.blue()));
+
+ return style;
+}
+
+void SmallJobLabel::setAction(QAction *action)
+{
+ m_action = action;
+}
+
+void SmallJobLabel::slotTimeLineChanged(qreal value)
+{
+ setFixedWidth(qMin(value * 2, qreal(1.0)) * sizeHint().width());
+ update();
+}
+
+void SmallJobLabel::slotTimeLineFinished()
+{
+ if (m_timeLine->direction() == QTimeLine::Forward) {
+ // Show
+ m_action->setVisible(true);
+ } else {
+ // Hide
+ m_action->setVisible(false);
+ setText(QString());
+ }
+}
+
+void SmallJobLabel::slotSetJobCount(int jobCount)
+{
+ if (jobCount > 0) {
+ // prepare animation
+ setText(i18np("%1 job", "%1 jobs", jobCount));
+ setToolTip(i18np("%1 pending job", "%1 pending jobs", jobCount));
+
+ //if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
+ if (style()->styleHint(QStyle::SH_Widget_Animate, 0, this)) {
+ setFixedWidth(sizeHint().width());
+ m_action->setVisible(true);
+ return;
+ }
+
+ if (m_action->isVisible()) {
+ setFixedWidth(sizeHint().width());
+ update();
+ return;
+ }
+
+ setFixedWidth(0);
+ m_action->setVisible(true);
+ int wantedWidth = sizeHint().width();
+ setGeometry(-wantedWidth, 0, wantedWidth, height());
+ m_timeLine->setDirection(QTimeLine::Forward);
+ if (m_timeLine->state() == QTimeLine::NotRunning) {
+ m_timeLine->start();
+ }
+ }
+ else {
+ //if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
+ if (style()->styleHint(QStyle::SH_Widget_Animate, 0, this)) {
+ setFixedWidth(0);
+ m_action->setVisible(false);
+ return;
+ }
+ // hide
+ m_timeLine->setDirection(QTimeLine::Backward);
+ if (m_timeLine->state() == QTimeLine::NotRunning) {
+ m_timeLine->start();
+ }
+ }
+}
+
EventEater::EventEater(QObject *parent) : QObject(parent)
{
}
@@ -112,6 +206,23 @@ Bin::Bin(QWidget* parent) :
connect(searchLine, SIGNAL(textChanged(const QString &)), m_proxyModel, SLOT(slotSetSearchString(const QString &)));
m_toolbar->addWidget(searchLine);
+ // small info button for pending jobs
+ m_infoLabel = new SmallJobLabel(this);
+ m_infoLabel->setStyleSheet(SmallJobLabel::getStyleSheet(palette()));
+ QAction *infoAction = m_toolbar->addWidget(m_infoLabel);
+ m_jobsMenu = new QMenu(this);
+ connect(m_jobsMenu, SIGNAL(aboutToShow()), this, SLOT(slotPrepareJobsMenu()));
+ m_cancelJobs = new QAction(i18n("Cancel All Jobs"), this);
+ m_cancelJobs->setCheckable(false);
+ connect(this, SIGNAL(checkJobProcess()), this, SLOT(slotCheckJobProcess()));
+ m_discardCurrentClipJobs = new QAction(i18n("Cancel Current Clip Jobs"), this);
+ m_discardCurrentClipJobs->setCheckable(false);
+ m_jobsMenu->addAction(m_cancelJobs);
+ m_jobsMenu->addAction(m_discardCurrentClipJobs);
+ m_infoLabel->setMenu(m_jobsMenu);
+
+ m_infoLabel->setAction(infoAction);
+
// Build item view model
m_itemModel = new ProjectItemModel(this);
@@ -245,6 +356,21 @@ void Bin::deleteClip(const QString &id)
delete clip;
}
+AbstractProjectItem *Bin::getFirstSelectedClip()
+{
+ QModelIndexList indexes = m_proxyModel->selectionModel()->selectedIndexes();
+ if (indexes.isEmpty()) {
+ return NULL;
+ }
+ foreach (const QModelIndex &ix, indexes) {
+ AbstractProjectItem *currentItem = static_cast<AbstractProjectItem *>(m_proxyModel->mapToSource(ix).internalPointer());
+ if (!currentItem->isFolder()) {
+ return currentItem;
+ }
+ }
+ return NULL;
+}
+
void Bin::slotDeleteClip()
{
QModelIndexList indexes = m_proxyModel->selectionModel()->selectedIndexes();
@@ -340,6 +466,9 @@ void Bin::setDocument(KdenliveDoc* project)
connect(this, SIGNAL(producerReady(QString)), m_doc->renderer(), SLOT(slotProcessingDone(QString)));
connect(m_jobManager, SIGNAL(addClip(QString,QString,QString)), this, SLOT(slotAddUrl(QString,QString,QString)));
connect(m_proxyAction, SIGNAL(toggled(bool)), m_doc, SLOT(slotProxyCurrentItem(bool)));
+ connect(m_jobManager, SIGNAL(jobCount(int)), m_infoLabel, SLOT(slotSetJobCount(int)));
+ connect(m_discardCurrentClipJobs, SIGNAL(triggered()), m_jobManager, SLOT(slotDiscardClipJobs()));
+ connect(m_cancelJobs, SIGNAL(triggered()), m_jobManager, SLOT(slotCancelJobs()));
//connect(m_itemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), m_itemView
//connect(m_itemModel, SIGNAL(updateCurrentItem()), this, SLOT(autoSelect()));
slotInitView(NULL);
@@ -1162,3 +1291,18 @@ void Bin::slotCancelRunningJob(const QString &id, const QMap<QString, QString> &
}
+void Bin::slotPrepareJobsMenu()
+{
+ AbstractProjectItem *item = getFirstSelectedClip();
+ if (item) {
+ QString id = item->clipId();
+ m_discardCurrentClipJobs->setData(id);
+ QStringList jobs = m_jobManager->getPendingJobs(id);
+ m_discardCurrentClipJobs->setEnabled(!jobs.isEmpty());
+ } else {
+ m_discardCurrentClipJobs->setData(QString());
+ m_discardCurrentClipJobs->setEnabled(false);
+ }
+}
+
+
diff --git a/src/bin/bin.h b/src/bin/bin.h
index 1b9fcdf..ba3800b 100644
--- a/src/bin/bin.h
+++ b/src/bin/bin.h
@@ -30,10 +30,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QStyledItemDelegate>
#include <QPainter>
#include <QDomElement>
+#include <QPushButton>
class KdenliveDoc;
class ClipController;
class QSplitter;
+class QTimeLine;
class KToolBar;
class KSplitterCollapserButton;
class QMenu;
@@ -52,6 +54,33 @@ namespace Mlt {
class Producer;
};
+
+class SmallJobLabel: public QPushButton
+{
+ Q_OBJECT
+public:
+ SmallJobLabel(QWidget *parent = 0);
+ static const QString getStyleSheet(const QPalette &p);
+ void setAction(QAction *action);
+private:
+ enum ItemRole {
+ NameRole = Qt::UserRole,
+ DurationRole,
+ UsageRole
+ };
+
+ QTimeLine* m_timeLine;
+ QAction *m_action;
+
+public slots:
+ void slotSetJobCount(int jobCount);
+
+private slots:
+ void slotTimeLineChanged(qreal value);
+ void slotTimeLineFinished();
+};
+
+
/**
* @class BinItemDelegate
* @brief This class is responsible for drawing items in the QTreeView.
@@ -326,6 +355,7 @@ private slots:
void slotItemDropped(const QList<QUrl>&urls, const QModelIndex &parent);
void slotItemEdited(QModelIndex,QModelIndex,QVector<int>);
void slotAddUrl(QString url, QString,QString);
+ void slotPrepareJobsMenu();
public slots:
void slotThumbnailReady(const QString &id, const QImage &img);
@@ -385,11 +415,16 @@ private:
QAction *m_proxyAction;
QAction *m_editAction;
QAction *m_deleteAction;
+ QMenu *m_jobsMenu;
+ QAction *m_cancelJobs;
+ QAction *m_discardCurrentClipJobs;
+ SmallJobLabel *m_infoLabel;
void showClipProperties(ProjectClip *clip);
void selectModel(const QModelIndex &id);
const QStringList getFolderInfo();
/** @brief Get the QModelIndex value for an item in the Bin. */
QModelIndex getIndexForId(const QString &id, bool folderWanted) const;
+ AbstractProjectItem *getFirstSelectedClip();
signals:
void itemUpdated(AbstractProjectItem*);
diff --git a/src/project/jobs/jobmanager.cpp b/src/project/jobs/jobmanager.cpp
index 1939cd7..be641bf 100644
--- a/src/project/jobs/jobmanager.cpp
+++ b/src/project/jobs/jobmanager.cpp
@@ -258,3 +258,51 @@ void JobManager::launchJob(ProjectClip *clip, AbstractClipJob *job, bool runQueu
clip->setJobStatus(job->jobType, JobWaiting, 0, job->statusMessage());
if (runQueue) slotCheckJobProcess();
}
+
+void JobManager::slotDiscardClipJobs()
+{
+ QAction* act = qobject_cast<QAction *>(sender());
+ if (act == 0) {
+ // Cannot access triggering action, something is wrong
+ qDebug()<<"// Error in job action";
+ return;
+ }
+ QString id = act->data().toString();
+ if (id.isEmpty()) return;
+ discardJobs(id);
+}
+
+void JobManager::slotCancelJobs()
+{
+ m_abortAllJobs = true;
+ for (int i = 0; i < m_jobList.count(); ++i) {
+ m_jobList.at(i)->setStatus(JobAborted);
+ }
+ m_jobThreads.waitForFinished();
+ m_jobThreads.clearFutures();
+
+ //TODO: undo job cancelation ? not sure it's necessary
+ /*QUndoCommand *command = new QUndoCommand();
+ command->setText(i18np("Cancel job", "Cancel jobs", m_jobList.count()));
+ m_jobMutex.lock();
+ for (int i = 0; i < m_jobList.count(); ++i) {
+ DocClipBase *currentClip = m_doc->clipManager()->getClipById(m_jobList.at(i)->clipId());
+ if (!currentClip) continue;
+ QMap <QString, QString> newProps = m_jobList.at(i)->cancelProperties();
+ if (newProps.isEmpty()) continue;
+ QMap <QString, QString> oldProps = currentClip->currentProperties(newProps);
+ //TODO
+ //new EditClipCommand(this, m_jobList.at(i)->clipId(), oldProps, newProps, true, command);
+ }
+ m_jobMutex.unlock();
+ if (command->childCount() > 0) {
+ m_doc->commandStack()->push(command);
+ }
+ else delete command;
+ */
+ if (!m_jobList.isEmpty()) qDeleteAll(m_jobList);
+ m_jobList.clear();
+ m_abortAllJobs = false;
+ emit jobCount(0);
+}
+
diff --git a/src/project/jobs/jobmanager.h b/src/project/jobs/jobmanager.h
index 5655f96..47b9882 100644
--- a/src/project/jobs/jobmanager.h
+++ b/src/project/jobs/jobmanager.h
@@ -65,7 +65,7 @@ public:
* @param type the parameters for the job
*/
void prepareJobs(QList <ProjectClip *>clips, AbstractClipJob::JOBTYPE jobType, const QStringList params = QStringList());
-
+
/** @brief Filter a list of selected clips to keep only those that match the job type
* @param clips the list of selected clips
* @param jobType the jobtype requested
@@ -73,20 +73,28 @@ public:
* @returns A QMap list (id, urls) of clip that match the job type
*/
QList <ProjectClip *> filterClips(QList <ProjectClip *>clips, AbstractClipJob::JOBTYPE jobType, const QStringList &params);
-
+
/** @brief Put the job in our queue.
* @param clip the clip to whom the job will be applied
* @param job the job
* @param runQueue If true, try to start the job right now. False waits for a later command to start processing, useful when adding many jobs quickly.
*/
-
void launchJob(ProjectClip *clip, AbstractClipJob *job, bool runQueue = true);
+ /** @brief Get the list of job names for current clip. */
+ QStringList getPendingJobs(const QString &id);
+
private slots:
void slotCheckJobProcess();
void slotProcessJobs();
void slotProcessLog(const QString &id, int progress, int type, const QString &message);
+public slots:
+ /** @brief Discard jobs running on a clip whose id is in the calling action's data. */
+ void slotDiscardClipJobs();
+ /** @brief Discard all running jobs. */
+ void slotCancelJobs();
+
private:
/** @brief A pointer to the project's bin. */
Bin *m_bin;
@@ -100,8 +108,6 @@ private:
bool m_abortAllJobs;
/** @brief Stores the project's fps, useful for some jobs. */
double m_fps;
- /** @brief Get the list of job names for current clip. */
- QStringList getPendingJobs(const QString &id);
/** @brief Create a proxy for a clip. */
void createProxy(const QString &id);