Коммит ce593f45 создал по автору vladislav.larionov's avatar vladislav.larionov
Просмотр файлов

Add components from docviewer

владелец 940b0b6b
application/LibreOfficeKit
*.autosave
*.pro.user
*.pro.user.*
RPMS
Makefile
moc_*
*.moc
*.o
*.so
*.so.*
*.prl
*.pc
*.list
......@@ -38,6 +38,8 @@
TARGET = ru.auroraos.DocumentConverter
QT += core dbus
CONFIG += \
auroraapp
......@@ -46,9 +48,19 @@ PKGCONFIG += \
SOURCES += \
src/converter.cpp \
src/main.cpp \
src/filtermodel.cpp \
src/documentlistmodel.cpp \
src/trackerdocumentprovider.cpp \
src/documentprovider.cpp \
src/licensestatus.cpp
HEADERS += \
src/converter.h
src/converter.h \
src/filtermodel.h \
src/documentlistmodel.h \
src/trackerdocumentprovider.h \
src/documentprovider.h \
src/licensestatus.h
INCLUDEPATH += \
LibreOfficeKit
......@@ -59,10 +71,21 @@ DISTFILES += \
qml/DocumentConverter.qml \
qml/pages/MainPage.qml \
qml/pages/ConvertPage.qml \
qml/cover/DefaultCoverPage.qml
qml/dialogs/AcceptLicenseDialog.qml \
qml/cover/DefaultCoverPage.qml \
qml/images/Documents.svg \
qml/cover/CoverPage.qml \
qml/cover/CoverFileItem.qml \
qml/pages/FileListPage.qml \
qml/pages/SortTypeSelectionPage.qml \
licenses/*.txt
AURORAAPP_ICONS = 86x86 108x108 128x128 172x172
OTHER_FILES += \
licenses/*.txt
CONFIG += auroraapp_i18n
TRANSLATIONS += \
......@@ -75,3 +98,13 @@ translations.files = $$TRANSLATIONS
INSTALLS += \
translations
licenses.path = /usr/share/$$TARGET
licenses.files = licenses
INSTALLS += licenses
SUPPORT_MIMETYPES = "$$system(cat $$IN_PWD/ru.auroraos.DocumentConverter.desktop | grep MimeType)"
SUPPORT_MIMETYPES ~= s/MimeType=//
SUPPORT_MIMETYPES ~= s/;$//
SUPPORT_MIMETYPES = $$replace(SUPPORT_MIMETYPES, ";", ",")
DEFINES += SUPPORT_MIMETYPES=\\\"$$SUPPORT_MIMETYPES\\\"
END USER LICENSE AGREEMENT
IMPORTANT! BEFORE USING THE SOFTWARE COVERED WITH THIS END USER LICENSE AGREEMENT. IF YOU DO NOT AGREE TO THE TERMS OF THIS LICENSE AGREEMENT, YOU ARE NOT RIGHT TO USE THE SOFTWARE FOR ANY PURPOSE.
1. DEFINITIONS
"Company" - Limited Liability Company "Open Mobile Platform", 420500, Republic of Tatarstan, Verkhneuslonsky District, Moscow, st. Innopolis, st. University,
7, office 59, OGRN 1161690087020.
"Software" - the "Documents" application, which is designed to display documents in the following formats: *.rtf, *.doc, *.docx, *.xls, *.xlsx, *.ppt, *.pptx, *.txt, *.ods, *.odt, *.odp, *.csv.
A “device” is a hardware system (physical or virtual) with built-in storage on which software can run.
"License Agreement" - the right granted to you by the Company to use the software functionality under the terms of the GNU Public License, version 2 in accordance with the terms of this License Agreement.
“End User” is any legal entity (organization) that has acquired the Software for its own use and not for sale.
"User" - an individual who directly operates the Software for the purposes and in the manner established by the End User.
This License Agreement is a legal agreement between you (hereinafter referred to as the End User) and the Company.
2. LICENSE
2.1. Subject to the terms below, the Company will license you worldwide perpetual software licenses under the GNU General Public License, version 2 (GNU General Public License v.2).
3. RIGHTS TO SOFTWARE
3.1. The Software is owned by the Company and other companies operating under copyright and other applicable laws. Ownership of the software, as well as any copies, modifications
or the merger remains with the Company and other licensors, depending on the applicable license.
4. LIMITATIONS
4.1. The end user does not have the right to name in the name of the software, distributed with the software, copyright marks (copyright notice) or other indications of the Company or others.
5. PERSONAL DATA
5.1. The Company hereby informs that in the process of using the Software functionality by the End Device, it does not collect and process User data.
6. LIMITATION OF LICENSE AGREEMENT
6.1. The Software is provided on an "as is" (as is) basis. The Company does not provide any warranty for the error-free and uninterrupted operation of the Software, meets the specific goals and expectations of the End User, and does not provide any other, directly in this License Agreement.
6.2. To the maximum extent permitted by the current legislation, the Company is not responsible for any direct or indirect consequences of any use or inability to use the software / or damage caused to the End User and / or third parties as a result of any use or non-use of the software, including due to software errors or malfunctions.
7. UPDATES / NEW VERSIONS OF SOFTWARE.
7.1. Updates of this software, updating for its improvement, are carried out in the form of releasing new versions of the software.
7.2. The end user is notified and agrees that the Company does not guarantee the provision of software updates obtained under the License Agreement.
ЛИЦЕНЗИОННОЕ СОГЛАШЕНИЕ С КОНЕЧНЫМ ПОЛЬЗОВАТЕЛЕМ
ВАЖНО! ПЕРЕД ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, К КОТОРОМУ ПРИЛАГАЕТСЯ ДАННОЕ ЛИЦЕНЗИОННОЕ СОГЛАШЕНИЕ С КОНЕЧНЫМ ПОЛЬЗОВАТЕЛЕМ (ДАЛЕЕ ПО ТЕКСТУ – «ЛИЦЕНЗИОННОЕ СОГЛАШЕНИЕ»), ПОЖАЛУЙСТА, ВНИМАТЕЛЬНО ПРОЧИТАЙТЕ НИЖЕСЛЕДУЮЩИЕ УСЛОВИЯ. ЕСЛИ ВЫ НЕ СОГЛАШАЕТЕСЬ С УСЛОВИЯМИ НАСТОЯЩЕГО ЛИЦЕНЗИОННОГО СОГЛАШЕНИЯ, ТО ВЫ НЕ ИМЕЕТЕ ПРАВА ИСПОЛЬЗОВАТЬ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ В КАКИХ-ЛИБО ЦЕЛЯХ.
1. ОПРЕДЕЛЕНИЯ
«Компания» – общество с ограниченной ответственностью «Открытая мобильная платформа» (ООО «Открытая мобильная платформа»), 420500, Республика Татарстан, Верхнеуслонский район, г. Иннополис, ул. Университетская,
д. 7, офис 59, ОГРН 1161690087020.
«ПО» – приложение «Документы», которое предназначено для отображения документов следующих форматов: *.rtf, *.doc, *.docx, *.xls, *.xlsx, *.ppt, *.pptx, *.txt, *.ods, *.odt, *.odp, *.csv.
«Устройство» – это аппаратная система (физическая или виртуальная) со встроенным запоминающим устройством, на которой может быть запущено ПО.
«Лицензионное соглашение» – предоставляемое Вам Компанией право на использование функциональности ПО на условиях Общественной лицензией GNU, версия 2 в соответствии с условиями настоящего Лицензионного соглашения.
«Конечный пользователь» – любое юридическое лицо (организация), которое приобрело ПО для собственного использования и не для продажи.
«Пользователь» – физическое лицо, непосредственно осуществляющее эксплуатацию ПО в целях и порядке, определяемом Конечным пользователем.
Настоящее Лицензионное соглашение является юридическим соглашением между Вами (далее по тексту – Конечный пользователь) и Компанией.
2. ЛИЦЕНЗИЯ
2.1. Согласно приведенным ниже условиям, Компания предоставляет Вам бессрочную лицензию для всех стран мира на ПО в соответствии с Общественной лицензией GNU, версия 2 (GNU General Public License v.2).
3. ПРАВА НА ПО
3.1. ПО находится в собственности Компании и других лицензиаров и защищены законодательством об авторских правах и другим применимым законодательством. Право собственности на ПО, а также любые копии, модификации
или слияния остается у Компании и других лицензиаров, в зависимости от применимой лицензии.
4. ОГРАНИЧЕНИЯ
4.1. Конечный пользователь не вправе изменять наименование ПО, изменять и/или удалять присутствующие в ПО или иных материалах, распространяемых с ПО, знаки охраны авторского права (copyright notice) или иные указания на Компанию или иных лиц.
5. ПЕРСОНАЛЬНЫЕ ДАННЫЕ
5.1. Компания настоящим информирует, что в процессе использования Конечным пользователем функциональности ПО не осуществляет сбор и обработку персональных данных Пользователей.
6. ОГРАНИЧЕНИЕ ОТВЕТСТВЕННОСТИ ПО ЛИЦЕНЗИОННОМУ СОГЛАШЕНИЮ
6.1. ПО предоставляется на условиях «как есть» (as is). Компания не предоставляет никаких гарантий в отношении безошибочной и бесперебойной работы ПО, соответствия ПО конкретным целям и ожиданиям Конечного пользователя, а также не предоставляют никаких иных гарантий, прямо не указанных в настоящем Лицензионном соглашении.
6.2. В максимальной степени, допустимой действующим законодательством, Компания не несёт никакой ответственности за какие-либо прямые или косвенные последствия какого-либо использования или невозможности использования ПО и/или ущерб, причиненный Конечному пользователю и/или третьим сторонам в результате какого-либо использования или неиспользования ПО, в том числе из-за возможных ошибок или сбоев в работе ПО.
7. ОБНОВЛЕНИЯ/НОВЫЕ ВЕРСИИ ПО
7.1. Обновления настоящего ПО, направленные на его улучшение, могут осуществляться в форме выпуска новых версий ПО.
7.2. Конечный пользователь настоящим уведомлен и согласен с тем, что Компания не гарантирует предоставление обновления ПО, полученного по настоящему Лицензионному соглашению.
......@@ -39,11 +39,96 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import Aurora.Office.Files 1.0
import "pages"
import "cover"
ApplicationWindow {
objectName: "applicationWindow"
initialPage: Qt.resolvedUrl("pages/MainPage.qml")
cover: Qt.resolvedUrl("cover/DefaultCoverPage.qml")
allowedOrientations: defaultAllowedOrientations
ApplicationWindow
{
id: applicationWindow
property DocumentListModel fileListModel: trackerProvider.model
property Item documentItem
property Page mainPage
property var docView: null
signal searchRequest()
allowedOrientations: Orientation.All
_defaultPageOrientations: Orientation.All
initialPage: Component {
FileListPage {
id: fileListPage
Component.onCompleted: applicationWindow.mainPage = fileListPage
model: trackerProvider.model
provider: trackerProvider
}
}
cover: Component {
CoverPage {}
}
TrackerDocumentProvider {
id: trackerProvider
}
function mimeToIcon(fileMimeType) {
var iconType = "other"
switch (fileMimeType) {
case "text/x-vnote":
iconType = "note"
break
case "application/pdf":
iconType = "pdf"
break
case "application/vnd.oasis.opendocument.spreadsheet":
case "application/x-kspread":
case "application/vnd.ms-excel":
case "text/csv":
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
case "application/vnd.openxmlformats-officedocument.spreadsheetml.template":
iconType = "spreadsheet"
break
case "application/vnd.oasis.opendocument.presentation":
case "application/vnd.oasis.opendocument.presentation-template":
case "application/x-kpresenter":
case "application/vnd.ms-powerpoint":
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
case "application/vnd.openxmlformats-officedocument.presentationml.template":
iconType = "presentation"
break
case "text/plain":
case "application/vnd.oasis.opendocument.text-master":
case "application/vnd.oasis.opendocument.text":
case "application/vnd.oasis.opendocument.text-template":
case "application/msword":
case "application/rtf":
case "application/x-mswrite":
case "application/vnd.openxmlformats-officedocument.wordprocessing":
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
case "application/vnd.openxmlformats-officedocument.wordprocessingml.template":
case "application/vnd.ms-works":
iconType = "formatted"
break
}
return "image://theme/icon-m-file-" + iconType
}
Connections {
target: pageStack
onCurrentPageChanged: {
if (pageStack.currentPage !== null) {
applicationWindow.documentItem = pageStack.currentPage
}
}
onDepthChanged: {
if (pageStack.depth <= 1) {
applicationWindow.docView = null
}
}
ignoreUnknownSignals: true
}
}
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: Proprietary
*/
import QtQuick 2.4
import Sailfish.Silica 1.0
Item {
id: root
readonly property string stateGrid: "grid"
readonly property string stateList: "list"
readonly property var fileInfo: fileListModel.getFileInfo(model.filePath)
width: GridView.view.cellWidth
height: GridView.view.cellHeight
state: __documentsView.isGridMode ? root.stateGrid : root.stateList
states: [
State {
name: root.stateGrid
AnchorChanges {
target: icon
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
}
}
PropertyChanges {
target: icon
anchors {
topMargin: ui.internalPadding
}
}
AnchorChanges {
target: fileName
anchors {
top: icon.bottom
horizontalCenter: parent.horizontalCenter
}
}
PropertyChanges {
target: fileName
horizontalAlignment: Text.AlignHCenter
}
},
State {
name: root.stateList
AnchorChanges {
target: icon
anchors {
left: parent.left
top: parent.top
}
}
PropertyChanges {
target: icon
anchors {
leftMargin: ui.internalPadding
topMargin: ui.internalPadding
}
}
AnchorChanges {
target: fileName
anchors {
left: icon.right
}
}
PropertyChanges {
target: fileName
anchors {
leftMargin: ui.internalPadding
verticalCenter: icon.verticalCenter
}
}
}
]
Rectangle {
id: background
anchors {
fill: parent
bottomMargin: Theme.paddingSmall
rightMargin: __documentsView.isGridMode ? Theme.paddingSmall : 0
}
radius: Theme.dp(6)
opacity: 0.1
color: Theme.primaryColor
}
Item {
id: content
anchors {
fill: parent
margins: Theme.paddingSmall
bottomMargin: Theme.paddingSmall * 2
rightMargin: __documentsView.isGridMode
? Theme.paddingSmall * 2
: Theme.paddingSmall
}
Image {
id: icon
width: Theme.iconSizeSmallPlus
height: width
source: Theme.iconForMimeType(model.fileMimeType)
}
Label {
id: fileName
readonly property real availableWidth: __documentsView.isGridMode
? content.width
: content.width - Theme.iconSizeMedium
readonly property string dots: '...'
readonly property string suffix: '%1%2'.arg(fileName.dots).arg(root.fileInfo.suffix)
readonly property string elidedText:
tm.elidedText.substring(0, tm.elidedText.length -
fileName.suffix.length).trim() + fileName.suffix
anchors {
right: parent.right
}
wrapMode: Label.Wrap
maximumLineCount: 2
font.pixelSize: Theme.fontSizeTiny
color: Theme.primaryColor
text: tm.isElided
? fileName.elidedText
: root.fileInfo.fileName
}
TextMetrics {
id: tm
readonly property bool isElided: tm.text !== tm.elidedText
text: root.fileInfo.baseName
font: fileName.font
elide: Text.ElideRight
elideWidth: fileName.availableWidth * 2 - (__documentsView.isGridMode
? fm.advanceWidth(fileName.suffix)
: fm.advanceWidth(fileName.dots))
}
FontMetrics {
id: fm
font: fileName.font
}
}
QtObject {
id: ui
readonly property real calculatedHeight: {
if (__documentsView.isGridMode) {
return Theme.paddingSmall + Theme.iconSizeMedium + fileName.height
}
return Theme.iconSizeMedium + Theme.paddingSmall * 2
}
readonly property real internalPadding:
(Theme.iconSizeMedium - Theme.iconSizeSmallPlus) / 2
}
}
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: Proprietary
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
import Aurora.Office.Files 1.0
import ru.omp.documentprovider.libreoffice 1.0
Item {
id: root
Label {
id: documentName
anchors {
left: parent.left
right: parent.right
}
truncationMode: TruncationMode.Elide
elide: Label.ElideMiddle
font.pixelSize: Theme.fontSizeTiny
color: Theme.primaryColor
text: {
if (!coverPrivate.docView) {
return ""
}
return fileListModel.getFileInfo(coverPrivate.docView.path).fileName
}
}
Loader {
id: documentLoader
anchors {
fill: parent
leftMargin: -(Theme.paddingMedium + coverPrivate.borderPadding)
rightMargin: -(Theme.paddingMedium + coverPrivate.borderPadding)
topMargin: documentName.height + Theme.paddingSmall
}
active: coverPrivate.docView
sourceComponent: Item {
id: previewRoot
anchors.fill: parent
clip: true
Connections {
target: __cover
onStatusChanged: {
if (__cover.status === Cover.Activating) {
coverPrivate.grabDocViewAtChanges()
}
}
}
Image {
id: preview
readonly property bool includeDocHeader: {
if (!coverPrivate.docView) {
return false
}
return coverPrivate.docView.contentY <= coverPrivate.docView.topMargin
}
readonly property real scaledDocTopMargin: {
if (!coverPrivate.docView) {
return 0
}
const scale = previewRoot.height / (coverPrivate.docView.height + coverPrivate.docView.topMargin)
const value = coverPrivate.docView.topMargin - coverPrivate.docView.contentY
return Math.round(value * scale) * 2
}
anchors {
fill: parent
topMargin: preview.includeDocHeader
? -scaledDocTopMargin
: 0
}
asynchronous: true
source: coverPrivate.grabResult ? coverPrivate.grabResult.url : ""
fillMode: Image.PreserveAspectCrop
verticalAlignment: Image.AlignTop
horizontalAlignment: Image.AlignLeft
opacity: (coverPrivate.grabbing && coverPrivate.positionChanged) ? 0 : 1
Behavior on opacity {
FadeAnimation {}
}
}
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
visible: {
if (!coverPrivate.docView) {
return false
}
if (coverPrivate.docView.documentProvider.status === LoDocument.Loading) {
return true
}
return coverPrivate.grabbing && coverPrivate.positionChanged
}
running: visible
_forceAnimation: true
}
HighlightImage {
id: warningIcon
anchors.centerIn: parent
visible: {
if (!coverPrivate.docView) {
return false
}
if (busyIndicator.running) {
return false
}
return coverPrivate.docView.documentProvider.status === LoDocument.Error
}
source: "image://theme/icon-l-attention"
highlighted: true
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
QtObject {
id: coverPrivate
readonly property int borderPadding: Theme.lineWidth
? Theme.lineWidth
: 4
readonly property var docView: applicationWindow.docView
readonly property bool positionChanged: {
if (!coverPrivate.docView) {
return false
}
return coverPrivate.lastContentX !== coverPrivate.docView.contentX ||
coverPrivate.lastContentY !== coverPrivate.docView.contentY
}
property var grabResult: null
property bool grabbing: false
property int lastContentX: -1
property int lastContentY: -1
readonly property Timer delayedResultAssignTimer: Timer {
property var _result: null
function assign(result) {
_result = result
start()
}
function finish(result) {
coverPrivate.grabResult = result
coverPrivate.grabbing = false
coverPrivate.updateLastContentPos()
}
interval: 200
onTriggered: {
finish(_result)
}
}
function updateLastContentPos() {
coverPrivate.lastContentX = coverPrivate.docView.contentX
coverPrivate.lastContentY = coverPrivate.docView.contentY
}
function grabDocViewAtChanges() {
if (!coverPrivate.docView ||
coverPrivate.docView.documentProvider.status !== LoDocument.Ready) {
return
}
coverPrivate.grabDocView()
}
function grabDocView() {
if (!applicationWindow.visible) {
return
}
if (!coverPrivate.docView) {
console.warn('null document view')
return
}
coverPrivate.grabbing = true
coverPrivate.docView.cancelFlick()
coverPrivate.docView.grabToImage(function(result) {
if (!coverPrivate.positionChanged) {
delayedResultAssignTimer.finish(result)
} else {
coverPrivate.delayedResultAssignTimer.assign(result)
}
})
}
}
}
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: Proprietary
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
Item {
id: root
readonly property bool isGridMode: fileListModel.rowCount > documentsView.singleCoumnLimit
readonly property bool isVertical: __cover.isPortrait
readonly property alias __documentsView: root
SilicaGridView {
id: documentsView
readonly property int singleCoumnLimit: 3
readonly property int prefferedColumnCount: root.isVertical ? 2 : 3
anchors {
fill: parent
}
layer.enabled: true
layer.effect: OpacityRampEffect {
direction: OpacityRamp.TopToBottom
sourceItem: documentsView
slope: 4.0
offset: __cover.isPortrait ? 0.5 : 0.42
}
model: fileListModel
cellWidth: root.isGridMode
? documentsView.width / documentsView.prefferedColumnCount
: documentsView.width
cellHeight: (root.isGridMode ? Theme.dp(120)
: Theme.dp(76)) + Theme.paddingSmall
delegate: CoverDocumentDelegate {}
}
Component.onCompleted: {
__cover.actionsEnable = true
}
Component.onDestruction: {
__cover.actionsEnable = false
}
}
/**
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: Proprietary
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
Item {
id: root
Icon {
id: icon
source: "image://theme/icon-splus-cover-docs"
}
Label {
id: welcomeTitle
anchors {
left: parent.left
right: parent.right
top: icon.bottom
topMargin: Theme.paddingMedium
}
//% "Welcome to Documents!"
text: qsTrId("docviewer-la-welcome_do_documents")
wrapMode: Label.WordWrap
maximumLineCount: 2
font.weight: Font.Medium
truncationMode: TruncationMode.Fade
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeExtraSmall
}
Label {
id: noDocumentsSubTitle
anchors {
left: parent.left
right: parent.right
top: welcomeTitle.bottom
topMargin: __cover.isPortrait
? Theme.paddingMedium
: Theme.paddingSmall
}
//% "There is no documents on device yet"
text: qsTrId("docviewer-la-device_no_documents")
wrapMode: Label.WordWrap
maximumLineCount: 2
truncationMode: TruncationMode.Fade
color: Theme.secondaryColor
font.pixelSize: Theme.fontSizeTiny
}
}
/**
* SPDX-FileCopyrightText: Copyright 2020 - 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: GPLv2
*/
/*
* Copyright (C) 2013-2014 Jolla Ltd.
* Contact: Robin Burchell <robin.burchell@jolla.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.4
import Sailfish.Silica 1.0
import ru.omp.documentprovider.libreoffice 1.0
CoverBackground {
id: root
property bool actionsEnable: false
property bool documentViewOpenedOnce: false
readonly property bool isPortrait: root.orientation === Cover.Vertical
readonly property bool privateMode: false //! TODO
readonly property alias __cover: root
Connections {
target: applicationWindow
onVisibleChanged: {
coverPrivate.updateDocumentViewOpenedOnce()
}
onDocViewChanged: {
if (!applicationWindow.docView) {
root.documentViewOpenedOnce = false
}
}
}
Connections {
target: {
if (applicationWindow.docView) {
return applicationWindow.docView.documentProvider
}
return null
}
onStatusChanged: {
coverPrivate.updateDocumentViewOpenedOnce()
}
}
Loader {
id: coverContentLoader
anchors {
fill: parent
leftMargin: Theme.paddingCover
rightMargin: Theme.paddingCover
}
objectName: "coverContentLoader"
sourceComponent: {
if (applicationWindow.docView
&& !root.privateMode
&& root.documentViewOpenedOnce) {
return documentItemComponent
}
if (fileListModel.rowCount > 0) {
return documentsViewComponent
}
return noDocumentsItemComponent
}
Component {
id: noDocumentsItemComponent
CoverNoDocumentsItem {}
}
Component {
id: documentsViewComponent
CoverDocumentsView {}
}
Component {
id: documentItemComponent
CoverDocumentItem {}
}
}
CoverActionList {
enabled: root.actionsEnable
CoverAction {
iconSource: "image://theme/icon-cover-search"
onTriggered: {
applicationWindow.searchRequest()
}
}
}
QtObject {
id: coverPrivate
function updateDocumentViewOpenedOnce() {
if (!applicationWindow.visible
|| root.documentViewOpenedOnce
|| !applicationWindow.docView) {
return
}
root.documentViewOpenedOnce = applicationWindow.docView.documentProvider.status === LoDocument.Ready
}
}
}
/****************************************************************************
**
** Copyright (C) 2021 Open Mobile Platform LLC
**
****************************************************************************/
import QtQuick 2.0
import Sailfish.Silica 1.0
import Aurora.Office.License 1.0
Dialog {
onAccepted: licenseStatus.accept()
onRejected: Qt.quit()
SilicaFlickable {
id: license
anchors.fill: parent
contentHeight: column.height
Column {
id: column
width: parent.width
DialogHeader { }
TextArea {
color: Theme.highlightColor
readOnly: true
wrapMode: Text.WordWrap
text: licenseStatus.textLicense(Qt.locale().name)
}
}
VerticalScrollDecorator {flickable: license}
}
LicenseStatus {
id: licenseStatus
}
}
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.299988" y="0.299805" width="85.4" height="85.4" rx="1" fill="url(#paint0_radial)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M35 35.9951C35.5523 35.9951 36 35.5474 36 34.9951L36 12.9973C36.0015 11.894 36.8963 11 38 11H74C74.5523 11 75 11.4477 75 12V74C75 74.5522 74.5523 75 74 75H12.0001C11.4478 75 11.0001 74.5522 11.0001 74V37.9869C11.0061 36.8874 11.8992 35.998 13 35.998L35 35.9951Z" fill="url(#paint1_radial)"/>
<g filter="url(#filter0_dd)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M63 27C63 26.4477 62.5523 26 62 26H24C23.4477 26 23 26.4477 23 27V29C23 29.5523 23.4477 30 24 30H62C62.5523 30 63 29.5523 63 29V27ZM23 37C23 36.4477 23.4477 36 24 36H62C62.5523 36 63 36.4477 63 37V39C63 39.5523 62.5523 40 62 40H24C23.4477 40 23 39.5523 23 39V37ZM63 47C63 46.4477 62.5523 46 62 46H24C23.4477 46 23 46.4477 23 47V49C23 49.5523 23.4477 50 24 50H62C62.5523 50 63 49.5523 63 49V47ZM63 57C63 56.4477 62.5523 56 62 56H24C23.4477 56 23 56.4477 23 57V59C23 59.5523 23.4477 60 24 60H62C62.5523 60 63 59.5523 63 59V57Z" fill="url(#paint2_radial)"/>
</g>
<path d="M36 34.9951C36 35.5474 35.5523 35.9951 35 35.9951L13 35.998C11.8955 35.998 11 36.8935 11 37.998V37.998C11 36.7175 11.5088 35.4894 12.4144 34.584L34.5923 12.4113C35.4961 11.5077 36.7219 11 38 11V11C36.8964 11 36.0015 11.894 36 12.9973L36 34.9951Z" fill="white"/>
<path d="M36 34.9951C36 35.5474 35.5523 35.9951 35 35.9951L13 35.998C11.8955 35.998 11 36.8935 11 37.998V37.998C11 36.7175 11.5088 35.4894 12.4144 34.584L34.5923 12.4113C35.4961 11.5077 36.7219 11 38 11V11C36.8964 11 36.0015 11.894 36 12.9973L36 34.9951Z" fill="url(#paint3_radial)"/>
<defs>
<filter id="filter0_dd" x="18" y="23" width="50" height="44" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="2.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0431373 0 0 0 0 0.584314 0 0 0 0 0.552941 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="0.5"/>
<feGaussianBlur stdDeviation="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0431373 0 0 0 0 0.584314 0 0 0 0 0.552941 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow" result="effect2_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow" result="shape"/>
</filter>
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-34.3017 98.9515) rotate(-39.74) scale(164.675)">
<stop stop-color="#20C1B7"/>
<stop offset="1" stop-color="#007E76"/>
</radialGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(16.6471 16.6471) rotate(45) scale(82.5235 72.3085)">
<stop offset="0.0001" stop-color="#9FCCC4" stop-opacity="0.9"/>
<stop offset="0.588542" stop-color="#CEEAE5"/>
<stop offset="1" stop-color="#E2E9E8"/>
</radialGradient>
<radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.4721 21.3118) rotate(45) scale(46.2323 39.9804)">
<stop stop-color="#9FCCC4" stop-opacity="0.9"/>
<stop offset="0.413626" stop-color="#E1EFEC"/>
<stop offset="1" stop-color="white"/>
</radialGradient>
<radialGradient id="paint3_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-31.75 -33.9967) rotate(44.9979) scale(108.183 94.7922)">
<stop offset="0.0001" stop-color="#DFE9E7"/>
<stop offset="1" stop-color="white"/>
</radialGradient>
</defs>
</svg>
/**
* SPDX-FileCopyrightText: Copyright 2019 - 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: GPLv2
*/
/*
* Copyright (C) 2013 - 2014 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
import Nemo.Configuration 1.0
import Nemo.DBus 2.0
import Sailfish.Share 1.0
import Aurora.Office.Files 1.0
import Aurora.Office.License 1.0
import ru.omp.docviewer 1.0
Page {
id: page
property alias model: filteredModel.sourceModel
property string title
property string searchText: searchField.text
property bool searchEnabled
property QtObject provider
property string deletingSource
property bool _firstActive: true
property Dialog _licenseDialog
function deleteSource(source) {
pageStack.pop()
deletingSource = source
var popup = Remorse.popupAction(
page,
Remorse.deletedText,
function() {
provider.deleteFile(deletingSource)
deletingSource = ""
})
popup.canceled.connect(function() { deletingSource = "" })
}
function prepareMimeType(mimeType) {
if (mimeType === "text/csv") {
mimeType = "text/plain";
}
return mimeType
}
allowedOrientations: Orientation.All
onStatusChanged: {
if (_firstActive && status == PageStatus.Active && !licenseStatus.isAccepted) {
_firstActive = false
_licenseDialog = pageStack.push("../dialogs/AcceptLicenseDialog.qml", PageStackAction.Immediate)
}
}
onSearchEnabledChanged: {
if (pageStack.currentPage.status === PageStatus.Active) {
if (searchEnabled) {
//#bug OS-5091. Calling forceActiveFocus() cause flickering on long tap.
// Using timer to avoid it.
activeFocusTimer.running = true
} else {
searchField.focus = false
}
}
if (!searchEnabled) searchField.text = ""
}
function getSortParameterName(parameter) {
if (parameter === FilterModel.Name) {
//% "name"
return qsTrId("docviewer-me-sort_by_name")
} else if (parameter === FilterModel.Type) {
//% "type"
return qsTrId("docviewer-me-sort_by_type")
} else if (parameter === FilterModel.Date) {
//% "date"
return qsTrId("docviewer-me-sort_by_date")
}
return ""
}
function openDocument(url, doShow, unsupported) {
var _documentPage = pageStack.push(docPageComponent,
{
path: url,
trackerDocumentProvider: provider,
},
doShow ? PageStackAction.Immediate : PageStackAction.Animated)
applicationWindow.docView = _documentPage
? _documentPage._docView
: null
}
function pathToUrl(path) {
if (path.indexOf("file://") === 0) {
return path
}
return "file://" + path.split("/").map(encodeURIComponent).join("/")
}
Connections {
target: applicationWindow
onSearchRequest: {
page.searchEnabled = true
if (!searchField.activeFocus) {
activeFocusTimer.start()
}
applicationWindow.activate()
}
}
FilterModel {
id: filteredModel
filterRegExp: RegExp(escapeRegExp(searchText), "i")
function escapeRegExp(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
}
Timer {
id: activeFocusTimer
repeat: false
running: false
interval: 750
onTriggered: searchField.forceActiveFocus()
}
SilicaListView {
id: listView
anchors.fill: parent
model: filteredModel
currentIndex: -1 // otherwise currentItem will steal focus
header: Item {
width: listView.width
height: headerContent.height
}
Column {
id: headerContent
parent: listView.headerItem
width: parent.width
height: pageHeader.height + (searchEnabled ? searchField.height : 0)
Behavior on height {
NumberAnimation {
duration: 150
easing.type: Easing.InOutQuad
}
}
PageHeader {
id: pageHeader
title: qsTrId("docviewer-ap-name")
}
SearchField {
id: searchField
width: parent.width
opacity: page.searchEnabled ? 1.0 : 0.0
visible: opacity > 0
//: Document search field placeholder text
//% "Search documents"
placeholderText: qsTrId("docviewer-tf-search-documents")
// We prefer lowercase
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase | Qt.ImhNoPredictiveText
EnterKey.iconSource: "image://theme/icon-m-enter-close"
EnterKey.onClicked: focus = false
Behavior on opacity { FadeAnimation { duration: 150 } }
}
}
Connections {
target: searchField.activeFocus ? listView : null
ignoreUnknownSignals: true
onContentYChanged: {
if (listView.contentY > (Screen.height / 2)) {
searchField.focus = false
}
}
}
PullDownMenu {
id: menu
property bool _searchEnabled
// avoid changing text state while menu is open
onActiveChanged: {
if (active) {
_searchEnabled = page.searchEnabled
}
}
MenuItem {
text: !menu._searchEnabled ? //% "Show search"
qsTrId("docviewer-me-show_search")
//% "Hide search"
: qsTrId("docviewer-me-hide_search")
onClicked: page.searchEnabled = !page.searchEnabled
}
MenuItem {
//% "Sort by: %1"
text: qsTrId("docviewer-me-sort_by").arg(getSortParameterName(filteredModel.sortParameter))
onClicked: {
var obj = pageStack.animatorPush("SortTypeSelectionPage.qml")
obj.pageCompleted.connect(function(page) {
page.sortSelected.connect(function(sortParameter) {
filteredModel.sortParameter = sortParameter
pageStack.pop()
})
})
}
}
}
InfoLabel {
parent: listView.contentItem
y: listView.headerItem.y + pageHeader.height + searchField.height + (page.isPortrait ? Theme.itemSizeMedium : Theme.paddingLarge)
//: View placeholder shown when there are no documents
//% "No documents"
text: page.provider.count === 0
? qsTrId("docviewer-la-no_documents")
: //% "No documents found"
qsTrId("docviewer-la-not-found")
opacity: (page.provider.ready && page.provider.count === 0) || (searchText.length > 0 && listView.count == 0) ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
}
delegate: ListItem {
id: listItem
contentHeight: Theme.itemSizeMedium
hidden: deletingSource === model.filePath
Image {
id: icon
anchors {
left: parent.left
leftMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
}
source: Theme.iconForMimeType(model.fileMimeType) + (highlighted ? "?" + Theme.highlightColor : "")
}
Column {
anchors {
left: icon.right
leftMargin: Theme.paddingMedium
right: parent.right
rightMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
}
Label {
id: label
width: parent.width
color: listItem.highlighted ? Theme.highlightColor : Theme.primaryColor
text: searchText.length > 0 ? Theme.highlightText(model.fileName, searchText, Theme.highlightColor)
: model.fileName
textFormat: searchText.length > 0 ? Text.StyledText : Text.PlainText
font.pixelSize: Theme.fontSizeMedium
truncationMode: TruncationMode.Fade
}
Item {
width: parent.width
height: sizeLabel.height
Label {
id: sizeLabel
text: Format.formatFileSize(model.fileSize)
font.pixelSize: Theme.fontSizeExtraSmall
color: listItem.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
}
Label {
id: dateLabel
anchors.right: parent.right
text: "%1, %2".arg(Format.formatDate(model.fileRead, Format.TimeValue)).arg(Qt.formatDate(model.fileRead, Qt.DefaultLocaleShortDate))
font.pixelSize: Theme.fontSizeExtraSmall
color: listItem.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
Connections {
target: timeFormatConfig
onValueChanged: dateLabel.text = Qt.binding(function () {return "%1, %2".arg(Format.formatDate(model.fileRead, Format.TimeValue)).arg(Qt.formatDate(model.fileRead, Qt.DefaultLocaleShortDate))})
}
}
}
}
onClicked: {
console.log("model.fileDocumentClass " + model.fileDocumentClass + ", model.fileMimeType " + model.fileMimeType)
if (model.fileDocumentClass === DocumentListModel.UnknownDocument) {
console.log("Unknown file format for file " + model.fileName + " with stated mimetype " + model.fileMimeType)
openDocument(model.filePath, false, true)
} else {
openDocument(model.filePath, false, false)
}
}
function deleteFile() {
remorseDelete(function() { page.provider.deleteFile(model.filePath) })
}
// TODO: transitions disabled until they don't anymore confuse SilicaListView positioning. JB#33215
//ListView.onAdd: AddAnimation { target: listItem }
//ListView.onRemove: RemoveAnimation { target: listItem }
menu: Component {
ContextMenu {
id: contextMenu
MenuItem {
//: Share a file
//% "Share"
text: qsTrId("docviewer-la-share")
onClicked: {
shareAction.resources = [pathToUrl(model.filePath)]
shareAction.trigger()
}
ShareAction {
id: shareAction
}
}
MenuItem {
//: Delete a file from the device
//% "Delete"
text: qsTrId("docviewer-me-delete")
onClicked: {
listItem.deleteFile()
}
}
}
}
}
VerticalScrollDecorator { }
}
Component {
id: docPageComponent
DocumentPage { }
}
LicenseStatus {
id: licenseStatus
}
ConfigurationValue {
id: timeFormatConfig
key: "/sailfish/i18n/lc_timeformat24h"
}
DBusAdaptor {
function openFile(url) {
if (url.length === 0) {
applicationWindow.activate()
return
}
if (pageStack.depth > 1) {
if (_licenseDialog === null) {
while (pageStack.depth > 1) {
pageStack.pop(undefined, PageStackAction.Immediate)
}
openDocument(url, true, false)
applicationWindow.activate()
} else {
_licenseDialog.acceptDestinationAction = PageStackAction.Replace
_licenseDialog.acceptDestinationProperties = {
path: url,
trackerDocumentProvider: provider,
}
_licenseDialog.acceptDestination = "ru.omp.docviewer.DocumentPage"
_licenseDialog.acceptDestinationInstance.statusChanged.connect(_documetPageReturn)
applicationWindow.activate()
}
} else {
openDocument(url, true, false)
applicationWindow.activate()
}
}
function _documetPageReturn() {
if (_licenseDialog.acceptDestinationInstance.status === PageStatus.Active) {
_licenseDialog.acceptDestinationInstance.statusChanged.disconnect(_documetPageReturn)
_licenseDialog = null
}
}
service: "ru.omp.DocViewer"
path: "/ru/omp/docviewer"
iface: "ru.omp.DocViewer"
}
}
/*
* Copyright (c) 2020 - 2022 Open Mobile Platform LLC
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
import Aurora.Office.Files 1.0
Page {
id: root
signal sortSelected(int sortType)
SilicaListView {
anchors.fill: parent
model: sortModel
header: PageHeader {
//% "Sort by"
title: qsTrId("docviewer-he-sort_by")
}
delegate: BackgroundItem {
Label {
x: Theme.horizontalPageMargin
anchors.verticalCenter: parent.verticalCenter
text: name
color: highlighted ? Theme.highlightColor : Theme.primaryColor
}
onClicked: root.sortSelected(sortType)
}
VerticalScrollDecorator {}
}
ListModel {
id: sortModel
ListElement {
sortType: FilterModel.Name
//: Sort by name
//% "Name"
name: qsTrId("docviewer-me-sort_name")
}
ListElement {
sortType: FilterModel.Type
//: Sort by type
//% "Type"
name: qsTrId("docviewer-me-sort_type")
}
ListElement {
sortType: FilterModel.Date
//: Sort by date
//% "Date"
name: qsTrId("docviewer-me-sort_date")
}
}
}
......@@ -3,11 +3,13 @@ Type=Application
X-Nemo-Application-Type=silica-qt5
Icon=ru.auroraos.DocumentConverter
Exec=/usr/bin/ru.auroraos.DocumentConverter
MimeType=application/vnd.oasis.opendocument.spreadsheet;application/x-kspread;application/vnd.ms-excel;text/csv;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;application/vnd.openxmlformats-officedocument.spreadsheetml.template;application/vnd.oasis.opendocument.presentation;application/vnd.oasis.opendocument.presentation-template;application/x-kpresenter;application/vnd.ms-powerpoint;application/vnd.openxmlformats-officedocument.presentationml.presentation;application/vnd.openxmlformats-officedocument.presentationml.template;application/vnd.oasis.opendocument.text-master;application/vnd.oasis.opendocument.text;application/vnd.oasis.opendocument.text-template;application/msword;application/rtf;text/plain;application/x-mswrite;application/vnd.openxmlformats-officedocument.wordprocessingml.document;application/vnd.openxmlformats-officedocument.wordprocessingml.template;application/vnd.ms-works;
Name=Document Converter
Name[ru]=Конвертер Документов
[X-Application]
Permissions=RemovableMedia;UserDirs
Permissions=UserDirs;MediaIndexing;RemovableMedia
OrganizationName=ru.auroraos
ApplicationName=DocumentConverter
ExecDBus=/usr/bin/ru.auroraos.DocumentConverter
/**
* SPDX-FileCopyrightText: Copyright 2019 - 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: GPLv2
*/
/*
* Copyright (C) 2013-2014 Jolla Ltd.
* Contact: Robin Burchell <robin.burchell@jolla.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "documentlistmodel.h"
#include <QDir>
struct DocumentListModelEntry
{
QString fileName;
QString filePath;
QString fileType;
int fileSize;
QDateTime fileRead;
QString mimeType;
DocumentListModel::DocumentClass documentClass;
bool dirty; // When true, should be removed from list.
};
class DocumentListModel::Private
{
public:
Private()
{
roles.insert(FileNameRole, "fileName");
roles.insert(FilePathRole, "filePath");
roles.insert(FileTypeRole, "fileType");
roles.insert(FileSizeRole, "fileSize");
roles.insert(FileReadRole, "fileRead");
roles.insert(FileMimeTypeRole, "fileMimeType");
roles.insert(FileDocumentClass, "fileDocumentClass");
roles.insert(FileTypeAndNameRole, "fileTypeAndNameRole");
}
QList<DocumentListModelEntry> entries;
QHash<int, QByteArray> roles;
};
DocumentListModel::DocumentListModel(QObject *parent)
: QAbstractListModel(parent)
, d(new Private)
{}
DocumentListModel::~DocumentListModel() {}
QVariant DocumentListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= d->entries.count())
return QVariant();
switch (role) {
case FileNameRole:
return d->entries.at(index.row()).fileName;
case FilePathRole:
return d->entries.at(index.row()).filePath;
case FileTypeRole:
return d->entries.at(index.row()).fileType;
case FileSizeRole:
return d->entries.at(index.row()).fileSize;
case FileReadRole:
return d->entries.at(index.row()).fileRead;
case FileMimeTypeRole:
return d->entries.at(index.row()).mimeType;
case FileDocumentClass:
return d->entries.at(index.row()).documentClass;
case FileTypeAndNameRole:
return QString("%1_%2").arg(d->entries.at(index.row()).fileType, d->entries.at(index.row()).fileName);
default:
break;
}
return QVariant();
}
int DocumentListModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return d->entries.count();
}
QHash<int, QByteArray> DocumentListModel::roleNames() const
{
return d->roles;
}
void DocumentListModel::setAllItemsDirty(bool status)
{
for (auto entry = d->entries.begin(); entry != d->entries.end(); ++entry) {
entry->dirty = status;
}
}
void DocumentListModel::addItem(QString name, QString path, QString type, int size, QDateTime lastRead, QString mimeType)
{
// We sometimes get duplicate entries... and that's kind of silly.
int row = 0;
for (auto entry = d->entries.begin(); entry != d->entries.end(); ++entry, ++row) {
if (entry->filePath == path) {
entry->dirty = false;
entry->fileType = type;
entry->fileSize = size;
entry->fileRead = lastRead;
entry->mimeType = mimeType;
entry->documentClass = static_cast<DocumentClass>(mimeTypeToDocumentClass(mimeType));
emit dataChanged(index(row), index(row));
return;
}
}
DocumentListModelEntry entry;
entry.dirty = false;
entry.fileName = name;
entry.filePath = path;
entry.fileType = type;
entry.fileSize = size;
entry.fileRead = lastRead;
entry.mimeType = mimeType;
entry.documentClass = static_cast<DocumentClass>(mimeTypeToDocumentClass(mimeType));
int index = 0;
for (; index < d->entries.count(); ++index) {
if (d->entries.at(index).fileRead < entry.fileRead)
break;
}
beginInsertRows(QModelIndex(), index, index);
d->entries.insert(index, entry);
endInsertRows();
emit rowCountChanged();
}
void DocumentListModel::removeItemsDirty()
{
for (int index = 0; index < d->entries.count();) {
if (d->entries.at(index).dirty) {
beginRemoveRows(QModelIndex(), index, index);
emit fileDeleted(d->entries.at(index).filePath);
d->entries.removeAt(index);
endRemoveRows();
emit rowCountChanged();
} else {
++index;
}
}
}
void DocumentListModel::removeAt(int index)
{
if (index > -1 && index < d->entries.count()) {
beginRemoveRows(QModelIndex(), index, index);
d->entries.removeAt(index);
endRemoveRows();
emit rowCountChanged();
}
}
void DocumentListModel::clear()
{
beginResetModel();
d->entries.clear();
endResetModel();
emit rowCountChanged();
}
int DocumentListModel::mimeTypeToDocumentClass(QString mimeType) const
{
DocumentClass documentClass = UnknownDocument;
if (mimeType == QLatin1String("application/vnd.oasis.opendocument.text") || mimeType == QLatin1String("application/msword")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.wordprocessing")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.wordprocessingml.document")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.wordprocessingml.template")
|| mimeType == QLatin1String("application/vnd.ms-word.document.macroEnabled.12")
|| mimeType == QLatin1String("application/vnd.ms-word.template.macroEnabled.12") || mimeType == QLatin1String("application/rtf")) {
documentClass = TextDocument;
} else if (mimeType == QLatin1String("text/plain")) {
documentClass = PlainTextDocument;
} else if (mimeType == QLatin1String("application/vnd.oasis.opendocument.presentation")
|| mimeType == QLatin1String("application/vnd.ms-powerpoint")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.presentationml.presentation")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.presentationml.template")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.presentationml.slideshow")
|| mimeType == QLatin1String("application/vnd.ms-powerpoint.presentation.macroEnabled.12")
|| mimeType == QLatin1String("application/vnd.ms-powerpoint.template.macroEnabled.12")
|| mimeType == QLatin1String("application/vnd.ms-powerpoint.slideshow.macroEnabled.12")) {
documentClass = PresentationDocument;
} else if (mimeType == QLatin1String("application/vnd.oasis.opendocument.spreadsheet") || mimeType == QLatin1String("application/vnd.ms-excel")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|| mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.spreadsheetml.template")
|| mimeType == QLatin1String("application/vnd.ms-excel.sheet.macroEnabled")
|| mimeType == QLatin1String("application/vnd.ms-excel.sheet.macroEnabled.12")
|| mimeType == QLatin1String("application/vnd.ms-excel.template.macroEnabled.12") || mimeType == QLatin1String("text/csv")) {
documentClass = SpreadSheetDocument;
} else if (mimeType == QLatin1String("application/pdf")) {
documentClass = PDFDocument;
}
return documentClass;
}
QVariantMap DocumentListModel::getFileInfo(const QString &filePath)
{
const auto fileInfo = QFileInfo{filePath};
return QVariantMap{
{ "filePath", fileInfo.filePath() },
{ "fileName", fileInfo.fileName() },
{ "baseName", fileInfo.baseName() },
{ "suffix", fileInfo.suffix() }
};
}
/**
* SPDX-FileCopyrightText: Copyright 2019 - 2023 Open Mobile Platform LLC <community@omp.ru>
* SPDX-License-Identifier: GPLv2
*/
/*
* Copyright (C) 2013-2014 Jolla Ltd.
* Contact: Robin Burchell <robin.burchell@jolla.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DOCUMENTLISTMODEL_H
#define DOCUMENTLISTMODEL_H
#include <QAbstractListModel>
#include <qdatetime.h>
class DocumentListModelPrivate;
class DocumentListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
public:
enum DocumentClass
{
UnknownDocument,
TextDocument,
PlainTextDocument,
SpreadSheetDocument,
PresentationDocument,
PDFDocument
};
Q_ENUMS(DocumentClass)
enum Roles
{
FileNameRole = Qt::UserRole + 1,
FilePathRole,
FileTypeRole,
FileSizeRole,
FileReadRole,
FileMimeTypeRole,
FileDocumentClass,
FileTypeAndNameRole
};
DocumentListModel(QObject *parent = 0);
~DocumentListModel();
DocumentListModel(const DocumentListModel &) = delete;
DocumentListModel &operator=(const DocumentListModel &) = delete;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const;
virtual QHash<int, QByteArray> roleNames() const;
void setAllItemsDirty(bool status);
void addItem(QString name, QString path, QString type, int size, QDateTime lastRead, QString mimeType);
void removeItemsDirty();
void removeAt(int index);
void clear();
Q_INVOKABLE int mimeTypeToDocumentClass(QString mimeType) const;
Q_INVOKABLE static QVariantMap getFileInfo(const QString &filePath);
signals:
void fileDeleted(const QString &filePath);
void rowCountChanged();
private:
class Private;
const QScopedPointer<Private> d;
};
#endif // DOCUMENTLISTMODEL_H
/*
* Copyright (C) 2013-2014 Jolla Ltd.
* Contact: Robin Burchell <robin.burchell@jolla.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "documentprovider.h"
class DocumentProvider::Private
{
public:
Private() {}
QUrl page;
};
DocumentProvider::DocumentProvider(QObject *parent)
: QObject(parent)
, d(new Private)
{}
DocumentProvider::~DocumentProvider()
{
delete d;
}
QString DocumentProvider::setupPageUrl() const
{
return QString();
}
bool DocumentProvider::needsSetup() const
{
return false;
}
QUrl DocumentProvider::page() const
{
return d->page;
}
void DocumentProvider::setPage(const QUrl &url)
{
d->page = url;
emit pageChanged();
}
void DocumentProvider::deleteFile(const QUrl &file)
{
Q_UNUSED(file);
qWarning("Provider does not implement file deletion.");
}
/*
* Copyright (C) 2013-2014 Jolla Ltd.
* Contact: Robin Burchell <robin.burchell@jolla.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DOCUMENTPROVIDER_H
#define DOCUMENTPROVIDER_H
#include <QObject>
#include <QUrl>
#include <QtGui/QImage>
class DocumentProvider : public QObject
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QUrl icon READ icon NOTIFY iconChanged)
Q_PROPERTY(QUrl thumbnail READ thumbnail NOTIFY thumbnailChanged)
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
Q_PROPERTY(QObject *model READ model NOTIFY modelChanged)
Q_PROPERTY(bool ready READ isReady NOTIFY readyChanged)
Q_PROPERTY(QUrl page READ page WRITE setPage NOTIFY pageChanged)
Q_PROPERTY(QString setupPageUrl READ setupPageUrl NOTIFY titleChanged)
Q_PROPERTY(bool needsSetup READ needsSetup NOTIFY needsSetupChanged)
public:
DocumentProvider(QObject *parent = 0);
virtual ~DocumentProvider();
virtual int count() const = 0;
virtual QUrl icon() const = 0;
virtual QString title() const = 0;
virtual QString description() const = 0;
virtual QObject *model() const = 0;
virtual QUrl thumbnail() const = 0;
virtual bool isReady() const = 0;
// Reimplement this and return the name of a QML file containing the account setup
// for this provider, if applicable. Otherwise a no-setup provider will be assumed.
virtual QString setupPageUrl() const;
virtual bool needsSetup() const;
QUrl page() const;
void setPage(const QUrl &url);
Q_INVOKABLE virtual void deleteFile(const QUrl &file);
signals:
void countChanged();
void iconChanged();
void thumbnailChanged();
void pageChanged();
void titleChanged();
void modelChanged();
void readyChanged();
void needsSetupChanged();
void fileDeleted(const QString &filePath);
private:
class Private;
Private *d;
};
Q_DECLARE_INTERFACE(DocumentProvider, "DocumentProviderInterface/1.0")
#endif // DOCUMENTPROVIDER_H
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать