Skip to content
Snippets Groups Projects
Commit b7408564 authored by akiraohgaki's avatar akiraohgaki Committed by GitHub
Browse files

Merge pull request #20 from xdgurl/development-qt

Development qt
parents 3986bf5b 33aa8f72
No related branches found
No related tags found
No related merge requests found
Showing with 639 additions and 51 deletions
*.pro.user
SHELL = /bin/sh
TARGET = xdgurl
srcdir = ./src
DESTDIR =
prefix = /usr/local
exec_prefix = $(prefix)
bindir = $(exec_prefix)/bin
datadir = $(prefix)/share
INSTALL = install
INSTALL_PROGRAM = $(INSTALL) -D -m 755
INSTALL_DATA = $(INSTALL) -D -m 644
RM = rm -f
.PHONY: all rebuild build clean install uninstall
all: rebuild ;
rebuild: clean build ;
build: $(TARGET) ;
clean:
$(RM) ./$(TARGET)
install: build
$(INSTALL_PROGRAM) ./$(TARGET) $(DESTDIR)$(bindir)/$(TARGET)
$(INSTALL_DATA) $(srcdir)/desktop/$(TARGET).desktop $(DESTDIR)$(datadir)/applications/$(TARGET).desktop
$(INSTALL_DATA) $(srcdir)/desktop/$(TARGET).svg $(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/$(TARGET).svg
uninstall:
$(RM) $(DESTDIR)$(bindir)/$(TARGET)
$(RM) $(DESTDIR)$(datadir)/applications/$(TARGET).desktop
$(RM) $(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/$(TARGET).svg
$(TARGET):
# Just copy for now
install -m 755 $(srcdir)/$(TARGET).py ./$(TARGET)
unix:!android {
isEmpty(PREFIX) {
PREFIX = /usr/local
}
SRCDIR = src
BINDIR = $${PREFIX}/bin
DATADIR = $${PREFIX}/share
target.path = $${BINDIR}
desktop.files = $${SRCDIR}/desktop/$${TARGET}.desktop
desktop.path = $${DATADIR}/applications
icon.files = $${SRCDIR}/desktop/$${TARGET}.svg
icon.path = $${DATADIR}/icons/hicolor/scalable/apps
INSTALLS += target desktop icon
}
export(INSTALLS)
......@@ -7,7 +7,7 @@ pkgdesc="An install helper program for desktop stuff."
arch=('i686' 'x86_64')
url="https://github.com/xdgurl/xdgurl"
license=('GPL3')
depends=('tk')
depends=('qt5-base>=5.3.0' 'qt5-declarative>=5.3.0' 'qt5-svg>=5.3.0' 'qt5-quickcontrols>=5.3.0')
#source=("https://github.com/xdgurl/xdgurl/archive/release-$pkgver.tar.gz")
source=("$pkgname.tar.gz")
md5sums=() #autofill using updpkgsums
......@@ -15,11 +15,12 @@ md5sums=() #autofill using updpkgsums
build() {
#cd "$pkgname-release-$pkgver"
cd $pkgname
qmake PREFIX="/usr"
make
}
package() {
#cd "$pkgname-release-$pkgver"
cd $pkgname
make DESTDIR="$pkgdir" prefix="/usr" install
make INSTALL_ROOT="$pkgdir" install
}
......@@ -5,7 +5,8 @@ cd `dirname $0`
build_ubuntu() {
mkdir ./build
cp -r ../src ./build/
cp ../Makefile ./build/
cp ../*.pro ./build/
cp ../*.pri ./build/
cp -r ./ubuntu/debian ./build/
cd ./build
debuild -uc -us -b
......
......@@ -9,7 +9,7 @@ URL: https://github.com/xdgurl/xdgurl
#Source0: https://github.com/xdgurl/xdgurl/archive/release-%{version}.tar.gz
Source0: %{name}.tar.gz
Requires: tkinter, python3-tkinter
Requires: qt5-qtbase >= 5.3.0, qt5-qtsvg >= 5.3.0, qt5-qtdeclarative >= 5.3.0, qt5-qtquickcontrols >= 5.3.0
%description
An install helper program for desktop stuff.
......@@ -20,10 +20,11 @@ An install helper program for desktop stuff.
%build
%define debug_package %{nil}
qmake PREFIX="/usr"
make
%install
make DESTDIR="%{buildroot}" prefix="/usr" install
make INSTALL_ROOT="%{buildroot}" install
%files
%defattr(-,root,root)
......
......@@ -2,11 +2,11 @@ Source: xdgurl
Section: web
Priority: optional
Maintainer: Akira Ohgaki <akiraohgaki@gmail.com>
Build-Depends: build-essential (>= 11), devscripts (>= 2.14), debhelper (>= 9), fakeroot (>= 1.20)
Build-Depends: build-essential (>= 11), qt5-default (>= 5.3.0), qtdeclarative5-dev (>= 5.3.0), libqt5svg5-dev (>= 5.3.0), devscripts (>= 2.14), debhelper (>= 9), fakeroot (>= 1.20)
Standards-Version: 3.9.4
Package: xdgurl
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, python-tk (>= 2.7.0), python3-tk (>= 3.2.0)
Depends: ${shlibs:Depends}, ${misc:Depends}, libqt5svg5 (>= 5.3.0), qtdeclarative5-qtquick2-plugin (>= 5.3.0), qtdeclarative5-window-plugin (>= 5.3.0), qtdeclarative5-controls-plugin (>= 5.3.0), qtdeclarative5-dialogs-plugin (>= 5.3.0)
Description: xdgurl
An install helper program for desktop stuff.
......@@ -3,8 +3,8 @@
%:
dh $@
override_dh_auto_install:
make DESTDIR="$(CURDIR)/debian/tmp" prefix="/usr" install
override_dh_auto_configure:
qmake PREFIX="/usr"
override_dh_shlibdeps:
# ignore
override_dh_auto_install:
make INSTALL_ROOT="$(CURDIR)/debian/tmp" install
unix:!android {
QMAKE_LFLAGS += -Wl,-rpath=\\\$\$ORIGIN
QMAKE_LFLAGS += -Wl,-rpath=/usr/lib/$${TARGET}
QMAKE_RPATH =
}
<RCC>
<qresource prefix="/">
<file>configs/application.json</file>
<file>configs/destinations.json</file>
<file>configs/destinations_alias.json</file>
</qresource>
</RCC>
{
"id": "xdgurl",
"name": "xdgurl",
"version": "1.1.0",
"organization": "xdgurl",
"domain": "com.xdgurl.xdgurl",
"icon": ":/desktop/xdgurl.svg",
"description": "An install helper program for desktop stuff.",
"license": "GPL-3+",
"author": "Akira Ohgaki",
"contact": "akiraohgaki@gmail.com",
"homepage": "https://github.com/xdgurl/xdgurl"
}
{
"downloads": "$HOME/Downloads",
"documents": "$HOME/Documents",
"pictures": "$HOME/Pictures",
"music": "$HOME/Music",
"videos": "$HOME/Videos",
"wallpapers": "$XDG_DATA_HOME/wallpapers",
"fonts": "$HOME/.fonts",
"cursors": "$HOME/.icons",
"icons": "$XDG_DATA_HOME/icons",
"emoticons": "$XDG_DATA_HOME/emoticons",
"themes": "$HOME/.themes",
"emerald_themes": "$HOME/.emerald/themes",
"enlightenment_themes": "$HOME/.e/e/themes",
"enlightenment_backgrounds": "$HOME/.e/e/backgrounds",
"fluxbox_styles": "$HOME/.fluxbox/styles",
"pekwm_themes": "$HOME/.pekwm/themes",
"icewm_themes": "$HOME/.icewm/themes",
"plasma_plasmoids": "$XDG_DATA_HOME/plasma/plasmoids",
"plasma_look_and_feel": "$XDG_DATA_HOME/plasma/look-and-feel",
"plasma_desktopthemes": "$XDG_DATA_HOME/plasma/desktoptheme",
"kwin_effects": "$XDG_DATA_HOME/kwin/effects",
"kwin_scripts": "$XDG_DATA_HOME/kwin/scripts",
"kwin_tabbox": "$XDG_DATA_HOME/kwin/tabbox",
"aurorae_themes": "$XDG_DATA_HOME/aurorae/themes",
"dekorator_themes": "$XDG_DATA_HOME/deKorator/themes",
"qtcurve": "$XDG_DATA_HOME/QtCurve",
"color_schemes": "$XDG_DATA_HOME/color-schemes",
"gnome_shell_extensions": "$XDG_DATA_HOME/gnome-shell/extensions",
"cinnamon_applets": "$XDG_DATA_HOME/cinnamon/applets",
"cinnamon_desklets": "$XDG_DATA_HOME/cinnamon/desklets",
"cinnamon_extensions": "$XDG_DATA_HOME/cinnamon/extensions",
"nautilus_scripts": "$XDG_DATA_HOME/nautilus/scripts",
"amarok_scripts": "$KDEHOME/share/apps/amarok/scripts",
"yakuake_skins": "$KDEHOME/share/apps/yakuake/skins",
"cairo_clock_themes": "$HOME/.cairo-clock/themes"
}
{
"gnome_shell_themes": "themes",
"cinnamon_themes": "themes",
"gtk2_themes": "themes",
"gtk3_themes": "themes",
"metacity_themes": "themes",
"xfwm4_themes": "themes",
"openbox_themes": "themes",
"kvantum_themes": "themes",
"compiz_themes": "emerald_themes",
"beryl_themes": "emerald_themes",
"plasma4_plasmoids": "plasma_plasmoids",
"plasma5_plasmoids": "plasma_plasmoids",
"plasma5_look_and_feel": "plasma_look_and_feel",
"plasma5_desktopthemes": "plasma_desktopthemes",
"plasma_color_schemes": "color_schemes"
}
#include "../utility/file.h"
#include "../utility/json.h"
#include "config.h"
namespace Core {
Config::Config(const QString &configsDir, QObject *parent) :
QObject(parent), _configsDir(configsDir)
{}
QJsonObject Config::get(const QString &name)
{
QString configFile = _configsDir + "/" + name + ".json";
if (!_cacheData.contains(name)) {
QString json = Utility::File::readText(configFile);
if (json.isEmpty()) {
json = "{}"; // Blank JSON data as default
}
_cacheData[name] = Utility::Json::convertStrToObj(json);
}
return _cacheData[name].toObject();
}
bool Config::set(const QString &name, const QJsonObject &jsonObj)
{
QString configFile = _configsDir + "/" + name + ".json";
QString json = Utility::Json::convertObjToStr(jsonObj);
Utility::File::makeDir(_configsDir);
if (Utility::File::writeText(configFile, json)) {
_cacheData[name] = jsonObj;
return true;
}
return false;
}
} // namespace Core
#ifndef CORE_CONFIG_H
#define CORE_CONFIG_H
#include <QObject>
#include <QJsonObject>
namespace Core {
class Config : public QObject
{
Q_OBJECT
private:
QString _configsDir;
QJsonObject _cacheData;
public:
explicit Config(const QString &configsDir, QObject *parent = 0);
QJsonObject get(const QString &name);
bool set(const QString &name, const QJsonObject &jsonObj);
};
} // namespace Core
#endif // CORE_CONFIG_H
#include <QEventLoop>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include "network.h"
namespace Core {
Network::Network(const bool &async, QObject *parent) :
QObject(parent), _async(async)
{
_manager = new QNetworkAccessManager();
connect(_manager, &QNetworkAccessManager::finished,
this, &Network::_finished);
if (!_async) {
_eventLoop = new QEventLoop();
connect(_manager, &QNetworkAccessManager::finished,
_eventLoop, &QEventLoop::quit);
}
}
Network::~Network()
{
_manager->deleteLater();
if (!_async) {
delete _eventLoop;
}
}
QNetworkReply *Network::head(const QUrl &uri)
{
QNetworkReply *reply = _manager->head(QNetworkRequest(uri));
if (!_async) {
_eventLoop->exec();
}
return reply;
}
QNetworkReply *Network::get(const QUrl &uri)
{
QNetworkReply *reply = _manager->get(QNetworkRequest(uri));
connect(reply, &QNetworkReply::downloadProgress,
this, &Network::_downloadProgress);
if (!_async) {
_eventLoop->exec();
}
return reply;
}
/**
* Private slots
*/
void Network::_finished(QNetworkReply *reply)
{
emit finished(reply);
}
void Network::_downloadProgress(const qint64 &received, const qint64 &total)
{
emit downloadProgress(received, total);
}
} // namespace Core
#ifndef CORE_NETWORK_H
#define CORE_NETWORK_H
#include <QObject>
class QEventLoop;
class QNetworkAccessManager;
class QNetworkReply;
namespace Core {
class Network : public QObject
{
Q_OBJECT
private:
bool _async;
QNetworkAccessManager *_manager;
QEventLoop *_eventLoop;
public:
explicit Network(const bool &async = true, QObject *parent = 0);
~Network();
QNetworkReply *head(const QUrl &uri);
QNetworkReply *get(const QUrl &uri);
private slots:
void _finished(QNetworkReply *reply);
void _downloadProgress(const qint64 &received, const qint64 &total);
signals:
void finished(QNetworkReply *reply);
void downloadProgress(const qint64 &received, const qint64 &total);
};
} // namespace Core
#endif // CORE_NETWORK_H
<RCC>
<qresource prefix="/">
<file>desktop/xdgurl.svg</file>
</qresource>
</RCC>
#include <QUrl>
#include <QUrlQuery>
#include <QTemporaryFile>
#include <QMimeDatabase>
#include <QNetworkReply>
#include "../core/config.h"
#include "../core/network.h"
#include "../utility/file.h"
#include "../utility/json.h"
#include "../utility/package.h"
#include "xdgurl.h"
namespace Handlers {
XdgUrl::XdgUrl(const QString &xdgUrl, Core::Config *config, Core::Network *network, QObject *parent) :
QObject(parent), _xdgUrl(xdgUrl), _config(config), _network(network)
{
_parse();
_loadDestinations();
connect(_network, &Core::Network::finished, this, &XdgUrl::_downloaded);
connect(_network, &Core::Network::downloadProgress, this, &XdgUrl::downloadProgress);
}
void XdgUrl::_parse()
{
QUrl url(_xdgUrl);
QUrlQuery query(url);
_metadata["scheme"] = QString("xdg");
_metadata["command"] = QString("download");
_metadata["url"] = QString("");
_metadata["type"] = QString("downloads");
_metadata["filename"] = QString("");
if (!url.scheme().isEmpty()) {
_metadata["scheme"] = url.scheme();
}
if (!url.host().isEmpty()) {
_metadata["command"] = url.host();
}
if (query.hasQueryItem("url") && !query.queryItemValue("url").isEmpty()) {
_metadata["url"] = query.queryItemValue("url", QUrl::FullyDecoded);
}
if (query.hasQueryItem("type") && !query.queryItemValue("type").isEmpty()) {
_metadata["type"] = query.queryItemValue("type", QUrl::FullyDecoded);
}
if (query.hasQueryItem("filename") && !query.queryItemValue("filename").isEmpty()) {
_metadata["filename"] = QUrl(query.queryItemValue("filename", QUrl::FullyDecoded)).fileName();
}
if (!_metadata["url"].toString().isEmpty() && _metadata["filename"].toString().isEmpty()) {
_metadata["filename"] = QUrl(_metadata["url"].toString()).fileName();
}
}
void XdgUrl::_loadDestinations()
{
QJsonObject configDestinations = _config->get("destinations");
QJsonObject configDestinationsAlias = _config->get("destinations_alias");
foreach (const QString key, configDestinations.keys()) {
_destinations[key] = _convertPathString(configDestinations[key].toString());
}
foreach (const QString key, configDestinationsAlias.keys()) {
QString value = configDestinationsAlias[key].toString();
if (_destinations.contains(value)) {
_destinations[key] = _destinations.value(value);
}
}
}
QString XdgUrl::_convertPathString(const QString &path)
{
QString newPath = path;
if (newPath.contains("$HOME")) {
newPath.replace("$HOME", Utility::File::homePath());
}
else if (newPath.contains("$XDG_DATA_HOME")) {
newPath.replace("$XDG_DATA_HOME", Utility::File::xdgDataHomePath());
}
else if (newPath.contains("$KDEHOME")) {
newPath.replace("$KDEHOME", Utility::File::kdehomePath());
}
return newPath;
}
void XdgUrl::_saveDownloadedFile(QNetworkReply *reply)
{
QJsonObject result;
QTemporaryFile temporaryFile;
if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) {
result["status"] = QString("error_save");
result["message"] = temporaryFile.errorString();
emit error(Utility::Json::convertObjToStr(result));
return;
}
QMimeDatabase mimeDb;
QString mimeType = mimeDb.mimeTypeForFile(temporaryFile.fileName()).name();
if (mimeType == "text/html" || mimeType == "application/xhtml+xml") {
result["status"] = QString("error_filetype");
result["message"] = QString("The file is unsupported file type " + mimeType);
emit error(Utility::Json::convertObjToStr(result));
return;
}
QString type = _metadata["type"].toString();
QString destination = _destinations[type].toString();
QString path = destination + "/" + _metadata["filename"].toString();
Utility::File::makeDir(destination);
Utility::File::remove(path); // Remove previous downloaded file
if (!temporaryFile.copy(path)) {
result["status"] = QString("error_save");
result["message"] = temporaryFile.errorString();
emit error(Utility::Json::convertObjToStr(result));
return;
}
result["status"] = QString("success_download");
result["message"] = QString("The file has been stored into " + destination);
emit finished(Utility::Json::convertObjToStr(result));
}
void XdgUrl::_installDownloadedFile(QNetworkReply *reply)
{
QJsonObject result;
QTemporaryFile temporaryFile;
if (!temporaryFile.open() || temporaryFile.write(reply->readAll()) == -1) {
result["status"] = QString("error_save");
result["message"] = temporaryFile.errorString();
emit error(Utility::Json::convertObjToStr(result));
return;
}
QMimeDatabase mimeDb;
QString mimeType = mimeDb.mimeTypeForFile(temporaryFile.fileName()).name();
if (mimeType == "text/html" || mimeType == "application/xhtml+xml") {
result["status"] = QString("error_filetype");
result["message"] = QString("The file is unsupported file type " + mimeType);
emit error(Utility::Json::convertObjToStr(result));
return;
}
QString type = _metadata["type"].toString();
QString destination = _destinations[type].toString();
QString path = destination + "/" + _metadata["filename"].toString();
Utility::File::makeDir(destination);
Utility::File::remove(path); // Remove previous downloaded file
if ((type == "plasma_plasmoids" || type == "plasma4_plasmoids" || type == "plasma5_plasmoids")
&& Utility::Package::installPlasmapkg(temporaryFile.fileName(), "plasmoid")) {
result["message"] = QString("The plasmoid has been installed");
}
else if ((type == "plasma_look_and_feel" || type == "plasma5_look_and_feel")
&& Utility::Package::installPlasmapkg(temporaryFile.fileName(), "lookandfeel")) {
result["message"] = QString("The plasma look and feel has been installed");
}
else if ((type == "plasma_desktopthemes" || type == "plasma5_desktopthemes")
&& Utility::Package::installPlasmapkg(temporaryFile.fileName(), "theme")) {
result["message"] = QString("The plasma desktop theme has been installed");
}
else if (type == "kwin_effects"
&& Utility::Package::installPlasmapkg(temporaryFile.fileName(), "kwineffect")) {
result["message"] = QString("The KWin effect has been installed");
}
else if (type == "kwin_scripts"
&& Utility::Package::installPlasmapkg(temporaryFile.fileName(), "kwinscript")) {
result["message"] = QString("The KWin script has been installed");
}
else if (type == "kwin_tabbox"
&& Utility::Package::installPlasmapkg(temporaryFile.fileName(), "windowswitcher")) {
result["message"] = QString("The KWin window switcher has been installed");
}
else if (Utility::Package::uncompressArchive(temporaryFile.fileName(), destination)) {
result["message"] = QString("The archive file has been uncompressed into " + destination);
}
else if (temporaryFile.copy(path)) {
result["message"] = QString("The file has been stored into " + destination);
}
else {
result["status"] = QString("error_install");
result["message"] = temporaryFile.errorString();
emit error(Utility::Json::convertObjToStr(result));
return;
}
result["status"] = QString("success_install");
emit finished(Utility::Json::convertObjToStr(result));
}
/**
* Private slots
*/
void XdgUrl::_downloaded(QNetworkReply *reply)
{
if (reply->error() != QNetworkReply::NoError) {
QJsonObject result;
result["status"] = QString("error_network");
result["message"] = reply->errorString();
emit error(Utility::Json::convertObjToStr(result));
return;
}
// If the network reply has a refresh header, retry download
if (reply->hasRawHeader("Refresh")) {
QString refreshUrl = QString(reply->rawHeader("Refresh")).split("url=").last();
if (refreshUrl.startsWith("/")) {
refreshUrl = reply->url().authority() + refreshUrl;
}
_network->get(QUrl(refreshUrl));
return;
}
if (_metadata["command"].toString() == "download") {
_saveDownloadedFile(reply);
}
else if (_metadata["command"].toString() == "install") {
_installDownloadedFile(reply);
}
}
/**
* Public slots
*/
QString XdgUrl::getXdgUrl()
{
return _xdgUrl;
}
QString XdgUrl::getMetadata()
{
return Utility::Json::convertObjToStr(_metadata);
}
bool XdgUrl::isValid()
{
QString scheme = _metadata["scheme"].toString();
QString command = _metadata["command"].toString();
QString url = _metadata["url"].toString();
QString type = _metadata["type"].toString();
QString filename = _metadata["filename"].toString();
if ((scheme == "xdg" || scheme == "xdgs")
&& (command == "download" || command == "install")
&& QUrl(url).isValid()
&& _destinations.contains(type)
&& !filename.isEmpty()) {
return true;
}
return false;
}
void XdgUrl::process()
{
/**
* xdgs scheme is a reserved name, so the process of xdgs
* is the same process of the xdg scheme currently.
*/
if (!isValid()) {
QJsonObject result;
result["status"] = QString("error_validation");
result["message"] = QString("Invalid XDG-URL " + _xdgUrl);
emit error(Utility::Json::convertObjToStr(result));
return;
}
_network->get(QUrl(_metadata["url"].toString()));
emit started();
}
} // namespace Handlers
#ifndef HANDLERS_XDGURL_H
#define HANDLERS_XDGURL_H
#include <QObject>
#include <QJsonObject>
class QNetworkReply;
namespace Core {
class Config;
class Network;
}
namespace Handlers {
class XdgUrl : public QObject
{
Q_OBJECT
private:
QString _xdgUrl;
Core::Config *_config;
Core::Network *_network;
QJsonObject _metadata;
QJsonObject _destinations;
public:
explicit XdgUrl(const QString &xdgUrl, Core::Config *config, Core::Network *network, QObject *parent = 0);
private:
void _parse();
void _loadDestinations();
QString _convertPathString(const QString &path);
void _saveDownloadedFile(QNetworkReply *reply);
void _installDownloadedFile(QNetworkReply *reply);
private slots:
void _downloaded(QNetworkReply *reply);
public slots:
QString getXdgUrl();
QString getMetadata();
bool isValid();
void process();
signals:
void started();
void finished(const QString &result);
void error(const QString &result);
void downloadProgress(const qint64 &received, const qint64 &total);
};
} // namespace Handlers
#endif // HANDLERS_XDGURL_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment