diff --git a/core/document.cpp b/core/document.cpp --- a/core/document.cpp +++ b/core/document.cpp @@ -2363,9 +2363,22 @@ QMimeDatabase db; QMimeType mime = _mime; QByteArray filedata; - bool isstdin = url.fileName() == QLatin1String( "-" ); + int fd = -1; + if (url.scheme() == QLatin1String("fd")) + { + bool ok; + fd = url.path().mid(1).toInt(&ok); + if (!ok) + { + return OpenError; + } + } + else if (url.fileName() == QLatin1String( "-" )) + { + fd = 0; + } bool triedMimeFromFileContent = false; - if ( !isstdin ) + if ( fd < 0 ) { if ( !mime.isValid() ) return OpenError; @@ -2379,15 +2392,22 @@ else { QFile qstdin; - qstdin.open( stdin, QIODevice::ReadOnly ); + const bool ret = qstdin.open( fd, QIODevice::ReadOnly, QFileDevice::AutoCloseHandle ); + if (!ret) { + qWarning() << "failed to read" << url << filedata; + return OpenError; + } + filedata = qstdin.readAll(); mime = db.mimeTypeForData( filedata ); if ( !mime.isValid() || mime.isDefault() ) return OpenError; d->m_docSize = filedata.size(); triedMimeFromFileContent = true; } + const bool fromFileDescriptor = fd >= 0; + // 0. load Generator // request only valid non-disabled plugins suitable for the mimetype KPluginMetaData offer = DocumentPrivate::generatorForMimeType(mime, d->m_widget); @@ -2422,16 +2442,16 @@ } // 1. load Document - OpenResult openResult = d->openDocumentInternal( offer, isstdin, docFile, filedata, password ); + OpenResult openResult = d->openDocumentInternal( offer, fromFileDescriptor, docFile, filedata, password ); if ( openResult == OpenError ) { QVector triedOffers; triedOffers << offer; offer = DocumentPrivate::generatorForMimeType(mime, d->m_widget, triedOffers); while ( offer.isValid() ) { - openResult = d->openDocumentInternal( offer, isstdin, docFile, filedata, password ); + openResult = d->openDocumentInternal( offer, fromFileDescriptor, docFile, filedata, password ); if ( openResult == OpenError ) { @@ -2451,7 +2471,7 @@ offer = DocumentPrivate::generatorForMimeType(mime, d->m_widget, triedOffers); while ( offer.isValid() ) { - openResult = d->openDocumentInternal( offer, isstdin, docFile, filedata, password ); + openResult = d->openDocumentInternal( offer, fromFileDescriptor, docFile, filedata, password ); if ( openResult == OpenError ) { @@ -2553,7 +2573,7 @@ d->m_nextDocumentDestination = QString(); } - AudioPlayer::instance()->d->m_currentDocument = isstdin ? QUrl() : d->m_url; + AudioPlayer::instance()->d->m_currentDocument = fromFileDescriptor ? QUrl() : d->m_url; const QStringList docScripts = d->m_generator->metaData( QStringLiteral("DocumentScripts"), QStringLiteral ( "JavaScript" ) ).toStringList(); if ( !docScripts.isEmpty() ) diff --git a/mobile/android/AndroidManifest.xml b/mobile/android/AndroidManifest.xml --- a/mobile/android/AndroidManifest.xml +++ b/mobile/android/AndroidManifest.xml @@ -4,11 +4,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -32,5 +68,8 @@ + + + diff --git a/mobile/android/src/OpenFileActivity.java b/mobile/android/src/OpenFileActivity.java new file mode 100644 --- /dev/null +++ b/mobile/android/src/OpenFileActivity.java @@ -0,0 +1,43 @@ +package org.kde.something; + +import android.content.ContentResolver; +import android.content.Intent; +import android.util.Log; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.net.Uri; + +import org.qtproject.qt5.android.bindings.QtActivity; + +class FileClass +{ + public static native void openUri(String uri); +} + +public class OpenFileActivity extends QtActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Intent bundleIntent = getIntent(); + if (bundleIntent == null) + return; + + final String action = bundleIntent.getAction(); + Uri uri = bundleIntent.getData(); + if (!uri.getScheme().equals("file")) { + try { + ContentResolver resolver = getBaseContext().getContentResolver(); + ParcelFileDescriptor fdObject = resolver.openFileDescriptor(uri, "r"); + uri = Uri.parse("fd:///" + fdObject.detachFd()); + } catch (Exception e) { + e.printStackTrace(); + + //TODO: emit warning that couldn't be opened + Log.v("Okular", "failed to open"); + return; + } + } + + FileClass.openUri(uri.toString()); + } +} diff --git a/mobile/app/main.cpp b/mobile/app/main.cpp --- a/mobile/app/main.cpp +++ b/mobile/app/main.cpp @@ -28,12 +28,40 @@ #include #include #include +#include -Q_DECL_EXPORT int main(int argc, char *argv[]) -{ #ifdef __ANDROID__ - qputenv("QT_QUICK_CONTROLS_STYLE", "material"); +#include + +class URIHandler : public QObject { +public: + void openUri(const QString &uri) { + m_lastUrl = uri; + } + + QString m_lastUrl; +} handler; + +extern "C" { + +JNIEXPORT void JNICALL + Java_org_kde_something_FileClass_openUri(JNIEnv *env, + jobject /*obj*/, + jstring uri) +{ + jboolean isCopy = false; + const char* utf = env->GetStringUTFChars(uri, &isCopy); + handler.openUri(QString::fromUtf8(utf)); + env->ReleaseStringUTFChars(uri, utf); + +} + +} + +Q_DECL_EXPORT #endif +int main(int argc, char *argv[]) +{ QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); app.setApplicationName(QStringLiteral("okularkirigami")); @@ -43,10 +71,17 @@ parser.addHelpOption(); //parser.setApplicationDescription(i18n("Okular mobile")); parser.process(app); - QQmlApplicationEngine engine; + +#ifdef __ANDROID__ + const QString uri = handler.m_lastUrl; +#else + const QString uri = parser.positionalArguments().count() == 1 + ? QUrl::fromUserInput(parser.positionalArguments().constFirst(), {}, QUrl::AssumeLocalFile).toString() + : QString(); +#endif engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); - engine.rootContext()->setContextProperty(QStringLiteral("commandlineArguments"), parser.positionalArguments()); + engine.rootContext()->setContextProperty(QStringLiteral("uri"), uri); QVariantMap paths; paths[QStringLiteral("desktop")] = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); paths[QStringLiteral("documents")] = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); diff --git a/mobile/app/package/contents/ui/Documents.qml b/mobile/app/package/contents/ui/Documents.qml --- a/mobile/app/package/contents/ui/Documents.qml +++ b/mobile/app/package/contents/ui/Documents.qml @@ -96,7 +96,7 @@ return; } - documentItem.path = model.filePath; + documentItem.url = model.fileURL; globalDrawer.close(); applicationWindow().controlsVisible = false; } diff --git a/mobile/app/package/contents/ui/OkularDrawer.qml b/mobile/app/package/contents/ui/OkularDrawer.qml --- a/mobile/app/package/contents/ui/OkularDrawer.qml +++ b/mobile/app/package/contents/ui/OkularDrawer.qml @@ -47,7 +47,7 @@ Connections { target: documentItem - onPathChanged: thumbnailsButton.checked = true; + onUrlChanged: thumbnailsButton.checked = true; } QQC2.ToolBar { diff --git a/mobile/app/package/contents/ui/main.qml b/mobile/app/package/contents/ui/main.qml --- a/mobile/app/package/contents/ui/main.qml +++ b/mobile/app/package/contents/ui/main.qml @@ -24,7 +24,6 @@ Kirigami.AbstractApplicationWindow { id: fileBrowserRoot - objectName: "fileBrowserRoot" visible: true /*TODO: port ResourceInstance @@ -44,11 +43,11 @@ drawerOpen: false } + title: documentItem.windowTitleForDocument Okular.DocumentItem { id: documentItem - onPathChanged: currentPage = 0 + onUrlChanged: { currentPage = 0 } onWindowTitleForDocumentChanged: { - fileBrowserRoot.title = windowTitleForDocument } } @@ -63,11 +62,9 @@ interval: 100 running: true onTriggered: { - if (commandlineArguments.length > 0) { - documentItem.path = commandlineArguments[0] - } - - if (commandlineArguments.length == 0) { + if (uri) { + documentItem.url = uri + } else { globalDrawer.open(); } } diff --git a/mobile/components/DocumentView.qml b/mobile/components/DocumentView.qml --- a/mobile/components/DocumentView.qml +++ b/mobile/components/DocumentView.qml @@ -50,7 +50,7 @@ } Connections { target: root.document - onPathChanged: resizeTimer.restart() + onUrlChanged: resizeTimer.restart() } Timer { id: resizeTimer diff --git a/mobile/components/documentitem.h b/mobile/components/documentitem.h --- a/mobile/components/documentitem.h +++ b/mobile/components/documentitem.h @@ -39,9 +39,9 @@ Q_OBJECT /** - * Absolute path of the document file to open + * Absolute URI to document file to open */ - Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) /** * Suggested window title if a window represents this document. may be pathname or document title, dependeing from Okular settings. @@ -98,8 +98,8 @@ explicit DocumentItem(QObject *parent=nullptr); ~DocumentItem(); - void setPath(const QString &path); - QString path() const; + void setUrl(const QUrl &url); + QUrl url() const; QString windowTitleForDocument() const; @@ -141,7 +141,7 @@ Observer *thumbnailObserver(); Q_SIGNALS: - void pathChanged(); + void urlChanged(); void pageCountChanged(); void openedChanged(); void searchInProgressChanged(); diff --git a/mobile/components/documentitem.cpp b/mobile/components/documentitem.cpp --- a/mobile/components/documentitem.cpp +++ b/mobile/components/documentitem.cpp @@ -53,12 +53,14 @@ delete m_document; } -void DocumentItem::setPath(const QString &path) +void DocumentItem::setUrl(const QUrl & url) { - //TODO: remote urls //TODO: password QMimeDatabase db; - m_document->openDocument(path, QUrl::fromLocalFile(path), db.mimeTypeForUrl(QUrl::fromLocalFile(path))); + + const QString path = url.isLocalFile() ? url.toLocalFile() : QLatin1String("-"); + + m_document->openDocument(path, url, db.mimeTypeForUrl(url)); m_tocModel->clear(); m_tocModel->fill(m_document->documentSynopsis()); @@ -69,7 +71,7 @@ m_matchingPages << (int)i; } emit matchingPagesChanged(); - emit pathChanged(); + emit urlChanged(); emit pageCountChanged(); emit openedChanged(); emit supportsSearchingChanged(); @@ -95,9 +97,9 @@ return title; } -QString DocumentItem::path() const +QUrl DocumentItem::url() const { - return m_document->currentDocument().toDisplayString(); + return m_document->currentDocument(); } void DocumentItem::setCurrentPage(int page) diff --git a/mobile/components/pageitem.cpp b/mobile/components/pageitem.cpp --- a/mobile/components/pageitem.cpp +++ b/mobile/components/pageitem.cpp @@ -121,7 +121,7 @@ emit documentChanged(); m_redrawTimer->start(); - connect(doc, &DocumentItem::pathChanged, this, &PageItem::refreshPage); + connect(doc, &DocumentItem::urlChanged, this, &PageItem::refreshPage); } int PageItem::pageNumber() const diff --git a/shell/shell.cpp b/shell/shell.cpp --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -278,7 +278,7 @@ m_tabWidget->setTabText( activeTab, url.fileName() ); applyOptionsToPart( activePart, serializedOptions ); bool openOk = activePart->openUrl( url ); - const bool isstdin = url.fileName() == QLatin1String( "-" ); + const bool isstdin = url.fileName() == QLatin1String( "-" ) || url.scheme() == QLatin1String( "fd" ); if ( !isstdin ) { if ( openOk )