1 /*
2 * Copyright (c) 2012-2020 Meltytech, LLC
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "jobsdock.h"
19 #include "ui_jobsdock.h"
20 #include "jobqueue.h"
21 #include <QtWidgets>
22 #include <Logger.h>
23 #include "dialogs/textviewerdialog.h"
24
JobsDock(QWidget * parent)25 JobsDock::JobsDock(QWidget *parent) :
26 QDockWidget(parent),
27 ui(new Ui::JobsDock)
28 {
29 LOG_DEBUG() << "begin";
30 ui->setupUi(this);
31 toggleViewAction()->setIcon(windowIcon());
32 ui->treeView->setModel(&JOBS);
33 QHeaderView* header = ui->treeView->header();
34 header->setStretchLastSection(false);
35 header->setSectionResizeMode(JobQueue::COLUMN_ICON, QHeaderView::Fixed);
36 ui->treeView->setColumnWidth(JobQueue::COLUMN_ICON, 24);
37 header->setSectionResizeMode(JobQueue::COLUMN_OUTPUT, QHeaderView::Stretch);
38 header->setSectionResizeMode(JobQueue::COLUMN_STATUS, QHeaderView::ResizeToContents);
39 ui->cleanButton->hide();
40 LOG_DEBUG() << "end";
41 }
42
~JobsDock()43 JobsDock::~JobsDock()
44 {
45 JOBS.cleanup();
46 delete ui;
47 }
48
currentJob() const49 AbstractJob *JobsDock::currentJob() const
50 {
51 QModelIndex index = ui->treeView->currentIndex();
52 if (!index.isValid()) return 0;
53 return JOBS.jobFromIndex(index);
54 }
55
onJobAdded()56 void JobsDock::onJobAdded()
57 {
58 QModelIndex index = JOBS.index(JOBS.rowCount() - 1, JobQueue::COLUMN_OUTPUT);
59 QProgressBar* progressBar = new QProgressBar;
60 progressBar->setMinimum(0);
61 progressBar->setMaximum(100);
62 progressBar->setAutoFillBackground(true);
63 progressBar->setTextVisible(false);
64 QHBoxLayout* layout = new QHBoxLayout(progressBar);
65 QLabel* label = new QLabel;
66 layout->addWidget(label);
67 layout->setContentsMargins(0, 0, 0, 0);
68 ui->treeView->setIndexWidget(index, progressBar);
69 ui->treeView->resizeColumnToContents(JobQueue::COLUMN_STATUS);
70 label->setToolTip(JOBS.data(index).toString());
71 label->setText(label->fontMetrics().elidedText(
72 JOBS.data(index).toString(), Qt::ElideMiddle, ui->treeView->columnWidth(JobQueue::COLUMN_OUTPUT)));
73 connect(JOBS.jobFromIndex(index), SIGNAL(progressUpdated(QStandardItem*, int)), SLOT(onProgressUpdated(QStandardItem*, int)));
74 show();
75 raise();
76 }
77
onProgressUpdated(QStandardItem * item,int percent)78 void JobsDock::onProgressUpdated(QStandardItem* item, int percent)
79 {
80 if (item) {
81 QModelIndex index = JOBS.index(item->row(), JobQueue::COLUMN_OUTPUT);
82 QProgressBar* progressBar = qobject_cast<QProgressBar*>(ui->treeView->indexWidget(index));
83 if (progressBar)
84 progressBar->setValue(percent);
85 }
86 }
87
resizeEvent(QResizeEvent * event)88 void JobsDock::resizeEvent(QResizeEvent *event)
89 {
90 QDockWidget::resizeEvent(event);
91 foreach (QLabel* label, ui->treeView->findChildren<QLabel*>()) {
92 label->setText(label->fontMetrics().elidedText(
93 label->toolTip(), Qt::ElideMiddle, ui->treeView->columnWidth(JobQueue::COLUMN_OUTPUT)));
94 }
95
96 }
97
on_treeView_customContextMenuRequested(const QPoint & pos)98 void JobsDock::on_treeView_customContextMenuRequested(const QPoint &pos)
99 {
100 QModelIndex index = ui->treeView->currentIndex();
101 QMenu menu(this);
102 AbstractJob* job = index.isValid()? JOBS.jobFromIndex(index) : nullptr;
103 if (job) {
104 if (job->ran() && job->state() == QProcess::NotRunning && job->exitStatus() == QProcess::NormalExit) {
105 menu.addActions(job->successActions());
106 }
107 if (job->stopped() || (JOBS.isPaused() && !job->ran()))
108 menu.addAction(ui->actionRun);
109 if (job->state() == QProcess::Running)
110 menu.addAction(ui->actionStopJob);
111 else
112 menu.addAction(ui->actionRemove);
113 if (job->ran())
114 menu.addAction(ui->actionViewLog);
115 menu.addActions(job->standardActions());
116 }
117 for (auto job : JOBS.jobs()) {
118 if (job->ran() && job->state() != QProcess::Running) {
119 menu.addAction(ui->actionRemoveFinished);
120 break;
121 }
122 }
123 menu.exec(mapToGlobal(pos));
124 }
125
on_actionStopJob_triggered()126 void JobsDock::on_actionStopJob_triggered()
127 {
128 QModelIndex index = ui->treeView->currentIndex();
129 if (!index.isValid()) return;
130 AbstractJob* job = JOBS.jobFromIndex(index);
131 if (job) job->stop();
132 }
133
on_actionViewLog_triggered()134 void JobsDock::on_actionViewLog_triggered()
135 {
136 QModelIndex index = ui->treeView->currentIndex();
137 if (!index.isValid()) return;
138 AbstractJob* job = JOBS.jobFromIndex(index);
139 if (job) {
140 TextViewerDialog dialog(this);
141 dialog.setWindowTitle(tr("Job Log"));
142 dialog.setText(job->log());
143 dialog.exec();
144 }
145 }
146
on_pauseButton_toggled(bool checked)147 void JobsDock::on_pauseButton_toggled(bool checked)
148 {
149 if (checked)
150 JOBS.pause();
151 else
152 JOBS.resume();
153 }
154
on_actionRun_triggered()155 void JobsDock::on_actionRun_triggered()
156 {
157 QModelIndex index = ui->treeView->currentIndex();
158 if (!index.isValid()) return;
159 AbstractJob* job = JOBS.jobFromIndex(index);
160 if (job) job->start();
161 }
162
on_menuButton_clicked()163 void JobsDock::on_menuButton_clicked()
164 {
165 on_treeView_customContextMenuRequested(ui->menuButton->mapToParent(QPoint(0, 0)));
166 }
167
on_treeView_doubleClicked(const QModelIndex & index)168 void JobsDock::on_treeView_doubleClicked(const QModelIndex &index)
169 {
170 AbstractJob* job = JOBS.jobFromIndex(index);
171 if (job && job->ran() && job->state() == QProcess::NotRunning && job->exitStatus() == QProcess::NormalExit) {
172 foreach (QAction* action, job->successActions()) {
173 if (action->text() == "Open") {
174 action->trigger();
175 break;
176 }
177 }
178 }
179 }
180
on_actionRemove_triggered()181 void JobsDock::on_actionRemove_triggered()
182 {
183 QModelIndex index = ui->treeView->currentIndex();
184 if (!index.isValid()) return;
185 JOBS.remove(index);
186 }
187
on_actionRemoveFinished_triggered()188 void JobsDock::on_actionRemoveFinished_triggered()
189 {
190 JOBS.removeFinished();
191 }
192
on_JobsDock_visibilityChanged(bool visible)193 void JobsDock::on_JobsDock_visibilityChanged(bool visible)
194 {
195 if (visible) {
196 foreach (QLabel* label, ui->treeView->findChildren<QLabel*>()) {
197 label->setText(label->fontMetrics().elidedText(
198 label->toolTip(), Qt::ElideMiddle, ui->treeView->columnWidth(JobQueue::COLUMN_OUTPUT)));
199 }
200 }
201 }
202