Make it DBusActivatable

This commit is contained in:
Anton Thomasson 2023-02-17 21:29:12 +01:00
parent e4038db1b0
commit 29c5bbf62b
16 changed files with 206 additions and 72 deletions

View file

@ -2,10 +2,11 @@
Type=Application Type=Application
Icon=harbour-seaprint Icon=harbour-seaprint
X-Nemo-Application-Type=silica-qt5 X-Nemo-Application-Type=silica-qt5
Exec=harbour-seaprint Exec=/usr/bin/harbour-seaprint
X-DBusActivatable=true
Name=SeaPrint Name=SeaPrint
[X-Sailjail] [X-Sailjail]
Permissions=Internet;Pictures;Documents;Downloads;RemovableMedia;MediaIndexing;Compatibility Permissions=Internet;Pictures;Documents;Downloads;RemovableMedia;MediaIndexing;Compatibility
OrganizationName=net.attah OrganizationName=net.attah
ApplicationName=seaprint ApplicationName=seaprint
ExecDBus=/usr/bin/harbour-seaprint --prestart

View file

@ -26,7 +26,7 @@ INSTALLS += i18n
system(lrelease $$PWD/translations/*.ts) system(lrelease $$PWD/translations/*.ts)
CONFIG += sailfishapp CONFIG += sailfishapp
QT += svg QT += svg dbus
PKGCONFIG += mlite5 libcurl poppler-glib glib-2.0 cairo libjpeg PKGCONFIG += mlite5 libcurl poppler-glib glib-2.0 cairo libjpeg
LIBS += -lcurl -lglib-2.0 -lgobject-2.0 -ldl LIBS += -lcurl -lglib-2.0 -lgobject-2.0 -ldl
DEFINES += MADNESS=1 DEFINES += MADNESS=1
@ -34,6 +34,7 @@ DEFINES += PDF_CREATOR='\\"SeaPrint\ $$VERSION\\"'
DEFINES += SEAPRINT_VERSION='\\"$$VERSION\\"' DEFINES += SEAPRINT_VERSION='\\"$$VERSION\\"'
SOURCES += src/harbour-seaprint.cpp \ SOURCES += src/harbour-seaprint.cpp \
src/dbusadaptor.cpp \
src/rangelistchecker.cpp \ src/rangelistchecker.cpp \
src/convertchecker.cpp \ src/convertchecker.cpp \
src/curlrequester.cpp \ src/curlrequester.cpp \
@ -82,6 +83,7 @@ TRANSLATIONS += translations/harbour-seaprint-de.ts \
translations/harbour-seaprint-pl.ts translations/harbour-seaprint-pl.ts
HEADERS += \ HEADERS += \
src/dbusadaptor.h \
src/rangelistchecker.h \ src/rangelistchecker.h \
src/convertchecker.h \ src/convertchecker.h \
src/curlrequester.h \ src/curlrequester.h \
@ -101,6 +103,7 @@ HEADERS += \
ppm2pwg/UrfPgHdr.codable \ ppm2pwg/UrfPgHdr.codable \
ppm2pwg/bytestream/bytestream.h \ ppm2pwg/bytestream/bytestream.h \
ppm2pwg/bytestream/codable.h \ ppm2pwg/bytestream/codable.h \
ppm2pwg/argget.h \
src/overrider.h \ src/overrider.h \
src/papersizes.h \ src/papersizes.h \
src/printerworker.h \ src/printerworker.h \

View file

@ -13,9 +13,37 @@ ApplicationWindow
{ {
id: appWin id: appWin
property Page _mainPage
property bool expectCalligra: true property bool expectCalligra: true
initialPage: Component { FirstPage { selectedFile: Qt.application.arguments[1] ? Qt.application.arguments[1] : "" } }
function openFile(file) {
selectedFile = file
selectedFileType = Mimer.get_type(selectedFile);
if(selectedFileType == "")
{
selectedFile = ""
notifier.notify(qsTr("Unsupported document format"))
}
if(pageStack.currentPage.busyPage)
{
notifier.notify(qsTr("New file selected"))
}
else
{
pageStack.pop(appWin._mainPage, PageStackAction.Immediate)
}
}
property string selectedFile: ""
property string selectedFileType
initialPage: Component {
FirstPage {
Component.onCompleted: appWin._mainPage = this
}
}
cover: Qt.resolvedUrl("cover/CoverPage.qml") cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: Orientation.All allowedOrientations: Orientation.All

View file

@ -3,6 +3,8 @@ import Sailfish.Silica 1.0
import "utils.js" as Utils import "utils.js" as Utils
Page { Page {
property bool busyPage: true
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
Component.onCompleted: { Component.onCompleted: {

View file

@ -12,9 +12,6 @@ Page {
id: page id: page
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
property string selectedFile: ""
property string selectedFileType
Connections { Connections {
target: wifi target: wifi
onConnectedChanged: { onConnectedChanged: {
@ -60,11 +57,6 @@ Page {
Component.onCompleted: { Component.onCompleted: {
IppDiscovery.discover(); IppDiscovery.discover();
if(selectedFile != "")
{
var type = Mimer.get_type(selectedFile);
selectedFileType = type;
}
} }
property bool nagged: false property bool nagged: false
@ -143,7 +135,7 @@ Page {
property string name: Utils.unknownForEmptyString(printer.attrs["printer-name"].value) property string name: Utils.unknownForEmptyString(printer.attrs["printer-name"].value)
property var supported_formats: Utils.supported_formats(printer, considerAdditionalFormatsSetting.value) property var supported_formats: Utils.supported_formats(printer, considerAdditionalFormatsSetting.value)
property bool canPrint: supported_formats.mimetypes.indexOf(selectedFileType) != -1 property bool canPrint: supported_formats.mimetypes.indexOf(appWin.selectedFileType) != -1
Connections { Connections {
target: printer target: printer
@ -182,7 +174,7 @@ Page {
{ {
if(printer.attrs.hasOwnProperty("printer-uuid")) if(printer.attrs.hasOwnProperty("printer-uuid"))
{ {
return JSON.parse(db.getJobSettings(printer.attrs["printer-uuid"].value, selectedFileType)); return JSON.parse(db.getJobSettings(printer.attrs["printer-uuid"].value, appWin.selectedFileType));
} }
else else
{ {
@ -199,7 +191,7 @@ Page {
return; return;
} }
debugCountReset.restart(); debugCountReset.restart();
if(selectedFile == "") if(appWin.selectedFile == "")
{ {
noFileSelected(); noFileSelected();
} }
@ -209,7 +201,7 @@ Page {
} }
else else
{ {
pageStack.push(Qt.resolvedUrl("PrinterPage.qml"), {printer: printer, selectedFile: selectedFile, jobParams: maybeGetParams()}) pageStack.push(Qt.resolvedUrl("PrinterPage.qml"), {printer: printer, selectedFile: appWin.selectedFile, jobParams: maybeGetParams()})
} }
} }
@ -250,13 +242,13 @@ Page {
Label { Label {
id: name_label id: name_label
color: canPrint || selectedFile == "" ? Theme.primaryColor : Theme.secondaryColor color: canPrint || appWin.selectedFile == "" ? Theme.primaryColor : Theme.secondaryColor
text: name text: name
} }
Label { Label {
id: mm_label id: mm_label
color: canPrint || selectedFile == "" ? Theme.primaryColor : Theme.secondaryColor color: canPrint || appWin.selectedFile == "" ? Theme.primaryColor : Theme.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
text: Utils.unknownForEmptyString(printer.attrs["printer-make-and-model"].value) text: Utils.unknownForEmptyString(printer.attrs["printer-make-and-model"].value)
+ (Utils.existsAndNotEmpty("printer-location", printer) ? " • "+printer.attrs["printer-location"].value : "") + (Utils.existsAndNotEmpty("printer-location", printer) ? " • "+printer.attrs["printer-location"].value : "")
@ -264,7 +256,7 @@ Page {
Label { Label {
id: uri_label id: uri_label
color: canPrint || selectedFile == "" ? Theme.highlightColor : Theme.secondaryColor color: canPrint || appWin.selectedFile == "" ? Theme.highlightColor : Theme.secondaryColor
font.pixelSize: Theme.fontSizeTiny font.pixelSize: Theme.fontSizeTiny
text: printer.url text: printer.url
} }
@ -285,7 +277,7 @@ Page {
width: Theme.itemSizeExtraSmall/2 width: Theme.itemSizeExtraSmall/2
visible: supported_formats.pdf visible: supported_formats.pdf
highlightColor: "red" highlightColor: "red"
highlighted: !(selectedFile == "" || canPrint) highlighted: !(appWin.selectedFile == "" || canPrint)
source: "image://theme/icon-m-file-pdf" source: "image://theme/icon-m-file-pdf"
} }
HighlightImage { HighlightImage {
@ -293,7 +285,7 @@ Page {
width: Theme.itemSizeExtraSmall/2 width: Theme.itemSizeExtraSmall/2
visible: supported_formats.postscript visible: supported_formats.postscript
highlightColor: "red" highlightColor: "red"
highlighted: !(selectedFile == "" || canPrint) highlighted: !(appWin.selectedFile == "" || canPrint)
source: "image://theme/icon-m-file-other" source: "image://theme/icon-m-file-other"
} }
@ -302,7 +294,7 @@ Page {
width: Theme.itemSizeExtraSmall/2 width: Theme.itemSizeExtraSmall/2
visible: supported_formats.plaintext visible: supported_formats.plaintext
highlightColor: "red" highlightColor: "red"
highlighted: !(selectedFile == "" || canPrint) highlighted: !(appWin.selectedFile == "" || canPrint)
source: "image://theme/icon-m-file-document" source: "image://theme/icon-m-file-document"
} }
HighlightImage { HighlightImage {
@ -310,7 +302,7 @@ Page {
width: Theme.itemSizeExtraSmall/2 width: Theme.itemSizeExtraSmall/2
visible: supported_formats.office visible: supported_formats.office
highlightColor: "red" highlightColor: "red"
highlighted: !(selectedFile == "" || canPrint) highlighted: !(appWin.selectedFile == "" || canPrint)
source: "image://theme/icon-m-file-formatted" source: "image://theme/icon-m-file-formatted"
} }
HighlightImage { HighlightImage {
@ -318,7 +310,7 @@ Page {
width: Theme.itemSizeExtraSmall/2 width: Theme.itemSizeExtraSmall/2
visible: supported_formats.office visible: supported_formats.office
highlightColor: "red" highlightColor: "red"
highlighted: !(selectedFile == "" || canPrint) highlighted: !(appWin.selectedFile == "" || canPrint)
source: "image://theme/icon-m-file-presentation" source: "image://theme/icon-m-file-presentation"
} }
HighlightImage { HighlightImage {
@ -326,7 +318,7 @@ Page {
width: Theme.itemSizeExtraSmall/2 width: Theme.itemSizeExtraSmall/2
visible: supported_formats.images visible: supported_formats.images
highlightColor: "red" highlightColor: "red"
highlighted: !(selectedFile == "" || canPrint) highlighted: !(appWin.selectedFile == "" || canPrint)
source: "image://theme/icon-m-file-image" source: "image://theme/icon-m-file-image"
} }
} }
@ -381,7 +373,7 @@ Page {
Row { Row {
id: warningRow id: warningRow
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: Mimer.isOffice(page.selectedFileType) visible: Mimer.isOffice(appWin.selectedFileType)
HighlightImage { HighlightImage {
source: "image://theme/icon-s-warning" source: "image://theme/icon-s-warning"
@ -404,7 +396,7 @@ Page {
horizontalAlignment: contentWidth > width ? Text.AlignRight : Text.AlignHCenter horizontalAlignment: contentWidth > width ? Text.AlignRight : Text.AlignHCenter
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
text: selectedFile != "" ? selectedFile : qsTr("No file selected") text: appWin.selectedFile != "" ? appWin.selectedFile : qsTr("No file selected")
SequentialAnimation { SequentialAnimation {
id: noFileSelectedAnimation id: noFileSelectedAnimation
@ -457,18 +449,7 @@ Page {
title: qsTr("Choose file") title: qsTr("Choose file")
onSelectedContentPropertiesChanged: { onSelectedContentPropertiesChanged: {
var mimeType = Mimer.get_type(selectedContentProperties.filePath) appWin.openFile(selectedContentProperties.filePath);
if(mimeType == Mimer.PDF || mimeType == Mimer.Postscript || mimeType == Mimer.Plaintext || Mimer.isOffice(mimeType))
{
page.selectedFile = selectedContentProperties.filePath
page.selectedFileType = mimeType
}
else
{
notifier.notify(qsTr("Unsupported document format"))
page.selectedFile = ""
page.selectedFileType = ""
}
} }
} }
} }
@ -478,8 +459,7 @@ Page {
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
onSelectedContentPropertiesChanged: { onSelectedContentPropertiesChanged: {
page.selectedFile = selectedContentProperties.filePath appWin.openFile(selectedContentProperties.filePath);
page.selectedFileType = Mimer.get_type(selectedContentProperties.filePath)
} }
} }
} }

26
src/dbusadaptor.cpp Normal file
View file

@ -0,0 +1,26 @@
#include "dbusadaptor.h"
#include <QtQuick>
DBusAdaptor::DBusAdaptor(QQuickView *view)
: QDBusAbstractAdaptor(view)
, _view(view)
{
}
DBusAdaptor::~DBusAdaptor()
{
}
void DBusAdaptor::Open(const QStringList &uris, const QVariantMap &)
{
if (!uris.isEmpty()) {
QMetaObject::invokeMethod(_view->rootObject(), "openFile", Q_ARG(QVariant, uris.at(0)));
}
QMetaObject::invokeMethod(_view->rootObject(), "activate");
}
void DBusAdaptor::Activate(const QVariantMap&)
{
QMetaObject::invokeMethod(_view->rootObject(), "activate");
}

26
src/dbusadaptor.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef DBUSADAPTOR_H
#define DBUSADAPTOR_H
#include <QObject>
#include <QtDBus/QDBusAbstractAdaptor>
#include <QQuickView>
class DBusAdaptor : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Application")
public:
DBusAdaptor(QQuickView *view);
~DBusAdaptor();
public Q_SLOTS:
Q_NOREPLY void Open(const QStringList &uris, const QVariantMap &platformData);
Q_NOREPLY void Activate(const QVariantMap &platformData);
private:
QQuickView* _view;
};
#endif // DBUSADAPTOR_H

View file

@ -1,4 +1,6 @@
#include <QtQuick> #include <QtQuick>
#include <QVariant>
#include <QDBusConnection>
#include <sailfishapp.h> #include <sailfishapp.h>
#include <src/ippdiscovery.h> #include <src/ippdiscovery.h>
@ -8,6 +10,9 @@
#include <src/convertchecker.h> #include <src/convertchecker.h>
#include <src/settings.h> #include <src/settings.h>
#include <src/rangelistchecker.h> #include <src/rangelistchecker.h>
#include <src/dbusadaptor.h>
#include "argget.h"
#include <iostream>
Q_DECLARE_METATYPE(CURLcode) Q_DECLARE_METATYPE(CURLcode)
Q_DECLARE_METATYPE(Bytestream) Q_DECLARE_METATYPE(Bytestream)
@ -26,6 +31,17 @@ static QObject* singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngi
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
bool prestart = false;
std::string FileName;
SwitchArg<bool> pretsartOpt(prestart, {"--prestart"}, "Run prestart");
PosArg fileArg(FileName, "File to print", true);
ArgGet args({&pretsartOpt}, {&fileArg});
if(!args.get_args(argc, argv))
{
return 1;
}
qRegisterMetaType<CURLcode>(); qRegisterMetaType<CURLcode>();
qRegisterMetaType<Bytestream>(); qRegisterMetaType<Bytestream>();
qRegisterMetaType<PrintParameters>(); qRegisterMetaType<PrintParameters>();
@ -52,8 +68,25 @@ int main(int argc, char *argv[])
QQuickView* view = SailfishApp::createView(); QQuickView* view = SailfishApp::createView();
view->engine()->addImportPath(SailfishApp::pathTo("qml/pages").toString()); view->engine()->addImportPath(SailfishApp::pathTo("qml/pages").toString());
view->setSource(SailfishApp::pathToMainQml()); view->setSource(SailfishApp::pathToMainQml());
view->show();
DBusAdaptor dbus(view);
if (!QDBusConnection::sessionBus().registerObject("/net/attah/seaprint", view))
qWarning() << "Could not register /net/attah/seaprint D-Bus object.";
if (!QDBusConnection::sessionBus().registerService("net.attah.seaprint"))
qWarning() << "Could not register net.attah.seaprint D-Bus service.";
if(!FileName.empty())
{
qDebug() << "Opening" << FileName.c_str();
QVariant fileNameVariant(FileName.c_str());
QMetaObject::invokeMethod(view->rootObject(), "openFile", Q_ARG(QVariant, fileNameVariant));
}
if(!prestart)
{
view->show();
}
return app->exec(); return app->exec();
} }

View file

@ -55,5 +55,12 @@ Mimer* Mimer::instance()
QString Mimer::get_type(QString filename) { QString Mimer::get_type(QString filename) {
QString type = _db.mimeTypeForFile(filename).name(); QString type = _db.mimeTypeForFile(filename).name();
qDebug() << "MimeType:" << type; qDebug() << "MimeType:" << type;
return type; if(type == PDF || type == Postscript || type == Plaintext || isImage(type) || isOffice(type))
{
return type;
}
else
{
return "";
}
} }

View file

@ -276,10 +276,6 @@
<source>Not on WiFi</source> <source>Not on WiFi</source>
<translation>Nicht mit einem WLAN verbunden</translation> <translation>Nicht mit einem WLAN verbunden</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Dieses Dokumentformat wird nicht unterstützt</translation>
</message>
<message> <message>
<source>This format may not render correctly</source> <source>This format may not render correctly</source>
<translation>Dieses Format wird möglicherweise nicht richtig dargestellt</translation> <translation>Dieses Format wird möglicherweise nicht richtig dargestellt</translation>
@ -623,6 +619,14 @@ auf diesem Drucker</translation>
<source>SVGs</source> <source>SVGs</source>
<translation>SVGs</translation> <translation>SVGs</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Dieses Dokumentformat wird nicht unterstützt</translation>
</message>
<message>
<source>New file selected</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>strings</name> <name>strings</name>

View file

@ -276,10 +276,6 @@
<source>Not on WiFi</source> <source>Not on WiFi</source>
<translation>No hay WiFi</translation> <translation>No hay WiFi</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Formato de documento no soportado</translation>
</message>
<message> <message>
<source>This format may not render correctly</source> <source>This format may not render correctly</source>
<translation>Este formato puede no renderizarse correctamente</translation> <translation>Este formato puede no renderizarse correctamente</translation>
@ -622,6 +618,14 @@
<source>SVGs</source> <source>SVGs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Formato de documento no soportado</translation>
</message>
<message>
<source>New file selected</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>strings</name> <name>strings</name>

View file

@ -276,10 +276,6 @@
<source>Not on WiFi</source> <source>Not on WiFi</source>
<translation>Pas en WiFi</translation> <translation>Pas en WiFi</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Format de document non supporté</translation>
</message>
<message> <message>
<source>This format may not render correctly</source> <source>This format may not render correctly</source>
<translation>Ce format peut ne pas être rendu correctement</translation> <translation>Ce format peut ne pas être rendu correctement</translation>
@ -623,6 +619,14 @@ sur cette imprimante</translation>
<source>SVGs</source> <source>SVGs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Format de document non supporté</translation>
</message>
<message>
<source>New file selected</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>strings</name> <name>strings</name>

View file

@ -276,10 +276,6 @@
<source>Not on WiFi</source> <source>Not on WiFi</source>
<translation>Niet met WiFi netwerk verbonden</translation> <translation>Niet met WiFi netwerk verbonden</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Niet-ondersteunde documentindeling</translation>
</message>
<message> <message>
<source>This format may not render correctly</source> <source>This format may not render correctly</source>
<translation>Dit formaat wordt mogelijk niet correct weergegeven</translation> <translation>Dit formaat wordt mogelijk niet correct weergegeven</translation>
@ -622,6 +618,14 @@
<source>SVGs</source> <source>SVGs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Niet-ondersteunde documentindeling</translation>
</message>
<message>
<source>New file selected</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>strings</name> <name>strings</name>

View file

@ -276,10 +276,6 @@
<source>Not on WiFi</source> <source>Not on WiFi</source>
<translation>Brak połączenia WiFi</translation> <translation>Brak połączenia WiFi</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Nieobsługiwany rodzaj dokumentu</translation>
</message>
<message> <message>
<source>This format may not render correctly</source> <source>This format may not render correctly</source>
<translation>Ten format może zostać przetworzony niepoprawnie</translation> <translation>Ten format może zostać przetworzony niepoprawnie</translation>
@ -622,6 +618,14 @@
<source>SVGs</source> <source>SVGs</source>
<translation>SVG</translation> <translation>SVG</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation>Nieobsługiwany rodzaj dokumentu</translation>
</message>
<message>
<source>New file selected</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>strings</name> <name>strings</name>

View file

@ -276,10 +276,6 @@
<source>Not on WiFi</source> <source>Not on WiFi</source>
<translation>WiFi</translation> <translation>WiFi</translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation></translation>
</message>
<message> <message>
<source>This format may not render correctly</source> <source>This format may not render correctly</source>
<translation></translation> <translation></translation>
@ -622,6 +618,14 @@
<source>SVGs</source> <source>SVGs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation></translation>
</message>
<message>
<source>New file selected</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>strings</name> <name>strings</name>

View file

@ -276,10 +276,6 @@
<source>Not on WiFi</source> <source>Not on WiFi</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>This format may not render correctly</source> <source>This format may not render correctly</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -622,6 +618,14 @@
<source>plaintext</source> <source>plaintext</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Unsupported document format</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>New file selected</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>strings</name> <name>strings</name>