Коммит 6b3f0d9b создал по автору OMP Education's avatar OMP Education Зафиксировано автором Vladislav Larionov
Просмотр файлов

[Project] Implement Document Converter

владелец 6a29bf9c
*.tgz filter=lfs diff=lfs merge=lfs -text
*.tar.gz filter=lfs diff=lfs merge=lfs -text
*.tar.xz filter=lfs diff=lfs merge=lfs -text
*.tar.bz2 filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
application/LibreOfficeKit
Makefile
application/Makefile
.apptool
.DS_Store
.mb2
.vscode
CMakeCache.txt
CMakeFiles
Makefile
QtCreatorDeployment.txt
RPMS
cmake_install.cmake
install_manifest.txt
*.autosave
*.list
*.md.backup
*.moc
*.o
*.pro.user*
*.qm
*~
*_autogen
CMakeLists.txt.user*
moc_*.cpp
application/moc_*.cpp
application/ru.auroraos.DocumentConverter
libs_build
[submodule "upstream"]
path = upstream
url = https://github.com/LibreOffice/core.git
# Authors
* Kirill Chuvilin, <k.chuvilin@omp.ru>
* Product owner, 2023
* Maintainer, 2023
* Konstantin Zvyagin, <k.zvyagin@omp.ru>
* Reviewer, 2023
* Anton Zernin, <a.zernin@omp.ru>
* Developer, 2023
* Oksana Torosyan, <o.torosyan@omp.ru>
* Designer, 2024
* Vladislav Larionov
* Reviewer, 2023
# Document Converter
This project provides an example using LibreOffice to converting documents.
## Terms of Use and Participation
The source code of the project is provided under [the license](LICENSE.BSD-3-Clause.md),
which allows its use in third-party applications.
The [contributor agreement](CONTRIBUTING.md) documents the rights granted by contributors
of the Open Mobile Platform.
Information about the contributors is specified in the [AUTHORS](AUTHORS.md) file.
[Code of conduct](CODE_OF_CONDUCT.md) is a current set of rules of the Open Mobile
Platform which informs you how we expect the members of the community will interact
while contributing and communicating.
## Project Structure
The project has a standard structure
of an application based on C++ and QML for Aurora OS.
* **[application](application)** directory contains the application source code:
* **[application.pro](application/application.pro)** file
describes the structure of the application for the qmake build system.
* **[icons](application/icons)** directory contains the application icons for different screen resolutions.
* **[qml](application/qml)** directory contains the QML source code and the UI resources.
* **[cover](application/qml/cover)** directory contains the application cover implementations.
* **[icons](application/qml/icons)** directory contains the additional custom UI icons.
* **[pages](application/qml/pages)** directory contains the application pages.
* **[DocumentConverter.qml](application/qml/DocumentConverter.qml)** file
provides the application window implementation.
* **[translations](application/translations)** directory contains the UI translation files.
* **[src](application/src)** directory contains the C++ source code.
* **[main.cpp](application/src/main.cpp)** file is the application entry point.
* **[ru.auroraos.DocumentConverter.desktop](application/ru.auroraos.DocumentConverter.desktop)** file
defines the display and parameters for launching the application.
* **[rpm](rpm)** directory contains the rpm-package build settings.
* **[ru.auroraos.DocumentConverter.spec](rpm/ru.auroraos.DocumentConverter.spec)** file is used by rpmbuild tool.
* **[ru.auroraos.DocumentConverter.pro](application/ru.auroraos.DocumentConverter.pro)** file
describes the project that contains two subprojects where the first is responsible
for building the libreoffice, and the second describes the structure of the application for
the qmake build system.
* **[upstream](upstream)** directory contains source code LibreOffice (git submodule).
* **[tarballs](tarballs)** directory of dependencies in the form of archives necessary for the build LibreOffice.
* **[libs](libs)** directory of dependencies in the form of source codes necessary for the build LibreOffice.
## Compatibility
The project is compatible with all the current versions of the Aurora OS.
## Project Building
### Clear building
1. Make sure that you have 32 GB of RAM and SDK with docker (don't use VB for building this example).
1. Open a terminal or command prompt.
1. Navigate to the directory that contains your Git repository.
1. Execute the command "git lfs pull" to download any files tracked by LFS.
1. Execute the command "git submodule update --init --recursive" to update and initialize submodules in the repository.
1. Execute the command "mb2 -t AuroraOS-5.0.0.60-base-armv7hl build-init" to initialize the build environment.
1. Execute the command "mb2 -t AuroraOS-5.0.0.60-base-armv7hl prepare" to apply the patches needed for the build.
1. Execute the command "mb2 -t AuroraOS-5.0.0.60-base-armv7hl build" to start building the package.
1. Execute the command to sign the rpm-package:
```
sfdk engine exec rpmsign-external sign \
--key absolute/path/to/key/file.pem \
--cert absolute/path/to/cert/file.pem \
absolute/path/to/rpm/package.rpm
```
The target rpm-package is in the RPMS directory of the project.
### Solutions of possible problems
If building is failed with the next error
```
+ aclocal -I <path/to>/DocumentConverter/upstream/m4
autom4te: error: need GNU m4 1.4 or later: /usr/bin/m4
aclocal: error: echo failed with exit status: 1
```
then enter into the target and install the m4 dependency manually.
### Repeated building for another target
The build is run in the same directory as the application sources so it's necessary to delete the previous building results before a new build for another target.
Run the next commands from the project root directory:
1. `rm -fr libs_build`
2. `rm -fr upstream/workdir`
3. `rm -f application/Makefile`
4. `cd libs/liblangtag && make distclean`
## Screenshots
![screenshots](screenshots/screenshots.png)
## This document in Russian / Перевод этого документа на русский язык
- [README.ru.md](README.ru.md)
# Конвертер Документов
Проект предоставляет пример использования LibreOffice для конвертирования документов.
## Условия использования и участия
Исходный код проекта предоставляется по [лицензии](LICENSE.BSD-3-Clause.md),
которая позволяет использовать его в сторонних приложениях.
[Соглашение участника](CONTRIBUTING.md) регламентирует права,
предоставляемые участниками компании «Открытая Мобильная Платформа».
Информация об участниках указана в файле [AUTHORS](AUTHORS.md).
[Кодекс поведения](CODE_OF_CONDUCT.md) — это действующий набор правил
компании «Открытая Мобильная Платформа»,
который информирует об ожиданиях по взаимодействию между членами сообщества при общении и работе над проектами.
## Структура проекта
Проект имеет стандартную структуру приложения на базе C++ и QML для ОС Аврора.
* Каталог **[application](application)** содержит исходный код приложения:
* Файл **[application.pro](application/application.pro)** описывает структуру проекта для системы сборки qmake.
* Каталог **[icons](app/icons)** содержит иконки приложения для поддерживаемых разрешений экрана.
* Каталог **[qml](application/qml)** содержит исходный код на QML и ресурсы интерфейса пользователя.
* Каталог **[cover](application/qml/cover)** содержит реализации обложек приложения.
* Каталог **[icons](application/qml/icons)** содержит дополнительные иконки интерфейса пользователя.
* Каталог **[pages](application/qml/pages)** содержит страницы приложения.
* Файл **[DocumentConverter.qml](application/qml/pages/DocumentConverter.qml)**
предоставляет реализацию окна приложения.
* Каталог **[translations](application/translations)** содержит файлы перевода интерфейса пользователя.
* Каталог **[src](application/src)** содержит исходный код на C++.
* Файл **[main.cpp](application/src/main.cpp)** является точкой входа в приложение.
* Файл **[ru.auroraos.DocumentConverter.desktop](application/ru.auroraos.DocumentConverter.desktop)**
определяет отображение и параметры запуска приложения.
* Каталог **[rpm](rpm)** содержит настройки сборки rpm-пакета.
* Файл **[ru.auroraos.DocumentConverter.spec](rpm/ru.auroraos.DocumentConverter.spec)**
используется инструментом rpmbuild.
* Файл **[ru.auroraos.DocumentConverter.pro](application/ru.auroraos.DocumentConverter.pro)**
описывает проект, который содержит два подпроекта, первый отвечает за сборку libreoffice,
второй описывает структуру приложения для системы сборки qmake.
* Каталог **[upstream](upstream)** содержит исходный код библиотеки LibreOffice (подмодуль git).
* Каталог **[tarballs](tarballs)** содержит зависимости в форме архивов, необходимые для сборки библиотеки LibreOffice.
* Каталог **[libs](libs)** содержит зависимости в форме исходного кода, необходимые для сборки библиотеки LibreOffice.
## Совместимость
Проект совместим с актуальными версиями ОС Аврора.
## Сборка проекта
### Чистовая сборка
1. Убедитесь, что у вас есть 32 ГБ оперативной памяти и SDK с docker (не используйте VB для сборки этого примера).
1. Откройте терминал или командную строку.
1. Перейдите в каталог, содержащий ваш Git-репозиторий.
1. Выполните команду "git lfs pull", чтобы загрузить все файлы, отслеживаемые LFS.
1. Выполните команду "git submodule update --init --recursive", чтобы обновить и инициализировать все подмодули в репозитории.
1. Выполните команду "mb2 -t AuroraOS-5.0.0.60-base-armv7hl build-init", чтобы инициализировать окружение сборки.
1. Выполните команду "mb2 -t AuroraOS-5.0.0.60-base-armv7hl prepare", чтобы применить патчи, необходимые для сборки.
1. Выполните команду "mb2 -t AuroraOS-5.0.0.60-base-armv7hl build", чтобы начать сборку пакета.
1. Выполните команду для подписи rpm-пакета:
```
sfdk engine exec rpmsign-external sign \
--key absolute/path/to/key/file.pem \
--cert absolute/path/to/cert/file.pem \
absolute/path/to/rpm/package.rpm
```
Целевой rpm-пакет находится в каталоге RPMS.
### Решение возможных проблем
Если сборка проекта упала со следующей ошибкой
```
+ aclocal -I <path/to>/DocumentConverter/upstream/m4
autom4te: error: need GNU m4 1.4 or later: /usr/bin/m4
aclocal: error: echo failed with exit status: 1
```
то требуется зайти в таргет и установить вручную зависимость m4.
### Повторная сборка под другой таргет
Поскольку сборка проходит в той же самой директории, что и основной исходный код, перед сборкой под новый таргет требуется удалить результат предыдущий сборки.
Для этого требуется выполнить следующие команды из корня проекта:
1. `rm -fr libs_build`
2. `rm -fr upstream/workdir`
3. `rm -f application/Makefile`
4. `cd libs/liblangtag && make distclean`
## Снимки экранов
![screenshots](screenshots/screenshots.png)
## This document in English
- [README.md](README.md)
# SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
# SPDX-License-Identifier: BSD-3-Clause
TARGET = ru.auroraos.DocumentConverter
CONFIG += \
auroraapp
PKGCONFIG += \
SOURCES += \
src/converter.cpp \
src/main.cpp \
HEADERS += \
src/converter.h
INCLUDEPATH += \
LibreOfficeKit
LIBS += -ldl
DISTFILES += \
qml/DocumentConverter.qml \
qml/pages/MainPage.qml \
qml/pages/ConvertPage.qml \
qml/cover/DefaultCoverPage.qml
AURORAAPP_ICONS = 86x86 108x108 128x128 172x172
CONFIG += auroraapp_i18n
TRANSLATIONS += \
translations/ru.auroraos.DocumentConverter.ts \
translations/ru.auroraos.DocumentConverter-ru.ts \
translations.path = /usr/share/$${TARGET}/translations
translations.files = $$TRANSLATIONS
INSTALLS += \
translations
libs_install.path = /usr/share/ru.auroraos.DocumentConverter/lib/libreoffice/program
libs_install.commands = ln -sf $${PWD}/../libs_build/hunspell/res/lib/libhunspell-1.7.so $${PWD}/../libs_build/hunspell/res/lib/libhunspell-1.6.so.0
libs_install.files = \
$${PWD}/../libs_build/hunspell/res/lib/*.so* \
$${PWD}/../libs_build/liblangtag/lib/*.so*
INSTALLS += \
libs_install
// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
import QtQuick 2.0
import Sailfish.Silica 1.0
......@@ -6,4 +8,4 @@ ApplicationWindow {
initialPage: Qt.resolvedUrl("pages/MainPage.qml")
cover: Qt.resolvedUrl("cover/DefaultCoverPage.qml")
allowedOrientations: defaultAllowedOrientations
}
\ Нет новой строки в конце файла
}
// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
import QtQuick 2.0
import Sailfish.Silica 1.0
CoverBackground {
objectName: "defaultCover"
CoverPlaceholder {
objectName: "placeholder"
text: qsTr("Document Converter")
icon {
source: Qt.resolvedUrl("../icons/icon-document-converter.svg")
sourceSize {
width: icon.width
height: icon.height
}
}
forceFit: true
}
}
<svg width="86" height="86" viewBox="0 0 86 86" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_72)">
<mask id="mask0_1_72" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="86" height="86">
<path d="M0 30.0246C0 14.8691 0 9.41638 4.70819 4.70819C9.41638 0 14.8691 0 32.1495 0H53.8505C71.1308 0 76.5836 0 81.2918 4.70819C86 9.41638 86 14.8691 86 32.1495V53.8505C86 71.1308 86 76.5836 81.2918 81.2918C76.5836 86 71.1308 86 53.8505 86H32.1495C14.8691 86 9.41638 86 4.70819 81.2918C0 76.5836 0 71.1308 0 53.8505V30.0246Z" fill="white"/>
</mask>
<g mask="url(#mask0_1_72)">
<rect width="86" height="86" fill="url(#paint0_radial_1_72)"/>
<path d="M63.4575 37.1763L72.9954 46.7142V69.6448C72.9954 71.5002 71.4914 73.0042 69.636 73.0042H48.3595C46.5041 73.0042 45 71.5002 45 69.6448L45 40.5357C45 38.6803 46.5041 37.1763 48.3595 37.1763H63.4575Z" fill="white"/>
<path d="M68.5163 56.7668L49.4794 56.7668V55.647L68.5163 55.647V56.7668Z" fill="#BFF99B"/>
<path d="M68.5163 60.6862L49.4794 60.6862V59.5663L68.5163 59.5663V60.6862Z" fill="#BFF99B"/>
<path d="M49.4794 64.6055L68.5163 64.6055V63.4857L49.4794 63.4857V64.6055Z" fill="#BFF99B"/>
<path opacity="0.7" d="M63.4504 37.1702V44.4799C63.4504 45.7168 64.4532 46.7195 65.6901 46.7195H72.9997L63.4504 37.1702Z" fill="#AFFFA8"/>
</g>
<g clip-path="url(#clip1_1_72)">
<path d="M31.4575 13.0063L40.9954 22.5443V45.4748C40.9954 47.3302 39.4914 48.8343 37.636 48.8343H16.3595C14.5041 48.8343 13 47.3302 13 45.4748L13 16.3657C13 14.5104 14.5041 13.0063 16.3595 13.0063H31.4575Z" fill="white"/>
<path d="M36.5163 32.5968L17.4794 32.5968V31.477L36.5163 31.477V32.5968Z" fill="#BFF99B"/>
<path d="M36.5163 36.5162L17.4794 36.5162V35.3964L36.5163 35.3964V36.5162Z" fill="#BFF99B"/>
<path d="M17.4794 40.4355L36.5163 40.4355V39.3157L17.4794 39.3157V40.4355Z" fill="#BFF99B"/>
<path opacity="0.7" d="M31.4504 13.0002V20.3099C31.4504 21.5468 32.4532 22.5495 33.6901 22.5495H40.9997L31.4504 13.0002Z" fill="#AFFFA8"/>
<g filter="url(#filter0_i_1_72)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M51.5081 13C53.2209 12.9992 54.9165 13.3421 56.4944 14.0085C58.0777 14.6771 59.5101 15.6576 60.7063 16.8916C61.9025 18.1256 62.838 19.5878 63.457 21.1911C63.9234 22.3991 64.203 23.6684 64.2883 24.9556C64.3252 25.5117 64.771 25.968 65.3283 25.968H67.4805C68.3577 25.968 68.8098 27.017 68.2074 27.6547L62.7336 33.4486C62.339 33.8663 61.6744 33.8663 61.2798 33.4486L55.806 27.6547C55.2036 27.017 55.6556 25.968 56.5329 25.968H58.5626C59.1068 25.968 59.5577 25.5313 59.5027 24.9898C59.4304 24.2791 59.2634 23.5796 59.0049 22.9101C58.6166 21.9045 58.0299 20.9874 57.2796 20.2134C56.5293 19.4394 55.6309 18.8244 54.6378 18.405C53.6474 17.9868 52.5831 17.7717 51.5081 17.7725V17.7765L49 17.7765C48.4477 17.7765 48 17.3288 48 16.7765V14C48 13.4477 48.4477 13 49 13H51.5081Z" fill="white"/>
</g>
<g filter="url(#filter1_i_1_72)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M34.4919 73C32.7791 73.0008 31.0835 72.6579 29.5056 71.9915C27.9223 71.3229 26.4899 70.3424 25.2937 69.1084C24.0975 67.8744 23.162 66.4122 22.543 64.8089C22.0766 63.6009 21.797 62.3316 21.7117 61.0444C21.6748 60.4883 21.229 60.032 20.6717 60.032L18.5195 60.032C17.6423 60.032 17.1902 58.9829 17.7926 58.3453L23.2664 52.5514C23.661 52.1337 24.3256 52.1337 24.7202 52.5514L30.194 58.3453C30.7964 58.9829 30.3444 60.032 29.4671 60.032L27.4374 60.032C26.8932 60.032 26.4423 60.4687 26.4973 61.0102C26.5696 61.7209 26.7366 62.4204 26.9951 63.0899C27.3834 64.0955 27.9701 65.0126 28.7204 65.7866C29.4707 66.5606 30.3691 67.1756 31.3622 67.595C32.3526 68.0132 33.4169 68.2283 34.4919 68.2275L34.4919 68.2235L37 68.2235C37.5523 68.2235 38 68.6712 38 69.2235L38 72C38 72.5523 37.5523 73 37 73L34.4919 73Z" fill="white"/>
</g>
</g>
</g>
<defs>
<filter id="filter0_i_1_72" x="48" y="13" width="20.4824" height="20.7618" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<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" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="2.91062"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.98 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1_72"/>
</filter>
<filter id="filter1_i_1_72" x="17.5176" y="52.2382" width="20.4824" height="20.7618" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<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" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="2.91062"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.98 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1_72"/>
</filter>
<radialGradient id="paint0_radial_1_72" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="rotate(45) scale(121.622)">
<stop stop-color="#17B53A"/>
<stop offset="1" stop-color="#0CA324"/>
</radialGradient>
<clipPath id="clip0_1_72">
<rect width="86" height="86" fill="white"/>
</clipPath>
<clipPath id="clip1_1_72">
<rect width="60" height="60" fill="white" transform="translate(13 13)"/>
</clipPath>
</defs>
</svg>
// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
import QtQuick 2.2
import Sailfish.Silica 1.0
import Sailfish.Pickers 1.0
import ru.auroraos.DocumentConverter 1.0
Page {
id: loadFilePage
property string fileSourcePath
property string fileResultPath
property string fileName
objectName: "loadFilePage"
allowedOrientations: Orientation.All
PageHeader {
id: pageHader
objectName: "pageHeader"
title: qsTr("converting")
}
BusyIndicator {
id: indicator
size: BusyIndicatorSize.Large
anchors.centerIn: parent
running: visible
}
Timer {
id: timer
interval: 4500
running: true
onTriggered: {
if (converter.state === Converter.Saved) {
indicator.visible = false;
postIndicatorText.visible = true;
}
}
}
Text {
id: preIndicatorText
anchors {
top: indicator.bottom
topMargin: Theme.paddingLarge
}
width: parent.width
color: Theme.highlightColor
text: qsTr("Converting file ...")
font.pixelSize: Theme.fontSizeLarge
horizontalAlignment: Qt.AlignHCenter
visible: indicator.visible
}
Text {
id: postIndicatorText
anchors.centerIn: parent
width: parent.width
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeLarge
text: qsTr("File %1 saved").arg(fileName)
horizontalAlignment: Qt.AlignHCenter
visible: false
}
Text {
id: errorIndicatorText
anchors.centerIn: parent
width: parent.width
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeLarge
text: qsTr("Failed to convert %1").arg(fileName)
horizontalAlignment: Qt.AlignHCenter
visible: false
}
Converter {
id: converter
onStateChanged: {
switch (state) {
case Converter.Opening:
indicator.visible = true;
break;
case Converter.Saved:
if (!timer.running) {
indicator.visible = false;
postIndicatorText.visible = true;
}
break;
case Converter.Failed:
indicator.visible = false;
errorIndicatorText.visible = true;
break;
}
}
}
Component.onCompleted: {
converter.convert(fileSourcePath, fileResultPath);
}
}
// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
import QtQuick 2.0
import Nemo.FileManager 1.0
import Sailfish.Silica 1.0
import Sailfish.Pickers 1.0
Page {
id: loadPage
objectName: "loadPage"
SilicaListView {
id: lisView
property string currentPath
property string resultFileName
property string resultPath
property string defaultPath
property string directoryPath
anchors.fill: parent
model: fileModel
header: PageHeader {
title: fileModel.directoryName
}
delegate: ListItem {
width: parent.width
Image {
id: icon
anchors.verticalCenter: parent.verticalCenter
x: Theme.horizontalPageMargin
source: "image://theme/icon-m-file" + (model.isDir ? "-folder" : "-other") + (highlighted ? '?' + Theme.highlightColor : '')
}
Item {
id: description
anchors {
verticalCenter: parent.verticalCenter
verticalCenterOffset: -Theme.paddingMedium
right: parent.right
rightMargin: Theme.horizontalPageMargin
left: icon.right
leftMargin: Theme.paddingMedium
}
height: fileNameLabel.height
baselineOffset: fileNameLabel.baselineOffset
Label {
id: fileNameLabel
text: model.fileName
color: highlighted ? Theme.highlightColor : Theme.primaryColor
truncationMode: TruncationMode.Fade
width: parent.width - sizeLabel.width - Theme.paddingMedium
}
Label {
id: sizeLabel
text: Format.formatFileSize(model.size)
font.pixelSize: Theme.fontSizeExtraSmall
anchors.right: parent.right
anchors.baseline: parent.baseline
color: highlighted ? Theme.highlightColor : Theme.primaryColor
}
}
menu: ContextMenu {
hasContent: !model.isDir && (fileName.lastIndexOf(".pdf") === -1)
Repeater {
model: listExtension(fileName)
MenuItem {
text: qsTr("Conver to %1").arg(modelData)
onClicked: {
lisView.currentPath = absolutePath;
lisView.resultFileName = createFileName(fileName, modelData);
pageStack.push(folderPickerDialog);
}
}
}
}
Row {
spacing: Theme.paddingSmall
anchors {
top: description.bottom
right: description.right
}
Label {
opacity: 0.6
color: highlighted ? Theme.highlightColor : Theme.primaryColor
font.pixelSize: Theme.fontSizeExtraSmall
anchors.verticalCenter: parent.verticalCenter
text: Format.formatDate(model.modified, Format.Timepoint)
}
}
onClicked: {
if (model.isDir) {
fileModel.path = model.absolutePath;
}
}
}
VerticalScrollDecorator {
}
}
Component {
id: folderPickerDialog
FolderPickerPage {
showSystemFiles: false
dialogTitle: qsTr("Save as ...")
onSelectedPathChanged: {
lisView.resultPath = ("%1/%2").arg(selectedPath).arg(lisView.resultFileName);
var loadPage_ = pageStack.find(function (page) {
if (page.objectName === "loadPage")
return page;
});
pageStack.replaceAbove(loadPage_, Qt.resolvedUrl("ConvertPage.qml"), {
"fileSourcePath": lisView.currentPath,
"fileResultPath": lisView.resultPath,
"fileName": lisView.resultFileName
});
}
}
}
FileModel {
id: fileModel
active: true
includeDirectories: true
includeParentDirectory: false
directorySort: FileModel.SortDirectoriesBeforeFiles
nameFilters: ["*.doc", "*.docx", "*.pdf", "*.odt", "*.xls", "*.xlsx", "*.ods", "*.ppt", "*.pptx", "*.odp"]
sortBy: FileModel.SortByName
sortOrder: Qt.AscendingOrder
path: StandardPaths.documents
}
function createFileName(fileName, extension) {
var tmpIndex = fileName.lastIndexOf(".");
fileName = fileName.slice(0, tmpIndex);
return ("%1%2").arg(fileName).arg(extension);
}
function listExtension(fileName) {
var exIndex = fileName.lastIndexOf(".");
var extension = fileName.slice(exIndex);
var listDocumentsExtension = [".doc", ".docx", ".odt", ".pdf"];
var listTablesExtension = [".xls", ".xlsx", ".ods", ".pdf"];
var listPresentationExtension = [".ppt", ".pptx", ".odp", ".pdf"];
var listOfList = [listDocumentsExtension, listTablesExtension, listPresentationExtension];
for (var i = 0; i < listOfList.length; i++) {
var element = listOfList[i];
var tmpIndex = element.indexOf(extension);
if (tmpIndex !== -1 && extension !== ".pdf") {
element.splice(tmpIndex, 1);
return element;
}
}
}
}
......@@ -3,7 +3,7 @@ Type=Application
X-Nemo-Application-Type=silica-qt5
Icon=ru.auroraos.DocumentConverter
Exec=/usr/bin/ru.auroraos.DocumentConverter
Name=DocumentConverter
Name=Document Converter
Name[ru]=Конвертер Документов
[X-Application]
......
// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
#include "converter.h"
#include <QDir>
#include <QThreadPool>
#include <QtConcurrent/QtConcurrent>
#include <QDebug>
#define LIBREOFFICE_PATH "/usr/share/ru.auroraos.DocumentConverter/lib/libreoffice/program"
Converter::Converter(QObject *parent)
: QObject(parent), m_office(nullptr), m_document(nullptr), m_state(State::Initilize)
{
qRegisterMetaType<Converter::State>("Converter::State");
m_office = lok::lok_cpp_init(LIBREOFFICE_PATH);
if (!m_office) {
setState(Converter::State::Failed);
qWarning("Worker error: can't init the office instance");
}
}
void Converter::convert(const QString &fileSourcePath, const QString &fileResultPath)
{
// if (m_state != State::Opened)
// return;
auto worker = new ConverterWorker(m_office, fileSourcePath.toUtf8(), fileResultPath.toUtf8());
connect(worker, &ConverterWorker::satateChanged, this, &Converter::setState);
QThreadPool::globalInstance()->start(worker);
}
Converter::State Converter::state() const
{
return m_state;
}
void Converter::setState(State newState)
{
if (m_state == newState)
return;
m_state = newState;
emit stateChanged();
}
ConverterWorker::ConverterWorker(lok::Office *office, const QByteArray &srcUrl,
const QByteArray &dstUrl)
: m_office(office), m_srcUrl(srcUrl), m_dstUrl(dstUrl)
{
}
void ConverterWorker::run()
{
emit satateChanged(Converter::State::Opening);
const int flags = LOK_FEATURE_DOCUMENT_PASSWORD | LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
| LOK_FEATURE_RANGE_HEADERS | LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK
| LOK_FEATURE_NO_TILED_ANNOTATIONS;
m_office->setOptionalFeatures(flags);
QString options;
qDebug() << "Converting" << m_srcUrl << m_dstUrl;
auto document = m_office->documentLoad(m_srcUrl.data(), options.toStdString().c_str());
if (!document) {
emit satateChanged(Converter::State::Failed);
return;
}
emit satateChanged(Converter::State::Opened);
emit satateChanged(Converter::State::Saving);
bool status = document->saveAs(m_dstUrl.data());
if (status) {
emit satateChanged(Converter::State::Saved);
qDebug() << "Converted" << m_dstUrl;
} else {
emit satateChanged(Converter::State::Failed);
qDebug() << "Failed" << m_srcUrl << m_dstUrl;
}
}
// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
#ifndef CONVERTER_H
#define CONVERTER_H
#include <QString>
#include <QObject>
#include <QFile>
#include <QIODevice>
#include <QTextStream>
#include <QRunnable>
#define LOK_USE_UNSTABLE_API
#include <LibreOfficeKit.hxx>
#include <LibreOfficeKitEnums.h>
class Converter : public QObject
{
Q_OBJECT
public:
enum class State { Initilize, Opening, Opened, Saving, Saved, Failed };
Q_ENUM(State)
Q_PROPERTY(State state READ state NOTIFY stateChanged)
public:
explicit Converter(QObject *parent = nullptr);
State state() const;
void setState(State newState);
public slots:
void convert(const QString &fileSourcePath, const QString &fileResultPath);
signals:
void fileConverted();
void stateChanged();
private:
lok::Office *m_office;
lok::Document *m_document;
State m_state;
};
class ConverterWorker : public QObject, public QRunnable
{
Q_OBJECT
public:
ConverterWorker(lok::Office *office, const QByteArray &srcUrl, const QByteArray &dstUrl);
void run() override final;
signals:
void satateChanged(Converter::State);
private:
lok::Office *m_office;
QByteArray m_srcUrl;
QByteArray m_dstUrl;
};
#endif // CONVERTER_H
// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause
#include <auroraapp.h>
#include <QtQuick>
#include <QMetaType>
#include "converter.h"
int main(int argc, char *argv[])
{
QScopedPointer<QGuiApplication> application(Aurora::Application::application(argc, argv));
application->setOrganizationName(QStringLiteral("ru.auroraos"));
application->setApplicationName(QStringLiteral("DocumentConverter"));
qmlRegisterType<Converter>("ru.auroraos.DocumentConverter", 1, 0, "Converter");
QScopedPointer<QQuickView> view(Aurora::Application::createView());
view->setSource(Aurora::Application::pathTo(QStringLiteral("qml/DocumentConverter.qml")));
view->show();
return application->exec();
}
\ Нет новой строки в конце файла
}
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать