1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 10:46:35 +01:00

Greasemonkey: add script updating

- Fixed parsing @updateURL/@downloadURL
- Updating is only manual
- User have to click on update button located in Greasemonkey settings
- Update works just like download
- New version is not being checked, original script is replaced
- Fixed coding style issues

Closes #1653
This commit is contained in:
trnkava1 2016-03-19 17:16:55 +01:00
parent 3f10e6305e
commit b0b2820180
11 changed files with 128 additions and 32 deletions

View File

@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */ * ============================================================ */
#include "gm_downloader.h" #include "gm_downloader.h"
#include "gm_addscriptdialog.h"
#include "gm_manager.h" #include "gm_manager.h"
#include "gm_script.h" #include "gm_script.h"
@ -38,6 +37,11 @@ GM_Downloader::GM_Downloader(const QUrl &url, GM_Manager* manager)
connect(m_reply, SIGNAL(finished()), this, SLOT(scriptDownloaded())); connect(m_reply, SIGNAL(finished()), this, SLOT(scriptDownloaded()));
} }
void GM_Downloader::updateScript(const QString &fileName)
{
m_fileName = fileName;
}
void GM_Downloader::scriptDownloaded() void GM_Downloader::scriptDownloaded()
{ {
if (m_reply != qobject_cast<FollowRedirectReply*>(sender())) { if (m_reply != qobject_cast<FollowRedirectReply*>(sender())) {
@ -52,13 +56,15 @@ void GM_Downloader::scriptDownloaded()
const QByteArray response = QString::fromUtf8(m_reply->readAll()).toUtf8(); const QByteArray response = QString::fromUtf8(m_reply->readAll()).toUtf8();
if (response.contains(QByteArray("// ==UserScript=="))) { if (response.contains(QByteArray("// ==UserScript=="))) {
const QString filePath = QString("%1/%2").arg(m_manager->scriptsDirectory(), QzTools::getFileNameFromUrl(m_reply->url())); if (m_fileName.isEmpty()) {
m_fileName = QzTools::ensureUniqueFilename(filePath); const QString filePath = QString("%1/%2").arg(m_manager->scriptsDirectory(), QzTools::getFileNameFromUrl(m_reply->url()));
m_fileName = QzTools::ensureUniqueFilename(filePath);
}
QFile file(m_fileName); QFile file(m_fileName);
if (!file.open(QFile::WriteOnly)) { if (!file.open(QFile::WriteOnly)) {
qWarning() << "GreaseMonkey: Cannot open file for writing" << m_fileName; qWarning() << "GreaseMonkey: Cannot open file for writing" << m_fileName;
emit error();
deleteLater(); deleteLater();
return; return;
} }
@ -91,6 +97,7 @@ void GM_Downloader::scriptDownloaded()
void GM_Downloader::requireDownloaded() void GM_Downloader::requireDownloaded()
{ {
if (m_reply != qobject_cast<FollowRedirectReply*>(sender())) { if (m_reply != qobject_cast<FollowRedirectReply*>(sender())) {
emit error();
deleteLater(); deleteLater();
return; return;
} }
@ -109,6 +116,7 @@ void GM_Downloader::requireDownloaded()
if (!file.open(QFile::WriteOnly)) { if (!file.open(QFile::WriteOnly)) {
qWarning() << "GreaseMonkey: Cannot open file for writing" << fileName; qWarning() << "GreaseMonkey: Cannot open file for writing" << fileName;
emit error();
deleteLater(); deleteLater();
return; return;
} }
@ -135,24 +143,7 @@ void GM_Downloader::downloadRequires()
connect(m_reply, SIGNAL(finished()), this, SLOT(requireDownloaded())); connect(m_reply, SIGNAL(finished()), this, SLOT(requireDownloaded()));
} }
else { else {
bool deleteScript = true; emit finished(m_fileName);
GM_Script* script = new GM_Script(m_manager, m_fileName);
if (script->isValid()) {
if (!m_manager->containsScript(script->fullName())) {
GM_AddScriptDialog dialog(m_manager, script);
deleteScript = dialog.exec() != QDialog::Accepted;
}
else {
m_manager->showNotification(tr("'%1' is already installed").arg(script->name()));
}
}
if (deleteScript) {
delete script;
QFile(m_fileName).remove();
}
deleteLater(); deleteLater();
} }
} }

View File

@ -32,6 +32,12 @@ class GM_Downloader : public QObject
public: public:
explicit GM_Downloader(const QUrl &url, GM_Manager* manager); explicit GM_Downloader(const QUrl &url, GM_Manager* manager);
void updateScript(const QString& fileName);
signals:
void finished(const QString& fileName);
void error();
private slots: private slots:
void scriptDownloaded(); void scriptDownloaded();
void requireDownloaded(); void requireDownloaded();

View File

@ -20,6 +20,7 @@
#include "gm_downloader.h" #include "gm_downloader.h"
#include "gm_icon.h" #include "gm_icon.h"
#include "gm_urlinterceptor.h" #include "gm_urlinterceptor.h"
#include "gm_addscriptdialog.h"
#include "settings/gm_settings.h" #include "settings/gm_settings.h"
#include "browserwindow.h" #include "browserwindow.h"
@ -256,7 +257,25 @@ void GM_Manager::scriptChanged()
void GM_Manager::doDownloadScript(const QUrl &url) void GM_Manager::doDownloadScript(const QUrl &url)
{ {
new GM_Downloader(url, this); GM_Downloader *downloader = new GM_Downloader(url, this);
connect(downloader, &GM_Downloader::finished, this, [=](const QString &fileName) {
bool deleteScript = true;
GM_Script *script = new GM_Script(this, fileName);
if (script->isValid()) {
if (!containsScript(script->fullName())) {
GM_AddScriptDialog dialog(this, script);
deleteScript = dialog.exec() != QDialog::Accepted;
}
else {
showNotification(tr("'%1' is already installed").arg(script->name()));
}
}
if (deleteScript) {
delete script;
QFile(fileName).remove();
}
});
} }
bool GM_Manager::canRunOnScheme(const QString &scheme) bool GM_Manager::canRunOnScheme(const QString &scheme)

View File

@ -17,9 +17,12 @@
* ============================================================ */ * ============================================================ */
#include "gm_script.h" #include "gm_script.h"
#include "gm_manager.h" #include "gm_manager.h"
#include "gm_downloader.h"
#include "qzregexp.h" #include "qzregexp.h"
#include "delayedfilewatcher.h" #include "delayedfilewatcher.h"
#include "followredirectreply.h"
#include "mainapplication.h"
#include <QFile> #include <QFile>
#include <QStringList> #include <QStringList>
@ -36,6 +39,7 @@ GM_Script::GM_Script(GM_Manager* manager, const QString &filePath)
, m_fileName(filePath) , m_fileName(filePath)
, m_enabled(true) , m_enabled(true)
, m_valid(false) , m_valid(false)
, m_updating(false)
{ {
parseScript(); parseScript();
@ -148,6 +152,31 @@ QWebEngineScript GM_Script::webScript() const
return script; return script;
} }
bool GM_Script::isUpdating()
{
return m_updating;
}
void GM_Script::updateScript()
{
if (!m_downloadUrl.isValid() || m_updating)
return;
m_updating = true;
emit updatingChanged(m_updating);
GM_Downloader *downloader = new GM_Downloader(m_downloadUrl, m_manager);
downloader->updateScript(m_fileName);
connect(downloader, &GM_Downloader::finished, this, [this]() {
m_updating = false;
emit updatingChanged(m_updating);
});
connect(downloader, &GM_Downloader::error, this, [this]() {
m_updating = false;
emit updatingChanged(m_updating);
});
}
void GM_Script::watchedFileChanged(const QString &file) void GM_Script::watchedFileChanged(const QString &file)
{ {
if (m_fileName == file) { if (m_fileName == file) {
@ -254,6 +283,9 @@ void GM_Script::parseScript()
m_version = value; m_version = value;
} }
else if (key == QLatin1String("@updateURL")) { else if (key == QLatin1String("@updateURL")) {
m_updateUrl = QUrl(value);
}
else if (key == QLatin1String("@downloadURL")) {
m_downloadUrl = QUrl(value); m_downloadUrl = QUrl(value);
} }
else if (key == QLatin1String("@include") || key == QLatin1String("@match")) { else if (key == QLatin1String("@include") || key == QLatin1String("@match")) {
@ -276,12 +308,6 @@ void GM_Script::parseScript()
m_startAt = DocumentIdle; m_startAt = DocumentIdle;
} }
} }
else if (key == QLatin1String("@downloadURL") && m_downloadUrl.isEmpty()) {
m_downloadUrl = QUrl(value);
}
else if (key == QLatin1String("@updateURL") && m_updateUrl.isEmpty()) {
m_updateUrl = QUrl(value);
}
} }
if (m_include.isEmpty()) { if (m_include.isEmpty()) {

View File

@ -62,8 +62,12 @@ public:
QWebEngineScript webScript() const; QWebEngineScript webScript() const;
bool isUpdating();
void updateScript();
signals: signals:
void scriptChanged(); void scriptChanged();
void updatingChanged(bool updating);
private slots: private slots:
void watchedFileChanged(const QString &file); void watchedFileChanged(const QString &file);
@ -91,6 +95,7 @@ private:
QString m_fileName; QString m_fileName;
bool m_enabled; bool m_enabled;
bool m_valid; bool m_valid;
bool m_updating;
}; };
#endif // GM_SCRIPT_H #endif // GM_SCRIPT_H

View File

@ -38,6 +38,8 @@ GM_Settings::GM_Settings(GM_Manager* manager, QWidget* parent)
connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
this, SLOT(showItemInfo(QListWidgetItem*))); this, SLOT(showItemInfo(QListWidgetItem*)));
connect(ui->listWidget, SIGNAL(updateItemRequested(QListWidgetItem*)),
this, SLOT(updateItem(QListWidgetItem*)));
connect(ui->listWidget, SIGNAL(removeItemRequested(QListWidgetItem*)), connect(ui->listWidget, SIGNAL(removeItemRequested(QListWidgetItem*)),
this, SLOT(removeItem(QListWidgetItem*))); this, SLOT(removeItem(QListWidgetItem*)));
connect(ui->openDirectory, SIGNAL(clicked()), connect(ui->openDirectory, SIGNAL(clicked()),
@ -69,6 +71,15 @@ void GM_Settings::showItemInfo(QListWidgetItem* item)
dialog->open(); dialog->open();
} }
void GM_Settings::updateItem(QListWidgetItem* item)
{
GM_Script *script = getScript(item);
if (!script) {
return;
}
script->updateScript();
}
void GM_Settings::removeItem(QListWidgetItem* item) void GM_Settings::removeItem(QListWidgetItem* item)
{ {
GM_Script* script = getScript(item); GM_Script* script = getScript(item);
@ -148,6 +159,8 @@ void GM_Settings::loadScripts()
item->setText(script->name()); item->setText(script->name());
item->setData(Qt::UserRole, script->version()); item->setData(Qt::UserRole, script->version());
item->setData(Qt::UserRole + 1, script->description()); item->setData(Qt::UserRole + 1, script->description());
item->setData(Qt::UserRole + 2, !script->downloadUrl().isEmpty());
item->setData(Qt::UserRole + 3, script->isUpdating());
item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(script->isEnabled() ? Qt::Checked : Qt::Unchecked); item->setCheckState(script->isEnabled() ? Qt::Checked : Qt::Unchecked);

View File

@ -40,6 +40,7 @@ public:
private slots: private slots:
void showItemInfo(QListWidgetItem* item); void showItemInfo(QListWidgetItem* item);
void updateItem(QListWidgetItem* item);
void removeItem(QListWidgetItem* item); void removeItem(QListWidgetItem* item);
void itemChanged(QListWidgetItem* item); void itemChanged(QListWidgetItem* item);

View File

@ -29,6 +29,7 @@ GM_SettingsListDelegate::GM_SettingsListDelegate(QObject* parent)
, m_padding(0) , m_padding(0)
{ {
m_removePixmap = IconProvider::standardIcon(QStyle::SP_DialogCloseButton).pixmap(16); m_removePixmap = IconProvider::standardIcon(QStyle::SP_DialogCloseButton).pixmap(16);
m_updateIcon = IconProvider::standardIcon(QStyle::SP_BrowserReload);
} }
int GM_SettingsListDelegate::padding() const int GM_SettingsListDelegate::padding() const
@ -63,6 +64,8 @@ void GM_SettingsListDelegate::paint(QPainter* painter, const QStyleOptionViewIte
int leftPosition = m_padding; int leftPosition = m_padding;
int rightPosition = opt.rect.right() - m_padding - 16; // 16 for remove button int rightPosition = opt.rect.right() - m_padding - 16; // 16 for remove button
if (index.data(Qt::UserRole + 2).toBool())
rightPosition -= m_padding + 16; // 16 for update button
// Draw background // Draw background
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, w); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, w);
@ -109,6 +112,16 @@ void GM_SettingsListDelegate::paint(QPainter* painter, const QStyleOptionViewIte
painter->setFont(opt.font); painter->setFont(opt.font);
style->drawItemText(painter, infoRect, Qt::TextSingleLine | Qt::AlignLeft, opt.palette, true, info, colorRole); style->drawItemText(painter, infoRect, Qt::TextSingleLine | Qt::AlignLeft, opt.palette, true, info, colorRole);
// Draw update button
if (index.data(Qt::UserRole + 2).toBool()) {
const int updateIconSize = 16;
const int updateIconYPos = center - (updateIconSize / 2);
const QPixmap updatePixmap = m_updateIcon.pixmap(16, index.data(Qt::UserRole + 3).toBool() ? QIcon::Disabled : QIcon::Normal);
QRect updateIconRect(rightPosition, updateIconYPos, updateIconSize, updateIconSize);
painter->drawPixmap(updateIconRect, updatePixmap);
rightPosition += m_padding + 16;
}
// Draw remove button // Draw remove button
const int removeIconSize = 16; const int removeIconSize = 16;
const int removeIconYPos = center - (removeIconSize / 2); const int removeIconYPos = center - (removeIconSize / 2);

View File

@ -32,6 +32,7 @@ public:
private: private:
QPixmap m_removePixmap; QPixmap m_removePixmap;
QIcon m_updateIcon;
mutable int m_rowHeight; mutable int m_rowHeight;
mutable int m_padding; mutable int m_padding;

View File

@ -36,15 +36,18 @@ void GM_SettingsListWidget::mousePressEvent(QMouseEvent* event)
return; return;
} }
if (containsUpdateIcon(event->pos())) {
emit updateItemRequested(itemAt(event->pos()));
return;
}
QListWidget::mousePressEvent(event); QListWidget::mousePressEvent(event);
} }
void GM_SettingsListWidget::mouseDoubleClickEvent(QMouseEvent* event) void GM_SettingsListWidget::mouseDoubleClickEvent(QMouseEvent* event)
{ {
if (containsRemoveIcon(event->pos())) { if (containsRemoveIcon(event->pos()) || containsUpdateIcon(event->pos()))
emit removeItemRequested(itemAt(event->pos()));
return; return;
}
QListWidget::mouseDoubleClickEvent(event); QListWidget::mouseDoubleClickEvent(event);
} }
@ -65,3 +68,19 @@ bool GM_SettingsListWidget::containsRemoveIcon(const QPoint &pos) const
return removeIconRect.contains(pos); return removeIconRect.contains(pos);
} }
bool GM_SettingsListWidget::containsUpdateIcon(const QPoint &pos) const
{
QListWidgetItem *item = itemAt(pos);
if (!item || !item->data(Qt::UserRole + 2).toBool())
return false;
const QRect rect = visualItemRect(item);
const int updateIconPosition = rect.right() - m_delegate->padding() * 2 - 16 * 2;
const int center = rect.height() / 2 + rect.top();
const int updateIconYPos = center - (16 / 2);
QRect updateIconRect(updateIconPosition, updateIconYPos, 16, 16);
return updateIconRect.contains(pos);
}

View File

@ -30,11 +30,13 @@ public:
signals: signals:
void removeItemRequested(QListWidgetItem* item); void removeItemRequested(QListWidgetItem* item);
void updateItemRequested(QListWidgetItem* item);
public slots: public slots:
private: private:
bool containsRemoveIcon(const QPoint &pos) const; bool containsRemoveIcon(const QPoint &pos) const;
bool containsUpdateIcon(const QPoint &pos) const;
void mousePressEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event);
void mouseDoubleClickEvent(QMouseEvent* event); void mouseDoubleClickEvent(QMouseEvent* event);